diff --git a/taglib/trueaudio/trueaudiofile.cpp b/taglib/trueaudio/trueaudiofile.cpp index f98d6add..8f40564c 100644 --- a/taglib/trueaudio/trueaudiofile.cpp +++ b/taglib/trueaudio/trueaudiofile.cpp @@ -84,38 +84,38 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -TrueAudio::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(file) +TrueAudio::File::File(FileName file, bool readProperties, Properties::ReadStyle) : + TagLib::File(file), + d(new FilePrivate()) { - d = new FilePrivate; if(isOpen()) - read(readProperties, propertiesStyle); + read(readProperties); } TrueAudio::File::File(FileName file, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(file) + bool readProperties, Properties::ReadStyle) : + TagLib::File(file), + d(new FilePrivate(frameFactory)) { - d = new FilePrivate(frameFactory); if(isOpen()) - read(readProperties, propertiesStyle); + read(readProperties); } -TrueAudio::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(stream) +TrueAudio::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : + TagLib::File(stream), + d(new FilePrivate()) { - d = new FilePrivate; if(isOpen()) - read(readProperties, propertiesStyle); + read(readProperties); } TrueAudio::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(stream) + bool readProperties, Properties::ReadStyle) : + TagLib::File(stream), + d(new FilePrivate(frameFactory)) { - d = new FilePrivate(frameFactory); if(isOpen()) - read(readProperties, propertiesStyle); + read(readProperties); } TrueAudio::File::~File() @@ -246,12 +246,11 @@ bool TrueAudio::File::hasID3v2Tag() const return d->hasID3v2; } - //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// -void TrueAudio::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) +void TrueAudio::File::read(bool readProperties) { // Look for an ID3v2 tag @@ -284,16 +283,23 @@ void TrueAudio::File::read(bool readProperties, Properties::ReadStyle /* propert // Look for TrueAudio metadata if(readProperties) { - if(d->ID3v2Location >= 0) { + + long streamLength; + + if(d->hasID3v1) + streamLength = d->ID3v1Location; + else + streamLength = length(); + + if(d->hasID3v2) { seek(d->ID3v2Location + d->ID3v2OriginalSize); - d->properties = new Properties(readBlock(TrueAudio::HeaderSize), - length() - d->ID3v2OriginalSize); + streamLength -= (d->ID3v2Location + d->ID3v2OriginalSize); } else { seek(0); - d->properties = new Properties(readBlock(TrueAudio::HeaderSize), - length()); } + + d->properties = new Properties(readBlock(TrueAudio::HeaderSize), streamLength); } } diff --git a/taglib/trueaudio/trueaudiofile.h b/taglib/trueaudio/trueaudiofile.h index 36c85845..3fc515f6 100644 --- a/taglib/trueaudio/trueaudiofile.h +++ b/taglib/trueaudio/trueaudiofile.h @@ -239,7 +239,7 @@ namespace TagLib { File(const File &); File &operator=(const File &); - void read(bool readProperties, Properties::ReadStyle propertiesStyle); + void read(bool readProperties); long findID3v1(); long findID3v2(); diff --git a/taglib/trueaudio/trueaudioproperties.cpp b/taglib/trueaudio/trueaudioproperties.cpp index dedd74e9..17e3a2ab 100644 --- a/taglib/trueaudio/trueaudioproperties.cpp +++ b/taglib/trueaudio/trueaudioproperties.cpp @@ -39,10 +39,7 @@ using namespace TagLib; class TrueAudio::Properties::PropertiesPrivate { public: - PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) : - data(d), - streamLength(length), - style(s), + PropertiesPrivate() : version(0), length(0), bitrate(0), @@ -51,9 +48,6 @@ public: bitsPerSample(0), sampleFrames(0) {} - ByteVector data; - long streamLength; - ReadStyle style; int version; int length; int bitrate; @@ -67,10 +61,11 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -TrueAudio::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) +TrueAudio::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : + AudioProperties(style), + d(new PropertiesPrivate()) { - d = new PropertiesPrivate(data, streamLength, style); - read(); + read(data, streamLength); } TrueAudio::Properties::~Properties() @@ -79,6 +74,16 @@ TrueAudio::Properties::~Properties() } int TrueAudio::Properties::length() const +{ + return lengthInSeconds(); +} + +int TrueAudio::Properties::lengthInSeconds() const +{ + return d->length / 1000; +} + +int TrueAudio::Properties::lengthInMilliseconds() const { return d->length; } @@ -117,34 +122,50 @@ int TrueAudio::Properties::ttaVersion() const // private members //////////////////////////////////////////////////////////////////////////////// -void TrueAudio::Properties::read() +void TrueAudio::Properties::read(const ByteVector &data, long streamLength) { - if(!d->data.startsWith("TTA")) + if(data.size() < 4) { + debug("TrueAudio::Properties::read() -- data is too short."); return; + } - int pos = 3; + if(!data.startsWith("TTA")) { + debug("TrueAudio::Properties::read() -- invalid header signature."); + return; + } - d->version = d->data[pos] - '0'; + uint pos = 3; + + d->version = data[pos] - '0'; pos += 1; // According to http://en.true-audio.com/TTA_Lossless_Audio_Codec_-_Format_Description // TTA2 headers are in development, and have a different format if(1 == d->version) { + if(data.size() < 18) { + debug("TrueAudio::Properties::read() -- data is too short."); + return; + } + // Skip the audio format pos += 2; - d->channels = d->data.toShort(pos, false); + d->channels = data.toShort(pos, false); pos += 2; - d->bitsPerSample = d->data.toShort(pos, false); + d->bitsPerSample = data.toShort(pos, false); pos += 2; - d->sampleRate = d->data.toUInt(pos, false); + d->sampleRate = data.toUInt(pos, false); pos += 4; - d->sampleFrames = d->data.toUInt(pos, false); - d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; + d->sampleFrames = data.toUInt(pos, false); + pos += 4; - d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; + if(d->sampleFrames > 0 && d->sampleRate > 0) { + const double length = d->sampleFrames * 1000.0 / d->sampleRate; + d->length = static_cast(length + 0.5); + d->bitrate = static_cast(streamLength * 8.0 / length + 0.5); + } } } diff --git a/taglib/trueaudio/trueaudioproperties.h b/taglib/trueaudio/trueaudioproperties.h index 126b6788..4d8cd451 100644 --- a/taglib/trueaudio/trueaudioproperties.h +++ b/taglib/trueaudio/trueaudioproperties.h @@ -61,15 +61,50 @@ namespace TagLib { */ virtual ~Properties(); - // Reimplementations. - + /*! + * Returns the length of the file in seconds. The length is rounded down to + * the nearest whole second. + * + * \note This method is just an alias of lengthInSeconds(). + * + * \deprecated + */ virtual int length() const; + + /*! + * Returns the length of the file in seconds. The length is rounded down to + * the nearest whole second. + * + * \see lengthInMilliseconds() + */ + // BIC: make virtual + int lengthInSeconds() const; + + /*! + * Returns the length of the file in milliseconds. + * + * \see lengthInSeconds() + */ + // BIC: make virtual + int lengthInMilliseconds() const; + + /*! + * Returns the average bit rate of the file in kb/s. + */ virtual int bitrate() const; + + /*! + * Returns the sample rate in Hz. + */ virtual int sampleRate() const; + + /*! + * Returns the number of audio channels. + */ virtual int channels() const; /*! - * Returns number of bits per sample. + * Returns the number of bits per audio sample. */ int bitsPerSample() const; @@ -87,7 +122,7 @@ namespace TagLib { Properties(const Properties &); Properties &operator=(const Properties &); - void read(); + void read(const ByteVector &data, long streamLength); class PropertiesPrivate; PropertiesPrivate *d; diff --git a/tests/data/tagged.tta b/tests/data/tagged.tta new file mode 100644 index 00000000..1677a7ed Binary files /dev/null and b/tests/data/tagged.tta differ diff --git a/tests/test_trueaudio.cpp b/tests/test_trueaudio.cpp index 5ff114cf..33cb1904 100644 --- a/tests/test_trueaudio.cpp +++ b/tests/test_trueaudio.cpp @@ -11,6 +11,7 @@ class TestTrueAudio : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestTrueAudio); CPPUNIT_TEST(testReadPropertiesWithoutID3v2); + CPPUNIT_TEST(testReadPropertiesWithTags); CPPUNIT_TEST_SUITE_END(); public: @@ -20,6 +21,29 @@ public: TrueAudio::File f(TEST_FILE_PATH_C("empty.tta")); CPPUNIT_ASSERT(f.audioProperties()); CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(173, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(162496U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->ttaVersion()); + } + + void testReadPropertiesWithTags() + { + TrueAudio::File f(TEST_FILE_PATH_C("tagged.tta")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3685, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(173, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(162496U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->ttaVersion()); } };