Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions documentation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* Fixed: Ignores hidden files/folders and the known Windows system folders when checking for empty-folder (thanks to Douglas Carmichael).
* Fixed: A library name typed with its file ending (e.g. "MyLibrary.xrni") produced a doubled-up file name ("MyLibrary_xrni.xrni") - the ending is now recognized for every destination format (thanks to Douglas Carmichael).
* Fixed: The "Trim start and end" processing option cut the audio to the zone's start/end but left the loop points at their old positions, so a trimmed sample with a non-zero start got a displaced loop - the loop end could even point past the end of the trimmed audio. The loop points now move with the cut (thanks to Douglas Carmichael).
* Fixed: Replaced the external FLAC encoder library with an own implementation: the library crashed on samples whose length modulo 4096 was 2, 3 or 4 (e.g. "The FLAC encoder failed for sample '...'" when writing Renoise files; SFZ with FLAC option, Bliss and Synclavier Regen were affected as well) (thanks to Douglas Carmichael).
* Fixed: Fixed some potential NullPointerExceptions.
* 1010music (thanks to Douglas Carmichael)
* Fixed: The amplitude decay and release times were written with a different time scale than the one used when reading them back (25 seconds instead of 38 seconds full-scale), so a converted blackbox/Bento preset played its decay and release noticeably shorter than the source. The write scale now matches the read scale.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

