diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index c7cadb67..6c136cde 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -150,12 +150,22 @@ void RIFF::AIFF::File::read(bool readProperties, Properties::ReadStyle propertie debug("RIFF::AIFF::File::read() - Duplicate ID3v2 tag found."); } } - else if(name == "COMM" && readProperties) { - if(formatData.isEmpty()) { - formatData = chunkData(i); + else if(readProperties) { + if(name == "COMM") { + if(formatData.isEmpty()) { + formatData = chunkData(i); + } + else { + debug("RIFF::AIFF::File::read() - Duplicate 'COMM' chunk found."); + } } - else { - debug("RIFF::AIFF::File::read() - Duplicate 'COMM' chunk found."); + else if(name == "SSND") { + if(streamLength == 0) { + streamLength = chunkDataSize(i) + chunkPadding(i); + } + else { + debug("RIFF::AIFF::File::read() - Duplicate 'SSND' chunk found."); + } } } } diff --git a/taglib/riff/aiff/aiffproperties.cpp b/taglib/riff/aiff/aiffproperties.cpp index 63fed45f..8cb5de62 100644 --- a/taglib/riff/aiff/aiffproperties.cpp +++ b/taglib/riff/aiff/aiffproperties.cpp @@ -37,14 +37,14 @@ public: bitrate(0), sampleRate(0), channels(0), - sampleWidth(0), + bitsPerSample(0), sampleFrames(0) {} int length; int bitrate; int sampleRate; int channels; - int sampleWidth; + int bitsPerSample; ByteVector compressionType; String compressionName; @@ -56,9 +56,10 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -RIFF::AIFF::Properties::Properties(const ByteVector &data, ReadStyle style) : AudioProperties(style) +RIFF::AIFF::Properties::Properties(const ByteVector &data, ReadStyle style) : + AudioProperties(style), + d(new PropertiesPrivate()) { - d = new PropertiesPrivate; read(data); } @@ -68,6 +69,16 @@ RIFF::AIFF::Properties::~Properties() } int RIFF::AIFF::Properties::length() const +{ + return lengthInSeconds(); +} + +int RIFF::AIFF::Properties::lengthInSeconds() const +{ + return d->length / 1000; +} + +int RIFF::AIFF::Properties::lengthInMilliseconds() const { return d->length; } @@ -87,9 +98,14 @@ int RIFF::AIFF::Properties::channels() const return d->channels; } +int RIFF::AIFF::Properties::bitsPerSample() const +{ + return d->bitsPerSample; +} + int RIFF::AIFF::Properties::sampleWidth() const { - return d->sampleWidth; + return bitsPerSample(); } TagLib::uint RIFF::AIFF::Properties::sampleFrames() const @@ -122,16 +138,19 @@ void RIFF::AIFF::Properties::read(const ByteVector &data) return; } - d->channels = data.toShort(0U); - d->sampleFrames = data.toUInt(2U); - d->sampleWidth = data.toShort(6U); + d->channels = data.toShort(0U); + d->sampleFrames = data.toUInt(2U); + d->bitsPerSample = data.toShort(6U); + const long double sampleRate = data.toFloat80BE(8); - d->sampleRate = (int)sampleRate; - d->bitrate = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0); - d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; + if(sampleRate >= 1.0) { + d->sampleRate = static_cast(sampleRate + 0.5); + d->bitrate = static_cast(sampleRate * d->bitsPerSample * d->channels / 1000.0 + 0.5); + d->length = static_cast(d->sampleFrames * 1000.0 / sampleRate + 0.5); + } if(data.size() >= 23) { d->compressionType = data.mid(18, 4); - d->compressionName = String(data.mid(23, static_cast(data[22]))); + d->compressionName = String(data.mid(23, static_cast(data[22])), String::Latin1); } } diff --git a/taglib/riff/aiff/aiffproperties.h b/taglib/riff/aiff/aiffproperties.h index d0778704..651592a7 100644 --- a/taglib/riff/aiff/aiffproperties.h +++ b/taglib/riff/aiff/aiffproperties.h @@ -57,14 +57,65 @@ 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 the number of bits per audio sample. + */ + int bitsPerSample() const; + + /*! + * Returns the number of bits per audio sample. + * + * \note This method is just an alias of bitsPerSample(). + * + * \deprecated + */ int sampleWidth() const; + + /*! + * Returns the number of sample frames + */ uint sampleFrames() const; /*! diff --git a/tests/test_aiff.cpp b/tests/test_aiff.cpp index 968dbebb..360b7549 100644 --- a/tests/test_aiff.cpp +++ b/tests/test_aiff.cpp @@ -12,9 +12,9 @@ using namespace TagLib; class TestAIFF : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestAIFF); - CPPUNIT_TEST(testReading); - CPPUNIT_TEST(testSaveID3v2); + CPPUNIT_TEST(testAiffProperties); CPPUNIT_TEST(testAiffCProperties); + CPPUNIT_TEST(testSaveID3v2); CPPUNIT_TEST(testDuplicateID3v2); CPPUNIT_TEST(testFuzzedFile1); CPPUNIT_TEST(testFuzzedFile2); @@ -22,10 +22,38 @@ class TestAIFF : public CppUnit::TestFixture public: - void testReading() + void testAiffProperties() { RIFF::AIFF::File f(TEST_FILE_PATH_C("empty.aiff")); - CPPUNIT_ASSERT_EQUAL(705, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(67, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(706, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->sampleWidth()); + CPPUNIT_ASSERT_EQUAL(2941U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isAiffC()); + } + + void testAiffCProperties() + { + RIFF::AIFF::File f(TEST_FILE_PATH_C("alaw.aifc")); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); + CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(37, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(706, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->sampleWidth()); + CPPUNIT_ASSERT_EQUAL(1622U, f.audioProperties()->sampleFrames()); + CPPUNIT_ASSERT_EQUAL(true, f.audioProperties()->isAiffC()); + CPPUNIT_ASSERT_EQUAL(ByteVector("ALAW"), f.audioProperties()->compressionType()); + CPPUNIT_ASSERT_EQUAL(String("SGI CCITT G.711 A-law"), f.audioProperties()->compressionName()); } void testSaveID3v2() @@ -47,14 +75,6 @@ public: } } - void testAiffCProperties() - { - RIFF::AIFF::File f(TEST_FILE_PATH_C("alaw.aifc")); - CPPUNIT_ASSERT(f.audioProperties()->isAiffC()); - CPPUNIT_ASSERT_EQUAL(ByteVector("ALAW"), f.audioProperties()->compressionType()); - CPPUNIT_ASSERT_EQUAL(String("SGI CCITT G.711 A-law"), f.audioProperties()->compressionName()); - } - void testDuplicateID3v2() { RIFF::AIFF::File f(TEST_FILE_PATH_C("duplicate_id3v2.aiff"));