diff --git a/src/deluge/storage/audio/audio_file.cpp b/src/deluge/storage/audio/audio_file.cpp index 70e8cc47f8..0df0f55286 100644 --- a/src/deluge/storage/audio/audio_file.cpp +++ b/src/deluge/storage/audio/audio_file.cpp @@ -24,25 +24,14 @@ #include "storage/audio/audio_file_manager.h" #include "storage/audio/audio_file_reader.h" #include "storage/wave_table/wave_table.h" -#include "util/misc.h" +#include "storage/wave_table/wave_table_reader.h" #include - #include -#define MAX_NUM_MARKERS 8 - -Error AudioFile::loadFile(AudioFileReader* reader, bool isAiff, bool makeWaveTableWorkAtAllCosts) { - - // AIFF files will only be used for WaveTables if the user insists - if (type == AudioFileType::WAVETABLE && !makeWaveTableWorkAtAllCosts && isAiff) { - return Error::FILE_NOT_LOADABLE_AS_WAVETABLE; - } - - // http://muratnkonar.com/aiff/ - - // https://sites.google.com/site/musicgapi/technical-documents/wav-file-format?fbclid=IwAR1AWDhXq4m4LAlz991je_-NpRgRnD7eNg36ZfJ42X0xHkn38u5_skTvxHM#wavefilechunks +constexpr int32_t MAX_NUM_MARKERS = 8; - uint32_t bytePos = reader->getBytePos(); +Error AudioFile::loadWAVE(AudioFileReader& reader, bool makeWaveTableWorkAtAllCosts) { + uint32_t bytePos = reader.getBytePos(); Error error; bool foundDataChunk = false; // Also applies to AIFF file's SSND chunk @@ -54,398 +43,478 @@ Error AudioFile::loadFile(AudioFileReader* reader, bool isAiff, bool makeWaveTab uint32_t audioDataLengthBytes; uint32_t waveTableCycleSize = 2048; - // This stuff for AIFF files only - int16_t sustainLoopBeginMarkerId = -1; - int16_t sustainLoopEndMarkerId = -1; - uint16_t numMarkers; - int16_t markerIDs[MAX_NUM_MARKERS]; - uint32_t markerPositions[MAX_NUM_MARKERS]; - - while (bytePos < reader->fileSize) { + while (bytePos < reader.fileSize) { struct { uint32_t name; uint32_t length; } thisChunk; - error = reader->readBytes((char*)&thisChunk, 4 * 2); + error = reader.readBytes((char*)&thisChunk, 4 * 2); if (error != Error::NONE) { break; } - if (isAiff) { - thisChunk.length = swapEndianness32(thisChunk.length); - } - uint32_t bytesCurrentChunkNotRoundedUp = thisChunk.length; thisChunk.length = (thisChunk.length + 1) & ~(uint32_t)1; // If chunk size is odd, skip the extra byte of padding at the end - // too. Weird RIFF file requirement. + // too. Weird RIFF file requirement. - uint32_t bytePosOfThisChunkData = reader->getBytePos(); + uint32_t bytePosOfThisChunkData = reader.getBytePos(); // Move on for next RIFF chunk bytePos = bytePosOfThisChunkData + thisChunk.length; // ------ WAV ------ - if (!isAiff) { - - switch (thisChunk.name) { - - // Data chunk - "data" - case charsToIntegerConstant('d', 'a', 't', 'a'): { - foundDataChunk = true; - audioDataStartPosBytes = bytePosOfThisChunkData; - audioDataLengthBytes = bytesCurrentChunkNotRoundedUp; - if (type == AudioFileType::WAVETABLE) { -doSetupWaveTable: - if (byteDepth == 255) { - return Error::FILE_UNSUPPORTED; // If haven't found "fmt " tag yet, we don't know the bit depth - // or anything. Shouldn't happen. - } - if (numChannels != 1) { - return Error::FILE_NOT_LOADABLE_AS_WAVETABLE_BECAUSE_STEREO; // Stereo files not useable as - // WaveTable, ever. - } + switch (thisChunk.name) { + + // Data chunk - "data" + case charsToIntegerConstant('d', 'a', 't', 'a'): { + foundDataChunk = true; + audioDataStartPosBytes = bytePosOfThisChunkData; + audioDataLengthBytes = bytesCurrentChunkNotRoundedUp; + if (type == AudioFileType::WAVETABLE) { + // TODO: break this out (was originally a goto label called "do wavetable setup") + if (byteDepth == 255) { + return Error::FILE_UNSUPPORTED; // If haven't found "fmt " tag yet, we don't know the bit depth + // or anything. Shouldn't happen. + } - // If this isn't actually a wavetable-specifying file or at least a wavetable-looking length, and - // the user isn't insisting, then opt not to do it. - if (!fileExplicitlySpecifiesSelfAsWaveTable && !makeWaveTableWorkAtAllCosts) { - int32_t audioDataLengthSamples = audioDataLengthBytes / byteDepth; - if (audioDataLengthSamples & 2047) { - return Error::FILE_NOT_LOADABLE_AS_WAVETABLE; - } - } - error = ((WaveTable*)this) - ->setup(nullptr, waveTableCycleSize, audioDataStartPosBytes, audioDataLengthBytes, - byteDepth, rawDataFormat, (WaveTableReader*)reader); - if (true || error != Error::NONE) { - return error; // Just always return here, for now. + if (numChannels != 1) { + return Error::FILE_NOT_LOADABLE_AS_WAVETABLE_BECAUSE_STEREO; // Stereo files not useable as + // WaveTable, ever. + } + + // If this isn't actually a wavetable-specifying file or at least a wavetable-looking length, and + // the user isn't insisting, then opt not to do it. + if (!fileExplicitlySpecifiesSelfAsWaveTable && !makeWaveTableWorkAtAllCosts) { + int32_t audioDataLengthSamples = audioDataLengthBytes / byteDepth; + if (audioDataLengthSamples & 2047) { + return Error::FILE_NOT_LOADABLE_AS_WAVETABLE; } } + error = ((WaveTable*)this) + ->setup(nullptr, waveTableCycleSize, audioDataStartPosBytes, audioDataLengthBytes, byteDepth, + rawDataFormat, (WaveTableReader*)&reader); + if (true || error != Error::NONE) { + return error; // Just always return here, for now. + } + } + break; + } + + // Format chunk - "fmt " + case charsToIntegerConstant('f', 'm', 't', ' '): { + foundFmtChunk = true; + + // Read and process fmt chunk + uint32_t header[4]; + error = reader.readBytes((char*)&header, 4 * 4); + if (error != Error::NONE) { + return error; + } + + // Bit depth + uint16_t bits = header[3] >> 16; + switch (bits) { + case 8: + rawDataFormat = RawDataFormat::UNSIGNED_8; + // No break + case 16: + case 24: + case 32: + byteDepth = bits >> 3; break; + case 256 ... 65535: + __builtin_unreachable(); + default: + return Error::FILE_UNSUPPORTED; } - // Format chunk - "fmt " - case charsToIntegerConstant('f', 'm', 't', ' '): { - foundFmtChunk = true; + // Format + uint16_t format = header[0]; + if (format == WAV_FORMAT_PCM) {} + else if (format == WAV_FORMAT_FLOAT && byteDepth == 4) { + rawDataFormat = RawDataFormat::FLOAT; + } + else { + return Error::FILE_UNSUPPORTED; + } - // Read and process fmt chunk - uint32_t header[4]; - error = reader->readBytes((char*)&header, 4 * 4); - if (error != Error::NONE) { - return error; - } + // Num channels + numChannels = header[0] >> 16; + if (numChannels != 1 && numChannels != 2) { + return Error::FILE_UNSUPPORTED; + } - // Bit depth - uint16_t bits = header[3] >> 16; - switch (bits) { - case 8: - rawDataFormat = RawDataFormat::UNSIGNED_8; - // No break - case 16: - case 24: - case 32: - byteDepth = bits >> 3; - break; - case 256 ... 65535: - __builtin_unreachable(); - default: + if (type == AudioFileType::SAMPLE) { + ((Sample*)this)->byteDepth = byteDepth; + ((Sample*)this)->rawDataFormat = rawDataFormat; + + // Sample rate + ((Sample*)this)->sampleRate = header[1]; + if (((Sample*)this)->sampleRate < 5000 || ((Sample*)this)->sampleRate > 96000) { return Error::FILE_UNSUPPORTED; } + } - // Format - uint16_t format = header[0]; - if (format == WAV_FORMAT_PCM) {} - else if (format == WAV_FORMAT_FLOAT && byteDepth == 4) { - rawDataFormat = RawDataFormat::FLOAT; - } - else { - return Error::FILE_UNSUPPORTED; + break; + } + + // Sample chunk - "smpl" + case charsToIntegerConstant('s', 'm', 'p', 'l'): { + if (type == AudioFileType::SAMPLE) { + + uint32_t data[9]; + error = reader.readBytes((char*)data, 4 * 9); + if (error != Error::NONE) { + break; } - // Num channels - numChannels = header[0] >> 16; - if (numChannels != 1 && numChannels != 2) { - return Error::FILE_UNSUPPORTED; + uint32_t midiNote = data[3]; + uint32_t midiPitchFraction = data[4]; + uint32_t numLoops = data[7]; + + if ((midiNote || midiPitchFraction) && midiNote < 128) { + ((Sample*)this)->midiNoteFromFile = (float)midiPitchFraction / ((uint64_t)1 << 32) + midiNote; } - if (type == AudioFileType::SAMPLE) { - ((Sample*)this)->byteDepth = byteDepth; - ((Sample*)this)->rawDataFormat = rawDataFormat; + /* + D_PRINTLN("unity note: %d", midiNote); - // Sample rate - ((Sample*)this)->sampleRate = header[1]; - if (((Sample*)this)->sampleRate < 5000 || ((Sample*)this)->sampleRate > 96000) { - return Error::FILE_UNSUPPORTED; + D_PRINTLN("num loops: %d", numLoops); + */ + + if (numLoops == 1) { + + // Go through loops + for (int32_t l = 0; l < numLoops; l++) { + D_PRINTLN("loop %d", l); + + uint32_t loopData[6]; + error = reader.readBytes((char*)loopData, 4 * 6); + if (error != Error::NONE) { + goto finishedWhileLoop; + } + + D_PRINTLN("start: %d", loopData[2]); + ((Sample*)this)->fileLoopStartSamples = loopData[2]; + + D_PRINTLN("end: %d", loopData[3]); + ((Sample*)this)->fileLoopEndSamples = loopData[3]; + + D_PRINTLN("play count: %d", loopData[5]); } } - break; + D_PRINTLN(""); } + break; + } - // Sample chunk - "smpl" - case charsToIntegerConstant('s', 'm', 'p', 'l'): { - if (type == AudioFileType::SAMPLE) { + // Instrument chunk - "inst" + case charsToIntegerConstant('i', 'n', 's', 't'): { + if (type == AudioFileType::SAMPLE) { - uint32_t data[9]; - error = reader->readBytes((char*)data, 4 * 9); - if (error != Error::NONE) { - break; - } + uint8_t data[7]; + error = reader.readBytes((char*)data, 7); + if (error != Error::NONE) { + break; + } - uint32_t midiNote = data[3]; - uint32_t midiPitchFraction = data[4]; - uint32_t numLoops = data[7]; + uint8_t midiNote = data[0]; + int8_t fineTune = data[1]; + if (midiNote < 128) { + ((Sample*)this)->midiNoteFromFile = (float)midiNote - (float)fineTune * 0.01; + } - if ((midiNote || midiPitchFraction) && midiNote < 128) { - ((Sample*)this)->midiNoteFromFile = (float)midiPitchFraction / ((uint64_t)1 << 32) + midiNote; - } + D_PRINTLN("unshifted note: %d", midiNote); + } + break; + } - /* - D_PRINTLN("unity note: %d", midiNote); + // Serum wavetable chunk - "clm " + case charsToIntegerConstant('c', 'l', 'm', ' '): { + char data[7]; + error = reader.readBytes((char*)data, 7); + if (error != Error::NONE) { + break; + } - D_PRINTLN("num loops: %d", numLoops); - */ + if ((*(uint32_t*)data & 0x00FFFFFF) == charsToIntegerConstant('<', '!', '>', 0)) { + fileExplicitlySpecifiesSelfAsWaveTable = true; + int32_t number = memToUIntOrError(&data[3], &data[7]); - if (numLoops == 1) { + if (number >= 1) { + waveTableCycleSize = number; + D_PRINTLN("clm tag num samples per cycle: %d", waveTableCycleSize); + } + } - // Go through loops - for (int32_t l = 0; l < numLoops; l++) { - D_PRINTLN("loop %d", l); + break; + } + } - uint32_t loopData[6]; - error = reader->readBytes((char*)loopData, 4 * 6); - if (error != Error::NONE) { - goto finishedWhileLoop; - } + reader.jumpForwardToBytePos(bytePos); + } - D_PRINTLN("start: %d", loopData[2]); - ((Sample*)this)->fileLoopStartSamples = loopData[2]; +finishedWhileLoop: - D_PRINTLN("end: %d", loopData[3]); - ((Sample*)this)->fileLoopEndSamples = loopData[3]; + if (!foundDataChunk || !foundFmtChunk) { + return Error::FILE_CORRUPTED; + } - D_PRINTLN("play count: %d", loopData[5]); - } - } + if (type == AudioFileType::SAMPLE) { + ((Sample*)this)->audioDataStartPosBytes = audioDataStartPosBytes; + ((Sample*)this)->audioDataLengthBytes = audioDataLengthBytes; + ((Sample*)this)->waveTableCycleSize = waveTableCycleSize; + ((Sample*)this)->fileExplicitlySpecifiesSelfAsWaveTable = fileExplicitlySpecifiesSelfAsWaveTable; + } - D_PRINTLN(""); - } - break; - } + return Error::NONE; +} - // Instrument chunk - "inst" - case charsToIntegerConstant('i', 'n', 's', 't'): { - if (type == AudioFileType::SAMPLE) { +Error AudioFile::loadAIFF(AudioFileReader& reader, bool makeWaveTableWorkAtAllCosts) { + // AIFF files will only be used for WaveTables if the user insists + if (type == AudioFileType::WAVETABLE && !makeWaveTableWorkAtAllCosts) { + return Error::FILE_NOT_LOADABLE_AS_WAVETABLE; + } - uint8_t data[7]; - error = reader->readBytes((char*)data, 7); - if (error != Error::NONE) { - break; - } + // http://muratnkonar.com/aiff/ - uint8_t midiNote = data[0]; - int8_t fineTune = data[1]; - if (midiNote < 128) { - ((Sample*)this)->midiNoteFromFile = (float)midiNote - (float)fineTune * 0.01; - } + // https://sites.google.com/site/musicgapi/technical-documents/wav-file-format?fbclid=IwAR1AWDhXq4m4LAlz991je_-NpRgRnD7eNg36ZfJ42X0xHkn38u5_skTvxHM#wavefilechunks - D_PRINTLN("unshifted note: %d", midiNote); - } - break; - } + uint32_t bytePos = reader.getBytePos(); - // Serum wavetable chunk - "clm " - case charsToIntegerConstant('c', 'l', 'm', ' '): { - char data[7]; - error = reader->readBytes((char*)data, 7); - if (error != Error::NONE) { - break; - } + Error error; + bool foundDataChunk = false; // Also applies to AIFF file's SSND chunk + bool foundFmtChunk = false; // Also applies to AIFF file's COMM chunk + bool fileExplicitlySpecifiesSelfAsWaveTable = false; + uint8_t byteDepth = 255; // 255 means no "fmt " or "COMM" chunk seen yet. + RawDataFormat rawDataFormat = RawDataFormat::NATIVE; + uint32_t audioDataStartPosBytes; + uint32_t audioDataLengthBytes; + uint32_t waveTableCycleSize = 2048; - if ((*(uint32_t*)data & 0x00FFFFFF) == charsToIntegerConstant('<', '!', '>', 0)) { - fileExplicitlySpecifiesSelfAsWaveTable = true; - int32_t number = memToUIntOrError(&data[3], &data[7]); + // This stuff for AIFF files only + int16_t sustainLoopBeginMarkerId = -1; + int16_t sustainLoopEndMarkerId = -1; + uint16_t numMarkers; + int16_t markerIDs[MAX_NUM_MARKERS]; + uint32_t markerPositions[MAX_NUM_MARKERS]; - if (number >= 1) { - waveTableCycleSize = number; - D_PRINTLN("clm tag num samples per cycle: %d", waveTableCycleSize); - } - } + while (bytePos < reader.fileSize) { - break; - } - } + struct { + uint32_t name; + uint32_t length; + } thisChunk; + + error = reader.readBytes((char*)&thisChunk, 4 * 2); + if (error != Error::NONE) { + break; } - // ------ AIFF ------ - else { - switch (thisChunk.name) { + thisChunk.length = swapEndianness32(thisChunk.length); - // SSND - case charsToIntegerConstant('S', 'S', 'N', 'D'): { - foundDataChunk = true; + uint32_t bytesCurrentChunkNotRoundedUp = thisChunk.length; + thisChunk.length = + (thisChunk.length + 1) & ~(uint32_t)1; // If chunk size is odd, skip the extra byte of padding at the end + // too. Weird RIFF file requirement. - // Offset - uint32_t offset; - error = reader->readBytes((char*)&offset, 4); - if (error != Error::NONE) { - return error; - } - offset = swapEndianness32(offset); - audioDataLengthBytes = bytesCurrentChunkNotRoundedUp - offset - 8; + uint32_t bytePosOfThisChunkData = reader.getBytePos(); - // If we're here, we found the data! Take note of where it starts - audioDataStartPosBytes = reader->getBytePos() + 4 + offset; + // Move on for next RIFF chunk + bytePos = bytePosOfThisChunkData + thisChunk.length; - if (type == AudioFileType::WAVETABLE) { - goto doSetupWaveTable; - } - break; + switch (thisChunk.name) { + + // SSND + case charsToIntegerConstant('S', 'S', 'N', 'D'): { + foundDataChunk = true; + + // Offset + uint32_t offset; + error = reader.readBytes((char*)&offset, 4); + if (error != Error::NONE) { + return error; } + offset = swapEndianness32(offset); + audioDataLengthBytes = bytesCurrentChunkNotRoundedUp - offset - 8; - // COMM - case charsToIntegerConstant('C', 'O', 'M', 'M'): { - foundFmtChunk = true; + // If we're here, we found the data! Take note of where it starts + audioDataStartPosBytes = reader.getBytePos() + 4 + offset; - if (thisChunk.length != 18) { - return Error::FILE_UNSUPPORTED; // Why'd I do this? + if (type == AudioFileType::WAVETABLE) { + // TODO: break this out (was originally a goto label called "do wavetable setup") + if (byteDepth == 255) { + return Error::FILE_UNSUPPORTED; // If haven't found "fmt " tag yet, we don't know the bit depth + // or anything. Shouldn't happen. } - // Read and process COMM chunk - uint16_t header[9]; - error = reader->readBytes((char*)header, 18); - if (error != Error::NONE) { - return error; + if (numChannels != 1) { + return Error::FILE_NOT_LOADABLE_AS_WAVETABLE_BECAUSE_STEREO; // Stereo files not useable as + // WaveTable, ever. } - // Num channels - numChannels = swapEndianness2x16(header[0]); - if (numChannels != 1 && numChannels != 2) { - return Error::FILE_UNSUPPORTED; + // If this isn't actually a wavetable-specifying file or at least a wavetable-looking length, and + // the user isn't insisting, then opt not to do it. + if (!fileExplicitlySpecifiesSelfAsWaveTable && !makeWaveTableWorkAtAllCosts) { + int32_t audioDataLengthSamples = audioDataLengthBytes / byteDepth; + if (audioDataLengthSamples & 2047) { + return Error::FILE_NOT_LOADABLE_AS_WAVETABLE; + } + } + error = ((WaveTable*)this) + ->setup(NULL, waveTableCycleSize, audioDataStartPosBytes, audioDataLengthBytes, byteDepth, + rawDataFormat, (WaveTableReader*)&reader); + if (true || error != Error::NONE) { + return error; // Just always return here, for now. } + } + break; + } - // Bit depth - uint16_t bits = swapEndianness2x16(header[3]); + // COMM + case charsToIntegerConstant('C', 'O', 'M', 'M'): { + foundFmtChunk = true; - if (bits == 8 || bits == 16 || bits == 24 || bits == 32) {} - else { - return Error::FILE_UNSUPPORTED; - } - byteDepth = bits >> 3; + if (thisChunk.length != 18) { + return Error::FILE_UNSUPPORTED; // Why'd I do this? + } - if (byteDepth > 1) { - rawDataFormat = static_cast(util::to_underlying(RawDataFormat::ENDIANNESS_WRONG_16) - + byteDepth - 2); - } + // Read and process COMM chunk + uint16_t header[9]; + error = reader.readBytes((char*)header, 18); + if (error != Error::NONE) { + return error; + } - if (type == AudioFileType::SAMPLE) { - ((Sample*)this)->byteDepth = byteDepth; + // Num channels + numChannels = swapEndianness2x16(header[0]); + if (numChannels != 1 && numChannels != 2) { + return Error::FILE_UNSUPPORTED; + } - // Sample rate - uint32_t sampleRate = ConvertFromIeeeExtended((unsigned char*)&header[4]); - if (sampleRate < 5000 || sampleRate > 96000) { - return Error::FILE_UNSUPPORTED; - } + // Bit depth + uint16_t bits = swapEndianness2x16(header[3]); - ((Sample*)this)->sampleRate = sampleRate; - } - break; + if (bits == 8 || bits == 16 || bits == 24 || bits == 32) {} + else { + return Error::FILE_UNSUPPORTED; } + byteDepth = bits >> 3; - // MARK - case charsToIntegerConstant('M', 'A', 'R', 'K'): { - error = reader->readBytes((char*)&numMarkers, 2); - if (error != Error::NONE) { - break; - } - numMarkers = swapEndianness2x16(numMarkers); + if (byteDepth > 1) { + rawDataFormat = static_cast(util::to_underlying(RawDataFormat::ENDIANNESS_WRONG_16) + + byteDepth - 2); + } - D_PRINTLN("numMarkers: %d", numMarkers); + if (type == AudioFileType::SAMPLE) { + ((Sample*)this)->byteDepth = byteDepth; - if (numMarkers > MAX_NUM_MARKERS) { - numMarkers = MAX_NUM_MARKERS; + // Sample rate + uint32_t sampleRate = ConvertFromIeeeExtended((unsigned char*)&header[4]); + if (sampleRate < 5000 || sampleRate > 96000) { + return Error::FILE_UNSUPPORTED; } - for (int32_t m = 0; m < numMarkers; m++) { - uint16_t markerId; - error = reader->readBytes((char*)&markerId, 2); - if (error != Error::NONE) { - goto finishedWhileLoop; - } - markerIDs[m] = swapEndianness2x16(markerId); + ((Sample*)this)->sampleRate = sampleRate; + } + break; + } - D_PRINTLN(""); - D_PRINTLN("markerId: %d", markerIDs[m]); + // MARK + case charsToIntegerConstant('M', 'A', 'R', 'K'): { + error = reader.readBytes((char*)&numMarkers, 2); + if (error != Error::NONE) { + break; + } + numMarkers = swapEndianness2x16(numMarkers); - uint32_t markerPos; - error = reader->readBytes((char*)&markerPos, 4); - if (error != Error::NONE) { - goto finishedWhileLoop; - } - markerPositions[m] = swapEndianness32(markerPos); + D_PRINTLN("numMarkers: %d", numMarkers); - D_PRINTLN("markerPos: %d", markerPositions[m]); + if (numMarkers > MAX_NUM_MARKERS) { + numMarkers = MAX_NUM_MARKERS; + } - uint8_t stringLength; - error = reader->readBytes((char*)&stringLength, 1); - if (error != Error::NONE) { - goto finishedWhileLoop; - } + for (int32_t m = 0; m < numMarkers; m++) { + uint16_t markerId; + error = reader.readBytes((char*)&markerId, 2); + if (error != Error::NONE) { + goto finishedWhileLoop; + } + markerIDs[m] = swapEndianness2x16(markerId); + + D_PRINTLN(""); + D_PRINTLN("markerId: %d", markerIDs[m]); + + uint32_t markerPos; + error = reader.readBytes((char*)&markerPos, 4); + if (error != Error::NONE) { + goto finishedWhileLoop; + } + markerPositions[m] = swapEndianness32(markerPos); - uint32_t stringLengthRoundedUpToBeEven = ((uint32_t)stringLength + 1) & ~(uint32_t)1; - reader->byteIndexWithinCluster += - stringLengthRoundedUpToBeEven; // Cluster boundaries will be checked at next read + D_PRINTLN("markerPos: %d", markerPositions[m]); + + uint8_t stringLength; + error = reader.readBytes((char*)&stringLength, 1); + if (error != Error::NONE) { + goto finishedWhileLoop; } - break; + + uint32_t stringLengthRoundedUpToBeEven = ((uint32_t)stringLength + 1) & ~(uint32_t)1; + reader.byteIndexWithinCluster += + stringLengthRoundedUpToBeEven; // Cluster boundaries will be checked at next read } + break; + } - // INST - case charsToIntegerConstant('I', 'N', 'S', 'T'): { - if (type == AudioFileType::SAMPLE) { - uint8_t data[8]; - error = reader->readBytes((char*)data, 8); - if (error != Error::NONE) { - break; - } + // INST + case charsToIntegerConstant('I', 'N', 'S', 'T'): { + if (type == AudioFileType::SAMPLE) { + uint8_t data[8]; + error = reader.readBytes((char*)data, 8); + if (error != Error::NONE) { + break; + } - uint8_t midiNote = data[0]; - int8_t fineTune = data[1]; - if ((midiNote || fineTune) && midiNote < 128) { - ((Sample*)this)->midiNoteFromFile = (float)midiNote - (float)fineTune * 0.01; - D_PRINTLN("unshifted note: %s", ((Sample*)this)->midiNoteFromFile); - } + uint8_t midiNote = data[0]; + int8_t fineTune = data[1]; + if ((midiNote || fineTune) && midiNote < 128) { + ((Sample*)this)->midiNoteFromFile = (float)midiNote - (float)fineTune * 0.01; + D_PRINTLN("unshifted note: %s", ((Sample*)this)->midiNoteFromFile); + } - // for (int32_t l = 0; l < 2; l++) { + // for (int32_t l = 0; l < 2; l++) { - // if (l == 0) D_PRINTLN("sustain loop:"); - // else D_PRINTLN("release loop:"); + // if (l == 0) D_PRINTLN("sustain loop:"); + // else D_PRINTLN("release loop:"); - // Just read the sustain loop, which is first + // Just read the sustain loop, which is first - uint16_t loopData[3]; - error = reader->readBytes((char*)loopData, 3 * 2); - if (error != Error::NONE) { - break; - } + uint16_t loopData[3]; + error = reader.readBytes((char*)loopData, 3 * 2); + if (error != Error::NONE) { + break; + } - D_PRINTLN("play mode: %d", swapEndianness2x16(loopData[0])); + D_PRINTLN("play mode: %d", swapEndianness2x16(loopData[0])); - sustainLoopBeginMarkerId = swapEndianness2x16(loopData[1]); - D_PRINTLN("begin marker id: %d", sustainLoopBeginMarkerId); + sustainLoopBeginMarkerId = swapEndianness2x16(loopData[1]); + D_PRINTLN("begin marker id: %d", sustainLoopBeginMarkerId); - sustainLoopEndMarkerId = swapEndianness2x16(loopData[2]); - D_PRINTLN("end marker id: %d", sustainLoopEndMarkerId); - //} - } - break; - } + sustainLoopEndMarkerId = swapEndianness2x16(loopData[2]); + D_PRINTLN("end marker id: %d", sustainLoopEndMarkerId); + //} } + break; + } } - reader->jumpForwardToBytePos(bytePos); + reader.jumpForwardToBytePos(bytePos); } finishedWhileLoop: @@ -456,20 +525,18 @@ Error AudioFile::loadFile(AudioFileReader* reader, bool isAiff, bool makeWaveTab if (type == AudioFileType::SAMPLE) { - if (isAiff) { - ((Sample*)this)->rawDataFormat = rawDataFormat; + ((Sample*)this)->rawDataFormat = rawDataFormat; - // Sort out the sustain loop - if (sustainLoopEndMarkerId != -1) { - for (int32_t m = 0; m < numMarkers; m++) { + // Sort out the sustain loop + if (sustainLoopEndMarkerId != -1) { + for (int32_t m = 0; m < numMarkers; m++) { - if (markerIDs[m] == sustainLoopBeginMarkerId) { - ((Sample*)this)->fileLoopStartSamples = markerPositions[m]; - } + if (markerIDs[m] == sustainLoopBeginMarkerId) { + ((Sample*)this)->fileLoopStartSamples = markerPositions[m]; + } - if (markerIDs[m] == sustainLoopEndMarkerId) { - ((Sample*)this)->fileLoopEndSamples = markerPositions[m]; - } + if (markerIDs[m] == sustainLoopEndMarkerId) { + ((Sample*)this)->fileLoopEndSamples = markerPositions[m]; } } } diff --git a/src/deluge/storage/audio/audio_file.h b/src/deluge/storage/audio/audio_file.h index f625298488..3b58b2e1f3 100644 --- a/src/deluge/storage/audio/audio_file.h +++ b/src/deluge/storage/audio/audio_file.h @@ -28,7 +28,8 @@ class AudioFile : public Stealable { AudioFile(AudioFileType newType) : type(newType) {} ~AudioFile() override = default; - Error loadFile(AudioFileReader* reader, bool isAiff, bool makeWaveTableWorkAtAllCosts); + Error loadWAVE(AudioFileReader& reader, bool makeWaveTableWorkAtAllCosts); + Error loadAIFF(AudioFileReader& reader, bool makeWaveTableWorkAtAllCosts); virtual void finalizeAfterLoad(uint32_t fileSize) {} void addReason(); @@ -41,7 +42,7 @@ class AudioFile : public Stealable { String filePath; const AudioFileType type; - uint8_t numChannels; + uint8_t numChannels = 0; String loadedFromAlternatePath; // We now need to store this, since "alternate" files can now just have the same // filename (in special folder) as the original. So we need to remember which format // the name took. diff --git a/src/deluge/storage/audio/audio_file_manager.cpp b/src/deluge/storage/audio/audio_file_manager.cpp index 0b1a5f6b06..50acd9b96e 100644 --- a/src/deluge/storage/audio/audio_file_manager.cpp +++ b/src/deluge/storage/audio/audio_file_manager.cpp @@ -809,11 +809,11 @@ AudioFileManager::getAudioFileFromFilename(String& filePath, bool mayReadCard, F if (topHeader[0] == 0x46464952 // "RIFF" && topHeader[2] == 0x45564157) { // "WAVE" - error = audioFile->loadFile(reader, false, makeWaveTableWorkAtAllCosts); + error = audioFile->loadWAVE(*reader, makeWaveTableWorkAtAllCosts); } else if (topHeader[0] == 0x4D524F46 // "FORM" && topHeader[2] == 0x46464941) { // "AIFF" - error = audioFile->loadFile(reader, true, makeWaveTableWorkAtAllCosts); + error = audioFile->loadAIFF(*reader, makeWaveTableWorkAtAllCosts); } else { error = Error::FILE_UNSUPPORTED;