Expand Down Expand Up @@ -68,7 +66,6 @@
*/
public abstract class AbstractCreator<T extends ICoreTaskSettings> extends AbstractCoreTask<T> implements ICreator<T>
{
protected static final AudioFileFormat.Type FLAC_TARGET_FORMAT = new AudioFileFormat.Type ("FLAC", "flac");
/** The post-fix to use for the samples folder. */
protected static final String FOLDER_POSTFIX = " Samples";

Expand Down Expand Up @@ -436,18 +433,16 @@ protected String createSampleFilename (final ISampleZone zone, final int zoneInd


/**
* Writes all samples in the given audio file format from all groups into the given folder.
* Writes all samples in FLAC format from all groups into the given folder.
*
* @param sampleFolder The destination folder
* @param multisampleSource The multi-sample
* @return The written files
* @throws IOException Could not store the samples
* @throws UnsupportedAudioFileException The audio format is not supported
*/
protected List<File> writeFlacSamples (final File sampleFolder, final IMultisampleSource multisampleSource) throws IOException, UnsupportedAudioFileException
protected List<File> writeFlacSamples (final File sampleFolder, final IMultisampleSource multisampleSource) throws IOException
{
final List<File> writtenFiles = new ArrayList<> ();
final String extension = "." + FLAC_TARGET_FORMAT.getExtension ();

for (final IGroup group: multisampleSource.getGroups ())
{
Expand All @@ -459,14 +454,14 @@ protected List<File> writeFlacSamples (final File sampleFolder, final IMultisamp

final ISampleZone zone = sampleZones.get (zoneIndex);

final File file = new File (sampleFolder, this.createSampleFilename (zone, zoneIndex, extension));
final File file = new File (sampleFolder, this.createSampleFilename (zone, zoneIndex, ".flac"));
this.progress.notifyProgress ();
final Optional<ISampleData> sampleData = zone.getSampleData ();
if (sampleData.isEmpty ())
this.notifier.logError (IDS_NOTIFY_ERR_MISSING_SAMPLE_DATA, zone.getName (), file.getName ());
else
{
AudioFileUtils.compressToFLAC (sampleData.get (), FLAC_TARGET_FORMAT, file);
AudioFileUtils.compressToFLAC (sampleData.get (), file);
writtenFiles.add (file);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import de.mossgrabers.convertwithmoss.core.model.ISampleData;
import de.mossgrabers.convertwithmoss.core.model.implementation.DefaultAudioMetadata;
import de.mossgrabers.convertwithmoss.exception.ParseException;
import de.mossgrabers.convertwithmoss.file.flac.FlacEncoder;
import de.mossgrabers.convertwithmoss.file.wav.FormatChunk;
import de.mossgrabers.convertwithmoss.file.wav.WaveFile;
import de.mossgrabers.tools.ui.Functions;
Expand All @@ -43,7 +44,15 @@
*/
public final class AudioFileUtils
{
private static final String BROKEN_WAV = "IDS_NOTIFY_ERR_BROKEN_WAV";
private static final String BROKEN_WAV = "IDS_NOTIFY_ERR_BROKEN_WAV";

/** FLAC supports at maximum a resolution of 24 bit. */
private static final DestinationAudioFormat FLAC_COMPATIBLE_FORMAT = new DestinationAudioFormat (new int []
{
8,
16,
24
}, -1, false);


/**
Expand Down Expand Up @@ -415,31 +424,66 @@ public static void decompressToWav (final InputStream inputStream, final OutputS


/**
* Compresses the given sample data contained in the sampleData object into a specific file
* format (e.g. FLAC).
* Compresses the given sample data contained in the sampleData object into a FLAC file. Since
* FLAC supports at maximum a resolution of 24 bit, 32 bit samples are reduced (16 bit for
* 32-bit float).
*
* @param sampleData The sample data
* @param targetFormat The target format
* @param file The file to write to
* @throws IOException Could not read/write
* @throws UnsupportedAudioFileException The target audio format is not supported
*/
public static void compressToFLAC (final ISampleData sampleData, final AudioFileFormat.Type targetFormat, final File file) throws IOException, UnsupportedAudioFileException
public static void compressToFLAC (final ISampleData sampleData, final File file) throws IOException
{
final byte [] wavData = convertToWavData (sampleData, new DestinationAudioFormat ());
Files.write (file.toPath (), compressToFLAC (sampleData));
}

// Create a ByteArrayInputStream from the input data array
try (final ByteArrayInputStream bais = new ByteArrayInputStream (wavData); AudioInputStream ais = AudioSystem.getAudioInputStream (bais))
{
final AudioFormat sourceFormat = ais.getFormat ();
final AudioFormat targetAudioFormat = new AudioFormat (sourceFormat.getSampleRate (), sourceFormat.getSampleSizeInBits (), sourceFormat.getChannels (), true, sourceFormat.isBigEndian ());
try (final AudioInputStream convertedAIS = AudioSystem.getAudioInputStream (targetAudioFormat, ais))

/**
* Compresses the given sample data contained in the sampleData object into FLAC. Since FLAC
* supports at maximum a resolution of 24 bit, 32 bit samples are reduced (16 bit for 32-bit
* float).
*
* @param sampleData The sample data
* @return The FLAC data
* @throws IOException Could not read the sample data
*/
public static byte [] compressToFLAC (final ISampleData sampleData) throws IOException
{
final WaveFile waveFile = convertToWav (sampleData, FLAC_COMPATIBLE_FORMAT);
final FormatChunk formatChunk = waveFile.getFormatChunk ();
final int numberOfChannels = formatChunk.getNumberOfChannels ();
final int bitsPerSample = formatChunk.getSignificantBitsPerSample ();
final int bytesPerSample = bitsPerSample / 8;
final byte [] data = waveFile.getDataChunk ().getData ();

// De-interleave the samples of the channels; 8 bit WAV data is unsigned and therefore
// converted to the signed form required by FLAC
final int numberOfSamples = data.length / (numberOfChannels * bytesPerSample);
final int [] [] channels = new int [numberOfChannels] [numberOfSamples];
int position = 0;
for (int i = 0; i < numberOfSamples; i++)
for (int channel = 0; channel < numberOfChannels; channel++)
{
// IMPORTANT: we must write to a file not a stream since with a stream the FLAC
// header is not updated!
AudioSystem.write (convertedAIS, targetFormat, file);
final int value;
switch (bytesPerSample)
{
case 1:
value = (data[position] & 0xFF) - 128;
break;
case 2:
value = data[position] & 0xFF | data[position + 1] << 8;
break;
case 3:
value = data[position] & 0xFF | (data[position + 1] & 0xFF) << 8 | data[position + 2] << 16;
break;
default:
throw new IOException ("FLAC: Unsupported bit resolution: " + bitsPerSample);
}
channels[channel][i] = value;
position += bytesPerSample;
}
}

return FlacEncoder.encode (channels, formatChunk.getSampleRate (), bitsPerSample);
}


Expand Down
Loading