mirror of
https://github.com/taglib/taglib.git
synced 2026-04-12 17:09:50 -04:00
Add BEXT and iXML chunk support to WAV files (#1323)
Read, write, and remove Broadcast Audio Extension (BEXT, EBU Tech 3285) and iXML metadata chunks in WAV files. BEXT is widely used in broadcast and professional audio for originator, description, time reference, and loudness metadata. iXML is used by field recorders and DAWs for scene, take, and track metadata.
This commit is contained in:
@ -61,6 +61,10 @@ class TestWAV : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testWaveFormatExtensible);
|
||||
CPPUNIT_TEST(testInvalidChunk);
|
||||
CPPUNIT_TEST(testRIFFInfoProperties);
|
||||
CPPUNIT_TEST(testBEXTTag);
|
||||
CPPUNIT_TEST(testBEXTTagWithOtherTags);
|
||||
CPPUNIT_TEST(testiXMLTag);
|
||||
CPPUNIT_TEST(testiXMLTagWithOtherTags);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@ -482,6 +486,151 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void testBEXTTag()
|
||||
{
|
||||
ScopedFileCopy copy("empty", ".wav");
|
||||
string filename = copy.fileName();
|
||||
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(!f.hasBEXTData());
|
||||
CPPUNIT_ASSERT(f.BEXTData().isEmpty());
|
||||
|
||||
f.setBEXTData(ByteVector("test bext data"));
|
||||
f.save();
|
||||
CPPUNIT_ASSERT(f.hasBEXTData());
|
||||
}
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(f.hasBEXTData());
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("test bext data"), f.BEXTData());
|
||||
|
||||
f.setBEXTData(ByteVector());
|
||||
f.save();
|
||||
CPPUNIT_ASSERT(!f.hasBEXTData());
|
||||
}
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(!f.hasBEXTData());
|
||||
CPPUNIT_ASSERT(f.BEXTData().isEmpty());
|
||||
}
|
||||
|
||||
// Check if file without BEXT is same as original empty file
|
||||
const ByteVector origData = PlainFile(TEST_FILE_PATH_C("empty.wav")).readAll();
|
||||
const ByteVector fileData = PlainFile(filename.c_str()).readAll();
|
||||
CPPUNIT_ASSERT(origData == fileData);
|
||||
}
|
||||
|
||||
void testBEXTTagWithOtherTags()
|
||||
{
|
||||
ScopedFileCopy copy("empty", ".wav");
|
||||
string filename = copy.fileName();
|
||||
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
f.ID3v2Tag()->setTitle("ID3v2 Title");
|
||||
f.InfoTag()->setTitle("INFO Title");
|
||||
f.setBEXTData(ByteVector("bext payload"));
|
||||
f.save();
|
||||
}
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.hasID3v2Tag());
|
||||
CPPUNIT_ASSERT(f.hasInfoTag());
|
||||
CPPUNIT_ASSERT(f.hasBEXTData());
|
||||
CPPUNIT_ASSERT_EQUAL(String("ID3v2 Title"), f.ID3v2Tag()->title());
|
||||
CPPUNIT_ASSERT_EQUAL(String("INFO Title"), f.InfoTag()->title());
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("bext payload"), f.BEXTData());
|
||||
}
|
||||
}
|
||||
|
||||
void testiXMLTag()
|
||||
{
|
||||
ScopedFileCopy copy("empty", ".wav");
|
||||
string filename = copy.fileName();
|
||||
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(!f.hasiXMLData());
|
||||
CPPUNIT_ASSERT(f.iXMLData().isEmpty());
|
||||
|
||||
f.setiXMLData("<BWFXML><IXML_VERSION>1.0</IXML_VERSION></BWFXML>");
|
||||
f.save();
|
||||
CPPUNIT_ASSERT(f.hasiXMLData());
|
||||
}
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(f.hasiXMLData());
|
||||
CPPUNIT_ASSERT_EQUAL(
|
||||
String("<BWFXML><IXML_VERSION>1.0</IXML_VERSION></BWFXML>"),
|
||||
f.iXMLData());
|
||||
|
||||
f.setiXMLData(String());
|
||||
f.save();
|
||||
CPPUNIT_ASSERT(!f.hasiXMLData());
|
||||
}
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(!f.hasiXMLData());
|
||||
CPPUNIT_ASSERT(f.iXMLData().isEmpty());
|
||||
}
|
||||
|
||||
// Check if file without iXML is same as original empty file
|
||||
const ByteVector origData = PlainFile(TEST_FILE_PATH_C("empty.wav")).readAll();
|
||||
const ByteVector fileData = PlainFile(filename.c_str()).readAll();
|
||||
CPPUNIT_ASSERT(origData == fileData);
|
||||
}
|
||||
|
||||
void testiXMLTagWithOtherTags()
|
||||
{
|
||||
ScopedFileCopy copy("empty", ".wav");
|
||||
string filename = copy.fileName();
|
||||
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
f.ID3v2Tag()->setTitle("ID3v2 Title");
|
||||
f.setiXMLData("<BWFXML><SCENE>1</SCENE></BWFXML>");
|
||||
f.setBEXTData(ByteVector("bext data"));
|
||||
f.save();
|
||||
}
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.hasID3v2Tag());
|
||||
CPPUNIT_ASSERT(f.hasiXMLData());
|
||||
CPPUNIT_ASSERT(f.hasBEXTData());
|
||||
CPPUNIT_ASSERT_EQUAL(String("ID3v2 Title"), f.ID3v2Tag()->title());
|
||||
CPPUNIT_ASSERT_EQUAL(
|
||||
String("<BWFXML><SCENE>1</SCENE></BWFXML>"),
|
||||
f.iXMLData());
|
||||
CPPUNIT_ASSERT_EQUAL(ByteVector("bext data"), f.BEXTData());
|
||||
|
||||
f.setiXMLData(String());
|
||||
f.setBEXTData(ByteVector());
|
||||
f.strip();
|
||||
CPPUNIT_ASSERT(f.save());
|
||||
}
|
||||
{
|
||||
RIFF::WAV::File f(filename.c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(!f.hasID3v2Tag());
|
||||
CPPUNIT_ASSERT(!f.hasiXMLData());
|
||||
CPPUNIT_ASSERT(f.iXMLData().isEmpty());
|
||||
CPPUNIT_ASSERT(!f.hasBEXTData());
|
||||
CPPUNIT_ASSERT(f.BEXTData().isEmpty());
|
||||
}
|
||||
|
||||
// Check if file without tags is same as original empty file
|
||||
const ByteVector origData = PlainFile(TEST_FILE_PATH_C("empty.wav")).readAll();
|
||||
const ByteVector fileData = PlainFile(filename.c_str()).readAll();
|
||||
CPPUNIT_ASSERT(origData == fileData);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV);
|
||||
|
||||
Reference in New Issue
Block a user