diff --git a/taglib/wavpack/wavpackproperties.cpp b/taglib/wavpack/wavpackproperties.cpp index 8d7ab9ea..d5808be5 100644 --- a/taglib/wavpack/wavpackproperties.cpp +++ b/taglib/wavpack/wavpackproperties.cpp @@ -27,6 +27,7 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ +#include #include #include @@ -138,13 +139,6 @@ unsigned int WavPack::Properties::sampleFrames() const // private members //////////////////////////////////////////////////////////////////////////////// -namespace -{ - const unsigned int sample_rates[] = { - 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000, 192000, 0 }; -} - #define BYTES_STORED 3 #define MONO_FLAG 4 #define HYBRID_FLAG 8 @@ -169,6 +163,100 @@ namespace #define ID_LARGE 0x80 #define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7) +namespace +{ + const unsigned int sampleRates[] = { + 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, + 32000, 44100, 48000, 64000, 88200, 96000, 192000, 0 }; + + /*! + * Given a WavPack \a block (complete, but not including the 32-byte header), + * parse the metadata blocks until an \a id block is found and return the + * contained data, or zero if no such block is found. + * Supported values for \a id are ID_SAMPLE_RATE and ID_DSD_BLOCK. + */ + int getMetaDataChunk(const ByteVector &block, unsigned char id) + { + if(id != ID_SAMPLE_RATE && id != ID_DSD_BLOCK) + return 0; + + const int blockSize = static_cast(block.size()); + int index = 0; + + while(index + 1 < blockSize) { + const unsigned char metaId = static_cast(block[index]); + int metaBc = static_cast(block[index + 1]) << 1; + index += 2; + + if(metaId & ID_LARGE) { + if(index + 2 > blockSize) + return 0; + + metaBc += (static_cast(static_cast(block[index])) << 9) + + (static_cast(static_cast(block[index + 1])) << 17); + index += 2; + } + + if(index + metaBc > blockSize) + return 0; + + // if we got a sample rate, return it + + if(id == ID_SAMPLE_RATE && (metaId & ID_UNIQUE) == ID_SAMPLE_RATE && metaBc == 4) { + int sampleRate = static_cast(static_cast(block[index])); + sampleRate |= static_cast(static_cast(block[index + 1])) << 8; + sampleRate |= static_cast(static_cast(block[index + 2])) << 16; + + // only use 4th byte if it's really there + + if(!(metaId & ID_ODD_SIZE)) + sampleRate |= static_cast(static_cast(block[index + 3]) & 0x7f) << 24; + + return sampleRate; + } + + // if we got DSD block, return the specified rate shift amount + + if(id == ID_DSD_BLOCK && (metaId & ID_UNIQUE) == ID_DSD_BLOCK && metaBc > 0) { + const unsigned char rateShift = static_cast(block[index]); + if(rateShift <= 31) + return rateShift; + } + + index += metaBc; + } + + return 0; + } + + /*! + * Given a WavPack block (complete, but not including the 32-byte header), + * parse the metadata blocks until an ID_SAMPLE_RATE block is found and + * return the non-standard sample rate contained there, or zero if no such + * block is found. + */ + int getNonStandardRate(const ByteVector &block) + { + return getMetaDataChunk(block, ID_SAMPLE_RATE); + } + + /*! + * Given a WavPack block (complete, but not including the 32-byte header), + * parse the metadata blocks until a DSD audio data block is found and return + * the sample-rate shift value contained there, or zero if no such block is + * found. The nominal sample rate of DSD audio files (found in the header) + * must be left-shifted by this amount to get the actual "byte" sample rate. + * Note that 8-bit bytes are the "atoms" of the DSD audio coding (for + * decoding, seeking, etc), so the shifted rate must be further multiplied by + * 8 to get the actual DSD bit sample rate. + */ + int getDsdRateShifter(const ByteVector &block) + { + return getMetaDataChunk(block, ID_DSD_BLOCK); + } + +} + void WavPack::Properties::read(File *file, long streamLength) { long offset = 0; @@ -191,14 +279,14 @@ void WavPack::Properties::read(File *file, long streamLength) const unsigned int sampleFrames = data.toUInt(12, false); const unsigned int blockSamples = data.toUInt(20, false); const unsigned int flags = data.toUInt(24, false); - unsigned int sampleRate = sample_rates[(flags & SRATE_MASK) >> SRATE_LSB]; + unsigned int sampleRate = sampleRates[(flags & SRATE_MASK) >> SRATE_LSB]; - if (!blockSamples) { // ignore blocks with no samples + if(!blockSamples) { // ignore blocks with no samples offset += blockSize + 8; continue; } - if (blockSize < 24 || blockSize > 1048576) { + if(blockSize < 24 || blockSize > 1048576) { debug("WavPack::Properties::read() -- Invalid block header found."); break; } @@ -207,19 +295,19 @@ void WavPack::Properties::read(File *file, long streamLength) // to actually determine the sample rate. if(!sampleRate || (flags & DSD_FLAG)) { - const unsigned int adjusted_block_size = blockSize - 24; - const ByteVector block = file->readBlock(adjusted_block_size); + const unsigned int adjustedBlockSize = blockSize - 24; + const ByteVector block = file->readBlock(adjustedBlockSize); - if(block.size() < adjusted_block_size) { + if(block.size() < adjustedBlockSize) { debug("WavPack::Properties::read() -- block is too short."); break; } - if (!sampleRate) - sampleRate = getNonStandardRate(reinterpret_cast(block.data()), adjusted_block_size); + if(!sampleRate) + sampleRate = static_cast(getNonStandardRate(block)); - if (sampleRate && (flags & DSD_FLAG)) - sampleRate <<= getDsdRateShifter(reinterpret_cast(block.data()), adjusted_block_size); + if(sampleRate && (flags & DSD_FLAG)) + sampleRate <<= getDsdRateShifter(block); } if(flags & INITIAL_BLOCK) { @@ -228,7 +316,7 @@ void WavPack::Properties::read(File *file, long streamLength) break; d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 - ((flags & SHIFT_MASK) >> SHIFT_LSB); - d->sampleRate = sampleRate; + d->sampleRate = static_cast(sampleRate); d->lossless = !(flags & HYBRID_FLAG); d->sampleFrames = sampleFrames; } @@ -284,99 +372,3 @@ unsigned int WavPack::Properties::seekFinalIndex(File *file, long streamLength) return 0; } - -// Given a WavPack block (complete, but not including the 32-byte header), parse the metadata -// blocks until an ID_SAMPLE_RATE block is found and return the non-standard sample rate -// contained there, or zero if no such block is found. - -int WavPack::Properties::getNonStandardRate(unsigned char const *buffer, int bcount) -{ - unsigned char meta_id, c1, c2; - int meta_bc; - - while (bcount >= 2) { - meta_id = *buffer++; - c1 = *buffer++; - - meta_bc = c1 << 1; - bcount -= 2; - - if (meta_id & ID_LARGE) { - if (bcount < 2) - return 0; - - c1 = *buffer++; - c2 = *buffer++; - meta_bc += (static_cast(c1) << 9) + (static_cast(c2) << 17); - bcount -= 2; - } - - if (bcount < meta_bc) - return 0; - - // if we got a sample rate, return it - - if ((meta_id & ID_UNIQUE) == ID_SAMPLE_RATE && meta_bc == 4) { - int sample_rate = static_cast(*buffer++); - sample_rate |= static_cast(*buffer++) << 8; - sample_rate |= static_cast(*buffer++) << 16; - - // only use 4th byte if it's really there - - if (!(meta_id & ID_ODD_SIZE)) - sample_rate |= static_cast(*buffer & 0x7f) << 24; - - return sample_rate; - } - - bcount -= meta_bc; - buffer += meta_bc; - } - - return 0; -} - -// Given a WavPack block (complete, but not including the 32-byte header), parse the metadata -// blocks until a DSD audio data block is found and return the sample-rate shift value -// contained there, or zero if no such block is found. The nominal sample rate of DSD audio -// files (found in the header) must be left-shifted by this amount to get the actual "byte" -// sample rate. Note that 8-bit bytes are the "atoms" of the DSD audio coding (for decoding, -// seeking, etc), so the shifted rate must be further multiplied by 8 to get the actual DSD -// bit sample rate. - -int WavPack::Properties::getDsdRateShifter(unsigned char const *buffer, int bcount) -{ - unsigned char meta_id, c1, c2; - int meta_bc; - - while (bcount >= 2) { - meta_id = *buffer++; - c1 = *buffer++; - - meta_bc = c1 << 1; - bcount -= 2; - - if (meta_id & ID_LARGE) { - if (bcount < 2) - return 0; - - c1 = *buffer++; - c2 = *buffer++; - meta_bc += (static_cast(c1) << 9) + (static_cast(c2) << 17); - bcount -= 2; - } - - if (bcount < meta_bc) - return 0; - - // if we got DSD block, return the specified rate shift amount - - if ((meta_id & ID_UNIQUE) == ID_DSD_BLOCK && meta_bc && *buffer <= 31) - return *buffer; - - bcount -= meta_bc; - buffer += meta_bc; - } - - return 0; -} diff --git a/taglib/wavpack/wavpackproperties.h b/taglib/wavpack/wavpackproperties.h index ddc51f7d..e6acdcc3 100644 --- a/taglib/wavpack/wavpackproperties.h +++ b/taglib/wavpack/wavpackproperties.h @@ -139,8 +139,6 @@ namespace TagLib { void read(File *file, long streamLength); unsigned int seekFinalIndex(File *file, long streamLength); - int getNonStandardRate(unsigned char const *buffer, int bcount); - int getDsdRateShifter(unsigned char const *buffer, int bcount); class PropertiesPrivate; PropertiesPrivate *d;