return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
- if(ext == "AIF" || ext == "AIFF")
+ if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
sampleRate(0),
channels(0),
sampleWidth(0),
- sampleFrames(0)
- {
-
- }
+ sampleFrames(0) {}
int length;
int bitrate;
int sampleRate;
int channels;
int sampleWidth;
+
+ ByteVector compressionType;
+ String compressionName;
+
uint sampleFrames;
};
return d->sampleFrames;
}
+bool RIFF::AIFF::Properties::isAiffC() const
+{
+ return (!d->compressionType.isEmpty());
+}
+
+ByteVector RIFF::AIFF::Properties::compressionType() const
+{
+ return d->compressionType;
+}
+
+String RIFF::AIFF::Properties::compressionName() const
+{
+ return d->compressionName;
+}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void RIFF::AIFF::Properties::read(const ByteVector &data)
{
+ if(data.size() < 18) {
+ debug("RIFF::AIFF::Properties::read() - \"COMM\" chunk is too short for AIFF.");
+ return;
+ }
+
d->channels = data.toShort(0U);
d->sampleFrames = data.toUInt(2U);
d->sampleWidth = data.toShort(6U);
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(data.size() >= 23) {
+ d->compressionType = data.mid(18, 4);
+ d->compressionName = String(data.mid(23, static_cast<uchar>(data[22])));
+ }
}
int sampleWidth() const;
uint sampleFrames() const;
+ /*!
+ * Returns true if the file is in AIFF-C format, false if AIFF format.
+ */
+ bool isAiffC() const;
+
+ /*!
+ * Returns the compression type of the AIFF-C file. For example, "NONE" for
+ * not compressed, "ACE2" for ACE 2-to-1.
+ *
+ * If the file is in AIFF format, always returns an empty vector.
+ *
+ * \see isAiffC()
+ */
+ ByteVector compressionType() const;
+
+ /*!
+ * Returns the concrete compression name of the AIFF-C file.
+ *
+ * If the file is in AIFF format, always returns an empty string.
+ *
+ * \see isAiffC()
+ */
+ String compressionName() const;
+
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
{
CPPUNIT_TEST_SUITE(TestAIFF);
CPPUNIT_TEST(testReading);
+ CPPUNIT_TEST(testAiffCProperties);
+ CPPUNIT_TEST(testReading);
CPPUNIT_TEST_SUITE_END();
public:
delete f;
}
+ void testAiffCProperties()
+ {
+ ScopedFileCopy copy("alaw", ".aifc");
+ string filename = copy.fileName();
+
+ RIFF::AIFF::File *f = new RIFF::AIFF::File(filename.c_str());
+ 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());
+ delete f;
+ }
+
+ void testFuzzedFiles()
+ {
+ RIFF::AIFF::File f(TEST_FILE_PATH_C("segfault.aif"));
+ CPPUNIT_ASSERT(!f.isValid());
+ }
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestAIFF);