From 03fd0a3ead7e95dbe3db63aa23f76bcef0595e58 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 25 May 2015 10:29:14 +0900 Subject: [PATCH] AIFF: Calculate the actual average bitrate even if a file is compressed. Move property parsing code to Properties. --- taglib/riff/aiff/aifffile.cpp | 29 +++-------------- taglib/riff/aiff/aifffile.h | 2 ++ taglib/riff/aiff/aiffproperties.cpp | 49 ++++++++++++++++++++++++----- taglib/riff/aiff/aiffproperties.h | 10 +++++- tests/test_aiff.cpp | 2 +- 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index 6c136cde..6a6a84e8 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -137,42 +137,23 @@ bool RIFF::AIFF::File::hasID3v2Tag() const void RIFF::AIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) { - ByteVector formatData; - for(uint i = 0; i < chunkCount(); i++) { + for(uint i = 0; i < chunkCount(); ++i) { const ByteVector name = chunkName(i); if(name == "ID3 " || name == "id3 ") { if(!d->tag) { - d->tagChunkID = name; d->tag = new ID3v2::Tag(this, chunkOffset(i)); + d->tagChunkID = name; d->hasID3v2 = true; } else { debug("RIFF::AIFF::File::read() - Duplicate ID3v2 tag found."); } } - else if(readProperties) { - if(name == "COMM") { - if(formatData.isEmpty()) { - formatData = chunkData(i); - } - 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."); - } - } - } } if(!d->tag) - d->tag = new ID3v2::Tag; + d->tag = new ID3v2::Tag(); - if(!formatData.isEmpty()) - d->properties = new Properties(formatData, propertiesStyle); + if(readProperties) + d->properties = new Properties(this, propertiesStyle); } diff --git a/taglib/riff/aiff/aifffile.h b/taglib/riff/aiff/aifffile.h index a35b4cf3..8a5b45d3 100644 --- a/taglib/riff/aiff/aifffile.h +++ b/taglib/riff/aiff/aifffile.h @@ -132,6 +132,8 @@ namespace TagLib { void read(bool readProperties, Properties::ReadStyle propertiesStyle); + friend class Properties; + class FilePrivate; FilePrivate *d; }; diff --git a/taglib/riff/aiff/aiffproperties.cpp b/taglib/riff/aiff/aiffproperties.cpp index 8cb5de62..6112e0d8 100644 --- a/taglib/riff/aiff/aiffproperties.cpp +++ b/taglib/riff/aiff/aiffproperties.cpp @@ -25,6 +25,7 @@ #include #include +#include "aifffile.h" #include "aiffproperties.h" using namespace TagLib; @@ -56,11 +57,18 @@ public: // public members //////////////////////////////////////////////////////////////////////////////// -RIFF::AIFF::Properties::Properties(const ByteVector &data, ReadStyle style) : +RIFF::AIFF::Properties::Properties(const ByteVector & /*data*/, ReadStyle style) : AudioProperties(style), d(new PropertiesPrivate()) { - read(data); + debug("RIFF::AIFF::Properties::Properties() - This constructor is no longer used."); +} + +RIFF::AIFF::Properties::Properties(File *file, ReadStyle style) : + AudioProperties(style), + d(new PropertiesPrivate()) +{ + read(file); } RIFF::AIFF::Properties::~Properties() @@ -127,14 +135,38 @@ String RIFF::AIFF::Properties::compressionName() const { return d->compressionName; } + //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// -void RIFF::AIFF::Properties::read(const ByteVector &data) +void RIFF::AIFF::Properties::read(File *file) { + ByteVector data; + uint streamLength = 0; + for(uint i = 0; i < file->chunkCount(); i++) { + const ByteVector name = file->chunkName(i); + if(name == "COMM") { + if(data.isEmpty()) + data = file->chunkData(i); + else + debug("RIFF::AIFF::Properties::read() - Duplicate 'COMM' chunk found."); + } + else if(name == "SSND") { + if(streamLength == 0) + streamLength = file->chunkDataSize(i) + file->chunkPadding(i); + else + debug("RIFF::AIFF::Properties::read() - Duplicate 'SSND' chunk found."); + } + } + if(data.size() < 18) { - debug("RIFF::AIFF::Properties::read() - \"COMM\" chunk is too short for AIFF."); + debug("RIFF::AIFF::Properties::read() - 'COMM' chunk not found or too short."); + return; + } + + if(streamLength == 0) { + debug("RIFF::AIFF::Properties::read() - 'SSND' chunk not found."); return; } @@ -143,10 +175,13 @@ void RIFF::AIFF::Properties::read(const ByteVector &data) d->bitsPerSample = data.toShort(6U); const long double sampleRate = data.toFloat80BE(8); - if(sampleRate >= 1.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(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); } if(data.size() >= 23) { diff --git a/taglib/riff/aiff/aiffproperties.h b/taglib/riff/aiff/aiffproperties.h index 651592a7..1d92ac87 100644 --- a/taglib/riff/aiff/aiffproperties.h +++ b/taglib/riff/aiff/aiffproperties.h @@ -49,9 +49,17 @@ namespace TagLib { /*! * Create an instance of AIFF::Properties with the data read from the * ByteVector \a data. + * + * \deprecated */ Properties(const ByteVector &data, ReadStyle style); + /*! + * Create an instance of AIFF::Properties with the data read from the + * AIFF::File \a file. + */ + Properties(File *file, ReadStyle style); + /*! * Destroys this AIFF::Properties instance. */ @@ -146,7 +154,7 @@ namespace TagLib { Properties(const Properties &); Properties &operator=(const Properties &); - void read(const ByteVector &data); + void read(File *file); class PropertiesPrivate; PropertiesPrivate *d; diff --git a/tests/test_aiff.cpp b/tests/test_aiff.cpp index 360b7549..386c7686 100644 --- a/tests/test_aiff.cpp +++ b/tests/test_aiff.cpp @@ -45,7 +45,7 @@ public: 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(355, f.audioProperties()->bitrate()); CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample());