2018-11-14 Fred Gleason <fredg@paravelsystems.com>

* Added a '--metadata-cart=' switch to the 'audio_convert_test'
	test harness.
	* Added an 'audio_metadata_test' test harness.
	* Modified ID3 tag reading/writing to use TagLib.
This commit is contained in:
Fred Gleason 2018-11-14 14:40:44 -05:00
parent 8af01a466d
commit e8c619988f
21 changed files with 968 additions and 108 deletions

1
.gitignore vendored
View File

@ -95,6 +95,7 @@ systemd/rivendell.service
tests/audio_convert_test
tests/audio_export_test
tests/audio_import_test
tests/audio_metadata_test
tests/audio_peaks_test
tests/datedecode_test
tests/db_charset_test

View File

@ -18007,3 +18007,8 @@
* Fixed a regression in rdpanel(1) background image.
2018-11-09 Fred Gleason <fredg@paravelsystems.com>
* Removed a debugging printf in rdpanel(1).
2018-11-14 Fred Gleason <fredg@paravelsystems.com>
* Added a '--metadata-cart=' switch to the 'audio_convert_test'
test harness.
* Added an 'audio_metadata_test' test harness.
* Modified ID3 tag reading/writing to use TagLib.

View File

@ -58,6 +58,10 @@ Available at http://www.surina.net/soundtouch/.
Systemd System and Service Manager
Most modern Linux distros include this.
TagLib Audio Meta-Data Library, v1.8 or better
A high-quality C++ library for reading and writing a variety of audio metadata
formats. Available at https://taglib.org/.
X11 Window System
Virtually all Linux distros should include this.

View File

@ -227,6 +227,11 @@ fi
#
AC_CHECK_HEADER(id3/tag.h,[],[AC_MSG_ERROR([*** Id3Lib not found ***])])
#
# Check for TagLib
#
AC_CHECK_HEADER(taglib/taglib.h,[],[AC_MSG_ERROR([*** TagLib not found ***])])
#
# Check for LibCurl
#
@ -293,7 +298,8 @@ fi
#
# Set Hard Library Dependencies
#
AC_SUBST(LIB_RDLIBS,"-lm -lpthread -lrd -lcurl -lid3 $FLAC_LIBS -lsndfile -lsamplerate -lcdda_interface -lcdda_paranoia -lcrypt -ldl -lpam -lSoundTouch -lcrypto")
#AC_SUBST(LIB_RDLIBS,"-lm -lpthread -lrd -lcurl -lid3 $FLAC_LIBS -lsndfile -lsamplerate -lcdda_interface -lcdda_paranoia -lcrypt -ldl -lpam -lSoundTouch -lcrypto")
AC_SUBST(LIB_RDLIBS,"-lm -lpthread -lrd -lcurl -lid3 -ltag $FLAC_LIBS -lsndfile -lsamplerate -lcdda_interface -lcdda_paranoia -lcrypt -ldl -lpam -lSoundTouch -lcrypto")
#
# Setup MPEG Dependencies

View File

@ -20,7 +20,7 @@
##
## Use automake to process this into a Makefile.in
AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" @QT4_CFLAGS@ -Wno-strict-aliasing -DQT3_SUPPORT -I/usr/include/Qt3Support
AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" @QT4_CFLAGS@ -Wno-strict-aliasing -DQT3_SUPPORT -I/usr/include/Qt3Support -I/usr/include/taglib
MOC = @QT_MOC@
CWRAP = ../helpers/cwrap

View File

@ -685,6 +685,82 @@
<source>Unable to update automounter configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM8</source>
<translation type="unfinished">PCM8</translation>
</message>
<message>
<source>PCM16</source>
<translation type="unfinished">PCM16</translation>
</message>
<message>
<source>Float32</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer I</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer II (MP2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer III (MP3)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>OggVorbis</source>
<translation type="unfinished">OggVorbis</translation>
</message>
<message>
<source>PCM24</source>
<translation type="unfinished">PCM24</translation>
</message>
<message>
<source>RIFF/WAVE</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw MPEG Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ogg Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ATX</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TMC</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw FLAC Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AM-BOS Hybrid</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AIFF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MP4</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RDAddCart</name>

View File

@ -681,6 +681,82 @@
<source>Unable to update automounter configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM8</source>
<translation type="unfinished">PCM8</translation>
</message>
<message>
<source>PCM16</source>
<translation type="unfinished">PCM16</translation>
</message>
<message>
<source>Float32</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer I</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer II (MP2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer III (MP3)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>OggVorbis</source>
<translation type="unfinished">OggVorbis</translation>
</message>
<message>
<source>PCM24</source>
<translation type="unfinished">PCM24</translation>
</message>
<message>
<source>RIFF/WAVE</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw MPEG Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ogg Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ATX</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TMC</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw FLAC Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AM-BOS Hybrid</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AIFF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MP4</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RDAddCart</name>

View File

@ -681,6 +681,82 @@
<source>Unable to update automounter configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM8</source>
<translation type="unfinished">PCM8</translation>
</message>
<message>
<source>PCM16</source>
<translation type="unfinished">PCM16</translation>
</message>
<message>
<source>Float32</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer I</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer II (MP2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer III (MP3)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>OggVorbis</source>
<translation type="unfinished">OggVorbis</translation>
</message>
<message>
<source>PCM24</source>
<translation type="unfinished">PCM24</translation>
</message>
<message>
<source>RIFF/WAVE</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw MPEG Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ogg Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ATX</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TMC</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw FLAC Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AM-BOS Hybrid</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AIFF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MP4</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RDAddCart</name>

View File

@ -651,6 +651,82 @@
<source>Unable to update automounter configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM8</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM16</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Float32</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer I</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer II (MP2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer III (MP3)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>OggVorbis</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM24</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>RIFF/WAVE</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw MPEG Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ogg Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ATX</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TMC</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw FLAC Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AM-BOS Hybrid</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AIFF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MP4</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RDAddCart</name>

View File

@ -681,6 +681,82 @@
<source>Unable to update automounter configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM8</source>
<translation type="unfinished">PCM8</translation>
</message>
<message>
<source>PCM16</source>
<translation type="unfinished">PCM16</translation>
</message>
<message>
<source>Float32</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer I</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer II (MP2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer III (MP3)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>OggVorbis</source>
<translation type="unfinished">Ogg Vorbis</translation>
</message>
<message>
<source>PCM24</source>
<translation type="unfinished">PCM24</translation>
</message>
<message>
<source>RIFF/WAVE</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw MPEG Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ogg Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ATX</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TMC</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw FLAC Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AM-BOS Hybrid</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AIFF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MP4</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RDAddCart</name>

View File

@ -681,6 +681,82 @@
<source>Unable to update automounter configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM8</source>
<translation type="unfinished">PCM8</translation>
</message>
<message>
<source>PCM16</source>
<translation type="unfinished">PCM16</translation>
</message>
<message>
<source>Float32</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer I</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer II (MP2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer III (MP3)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>OggVorbis</source>
<translation type="unfinished">Ogg Vorbis</translation>
</message>
<message>
<source>PCM24</source>
<translation type="unfinished">PCM24</translation>
</message>
<message>
<source>RIFF/WAVE</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw MPEG Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ogg Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ATX</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TMC</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw FLAC Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AM-BOS Hybrid</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AIFF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MP4</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RDAddCart</name>

View File

@ -681,6 +681,82 @@
<source>Unable to update automounter configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PCM8</source>
<translation type="unfinished">PCM8</translation>
</message>
<message>
<source>PCM16</source>
<translation type="unfinished">PCM16</translation>
</message>
<message>
<source>Float32</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer I</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer II (MP2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MPEG Layer III (MP3)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dolby AC3</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>OggVorbis</source>
<translation type="unfinished">OggVorbis</translation>
</message>
<message>
<source>PCM24</source>
<translation type="unfinished">PCM24</translation>
</message>
<message>
<source>RIFF/WAVE</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw MPEG Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ogg Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ATX</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TMC</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Raw FLAC Bitstream</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AM-BOS Hybrid</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AIFF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>MP4</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RDAddCart</name>

View File

@ -52,7 +52,10 @@
#include <mp4v2/mp4v2.h>
#include <neaacdec.h>
#endif // HAVE_MP4_LIBS
#include <id3/tag.h>
//#include <id3/tag.h>
#include <id3v2tag.h>
#include <textidentificationframe.h>
#include <mpegfile.h>
#include <qfile.h>
#define STAGE2_XFER_SIZE 2048
@ -1886,71 +1889,71 @@ RDAudioConvert::ErrorCode RDAudioConvert::Stage3Pcm24(SNDFILE *src_sf,
void RDAudioConvert::ApplyId3Tag(const QString &filename,RDWaveData *wavedata)
{
ID3_Tag *tag=new ID3_Tag(filename);
ID3_Frame *frame=new ID3_Frame(ID3FID_TITLE);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->title().toUtf8());
tag->AddNewFrame(frame);
TagLib::MPEG::File *file=new TagLib::MPEG::File(filename.toUtf8(),false);
TagLib::PropertyMap *map=new TagLib::PropertyMap();
TagLib::ID3v2::Tag *tag=file->ID3v2Tag();
if(wavedata->beatsPerMinute()>0) {
frame=new ID3_Frame(ID3FID_BPM);
frame->GetField(ID3FN_TEXT)->
Set((const char *)QString().sprintf("%d",wavedata->beatsPerMinute()).toUtf8());
tag->AddNewFrame(frame);
AddId3Property(map,"TITLE",wavedata->title());
if(!wavedata->artist().isEmpty()) {
AddId3Property(map,"ARTIST",wavedata->artist());
}
if(!wavedata->album().isEmpty()) {
frame=new ID3_Frame(ID3FID_ALBUM);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->album().toUtf8());
tag->AddNewFrame(frame);
AddId3Property(map,"ALBUM",wavedata->album());
}
if(!wavedata->composer().isEmpty()) {
frame=new ID3_Frame(ID3FID_COMPOSER);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->composer().toUtf8());
tag->AddNewFrame(frame);
}
if(!wavedata->copyrightNotice().isEmpty()) {
frame=new ID3_Frame(ID3FID_COPYRIGHT);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->copyrightNotice().toUtf8());
tag->AddNewFrame(frame);
}
if(!wavedata->artist().isEmpty()) {
frame=new ID3_Frame(ID3FID_LEADARTIST);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->artist().toUtf8());
tag->AddNewFrame(frame);
}
if(!wavedata->publisher().isEmpty()) {
frame=new ID3_Frame(ID3FID_PUBLISHER);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->publisher().toUtf8());
tag->AddNewFrame(frame);
if(!wavedata->label().isEmpty()) {
AddId3Property(map,"LABEL",wavedata->label());
}
if(!wavedata->conductor().isEmpty()) {
frame=new ID3_Frame(ID3FID_CONDUCTOR);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->conductor().toUtf8());
tag->AddNewFrame(frame);
AddId3Property(map,"CONDUCTOR",wavedata->conductor());
}
if(!wavedata->composer().isEmpty()) {
AddId3Property(map,"COMPOSER",wavedata->composer());
}
if(!wavedata->publisher().isEmpty()) {
AddId3Property(map,"PUBLISHER",wavedata->publisher());
}
if(!wavedata->copyrightNotice().isEmpty()) {
AddId3Property(map,"COPYRIGHT",wavedata->copyrightNotice());
}
if(!wavedata->isrc().isEmpty()) {
frame=new ID3_Frame(ID3FID_ISRC);
frame->GetField(ID3FN_TEXT)->Set((const char *)wavedata->isrc().toUtf8());
tag->AddNewFrame(frame);
AddId3Property(map,"ISRC",wavedata->isrc());
}
if(wavedata->releaseYear()>0) {
frame=new ID3_Frame(ID3FID_YEAR);
frame->GetField(ID3FN_TEXT)->
Set((const char *)QString().sprintf("%d",wavedata->releaseYear()).toUtf8());
tag->AddNewFrame(frame);
AddId3Property(map,"YEAR",QString().sprintf("%d",wavedata->releaseYear()));
}
if(wavedata->beatsPerMinute()>0) {
AddId3Property(map,"BPM",
QString().sprintf("%d",wavedata->beatsPerMinute()));
}
tag->setProperties(*map);
RDCart *cart=new RDCart(wavedata->cartNumber());
if(cart->exists()) {
QString xml=
cart->xml(true,conv_start_point<0,conv_settings,wavedata->cutNumber());
frame=new ID3_Frame(ID3FID_USERTEXT);
frame->GetField(ID3FN_DESCRIPTION)->Set("rdxl");
frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_NONE);
frame->GetField(ID3FN_TEXT)->Set((const char *)xml.toUtf8());
tag->AddNewFrame(frame);
delete cart;
TagLib::ID3v2::UserTextIdentificationFrame *frame=
new TagLib::ID3v2::UserTextIdentificationFrame(TagLib::String::UTF8);
frame->setDescription("rdxl");
frame->setText(TagLib::String((const char *)xml.toUtf8(),
TagLib::String::UTF8));
tag->addFrame(frame);
}
tag->Update();
delete tag;
delete cart;
file->save();
delete map;
delete file;
}
void RDAudioConvert::AddId3Property(TagLib::PropertyMap *map,const QString &key,
const QString &value) const
{
TagLib::StringList args;
args.
append(TagLib::String((const char *)value.toUtf8(),TagLib::String::UTF8));
map->insert((const char *)key.toUtf8(),args);
}

View File

@ -22,6 +22,8 @@
#define RDAUDIOCONVERT_H
#include <sndfile.h>
#include <taglib/taglib.h>
#include <taglib/tpropertymap.h>
#ifdef HAVE_TWOLAME
#include <twolame.h>
#endif // HAVE_TWOLAME
@ -98,6 +100,8 @@ class RDAudioConvert : public QObject
RDAudioConvert::ErrorCode Stage3Pcm24(SNDFILE *src_sf,SF_INFO *src_sf_info,
const QString &dstfile);
void ApplyId3Tag(const QString &filename,RDWaveData *wavedata);
void AddId3Property(TagLib::PropertyMap *map,
const QString &key,const QString &value) const;
void UpdatePeak(const float data[],ssize_t len);
void UpdatePeak(const double data[],ssize_t len);
bool LoadMad();

View File

@ -34,14 +34,23 @@
#include <assert.h>
#include <arpa/inet.h>
#include <typeinfo>
#include <id3/tag.h>
#include <id3/misc_support.h>
#include <fileref.h>
#include <apetag.h>
#include <id3v1tag.h>
#include <id3v2tag.h>
#include <tag.h>
#include <tpropertymap.h>
#ifdef HAVE_FLAC
#include <FLAC/metadata.h>
#endif // HAVE_FLAC
#include <qobject.h>
#include <qstring.h>
#include <qtextcodec.h>
#include <qdatetime.h>
//Added by qt3to4:
#include <Q3CString>
@ -2164,6 +2173,111 @@ void RDWaveFile::setRdxlContents(const QString &xml)
}
QString RDWaveFile::formatText(RDWaveFile::Format fmt)
{
QString ret=QObject::tr("unknown");
switch(fmt) {
case RDWaveFile::Pcm8:
ret=QObject::tr("PCM8");
break;
case RDWaveFile::Pcm16:
ret=QObject::tr("PCM16");
break;
case RDWaveFile::Float32:
ret=QObject::tr("Float32");
break;
case RDWaveFile::MpegL1:
ret=QObject::tr("MPEG Layer I");
break;
case RDWaveFile::MpegL2:
ret=QObject::tr("MPEG Layer II (MP2)");
break;
case RDWaveFile::MpegL3:
ret=QObject::tr("MPEG Layer III (MP3)");
break;
case RDWaveFile::DolbyAc2:
ret=QObject::tr("Dolby AC2");
break;
case RDWaveFile::DolbyAc3:
ret=QObject::tr("Dolby AC3");
break;
case RDWaveFile::Vorbis:
ret=QObject::tr("OggVorbis");
break;
case RDWaveFile::Pcm24:
ret=QObject::tr("PCM24");
break;
}
return ret;
}
enum Format {Pcm8=0,Pcm16=1,Float32=2,MpegL1=3,MpegL2=4,MpegL3=5,
DolbyAc2=6,DolbyAc3=7,Vorbis=8,Pcm24=9};
enum Type {Unknown=0,Wave=1,Mpeg=2,Ogg=3,Atx=4,Tmc=5,Flac=6,Ambos=7,
Aiff=8,M4A=9};
QString RDWaveFile::typeText(RDWaveFile::Type type)
{
QString ret=QObject::tr("unknown");
switch(type) {
case RDWaveFile::Unknown:
break;
case RDWaveFile::Wave:
ret=QObject::tr("RIFF/WAVE");
break;
case RDWaveFile::Mpeg:
ret=QObject::tr("Raw MPEG Bitstream");
break;
case RDWaveFile::Ogg:
ret=QObject::tr("Ogg Bitstream");
break;
case RDWaveFile::Atx:
ret=QObject::tr("ATX");
break;
case RDWaveFile::Tmc:
ret=QObject::tr("TMC");
break;
case RDWaveFile::Flac:
ret=QObject::tr("Raw FLAC Bitstream");
break;
case RDWaveFile::Ambos:
ret=QObject::tr("AM-BOS Hybrid");
break;
case RDWaveFile::Aiff:
ret=QObject::tr("AIFF");
break;
case RDWaveFile::M4A:
ret=QObject::tr("MP4");
break;
}
return ret;
}
RDWaveFile::Type RDWaveFile::GetType(int fd)
{
if(IsWav(fd)) {
@ -3357,63 +3471,105 @@ void RDWaveFile::ReadId3Metadata()
if(wave_data==NULL) {
return;
}
ID3_Frame *frame=NULL;
ID3_Tag id3_tag(Q3CString().sprintf("%s",(const char *)wave_file.name().utf8()));
if((frame=id3_tag.Find(ID3FID_USERTEXT,ID3FN_DESCRIPTION,"rdxl"))!=NULL) {
rdxl_contents=ID3_GetString(frame,ID3FN_TEXT);
if(wave_data!=NULL) {
std::vector<RDWaveData> wavedatas;
if(RDCart::readXml(&wavedatas,rdxl_contents)>1) {
*wave_data=wavedatas[1];
bool using_rdxl=false;
TagLib::FileRef tagref(wave_file.name().toUtf8());
TagLib::PropertyMap tags=tagref.file()->properties();
//
// Check for an RDXL frame
// If we find one, use id3lib to process it, otherwise continue with TagLib
//
for(TagLib::PropertyMap::ConstIterator it=tags.begin();it!=tags.end();++it) {
QString name=QString::fromUtf8(it->first.toCString(true));
if(name==QString::fromUtf8("牤硬")) { // Mangled RD v2.x RDXL Frame
using_rdxl=true;
ID3_Frame *frame=NULL;
ID3_Tag id3_tag(wave_file.name().toUtf8());
if((frame=id3_tag.Find(ID3FID_USERTEXT,ID3FN_DESCRIPTION,"rdxl"))!=NULL) {
rdxl_contents=ID3_GetString(frame,ID3FN_TEXT);
if(wave_data!=NULL) {
std::vector<RDWaveData> wavedatas;
if(RDCart::readXml(&wavedatas,rdxl_contents)>1) {
*wave_data=wavedatas[1];
}
}
}
}
if(name=="RDXL") {
using_rdxl=true;
rdxl_contents=QString::fromUtf8(it->second.begin()->toCString(true));
if(wave_data!=NULL) {
std::vector<RDWaveData> wavedatas;
if(RDCart::readXml(&wavedatas,rdxl_contents)>1) {
*wave_data=wavedatas[1];
}
}
}
}
else {
if((frame=id3_tag.Find(ID3FID_TITLE))!=NULL) {
wave_data->setTitle(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_BPM))!=NULL) {
wave_data->
setBeatsPerMinute(QString(ID3_GetString(frame,ID3FN_TEXT)).toInt());
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_ALBUM))!=NULL) {
wave_data->setAlbum(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_COMPOSER))!=NULL) {
wave_data->setComposer(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_COPYRIGHT))!=NULL) {
wave_data->setCopyrightNotice(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_ORIGARTIST))!=NULL) {
wave_data->setArtist(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_LEADARTIST))!=NULL) {
wave_data->setArtist(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_CONDUCTOR))!=NULL) {
wave_data->setConductor(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_PUBLISHER))!=NULL) {
wave_data->setPublisher(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_ISRC))!=NULL) {
wave_data->setIsrc(ID3_GetString(frame,ID3FN_TEXT));
wave_data->setMetadataFound(true);
}
if((frame=id3_tag.Find(ID3FID_YEAR))!=NULL) {
wave_data->
setReleaseYear(QString(ID3_GetString(frame,ID3FN_TEXT)).toInt());
wave_data->setMetadataFound(true);
if(!using_rdxl) {
for(TagLib::PropertyMap::ConstIterator it=tags.begin();it!=tags.end();++it) {
QString name=QString::fromUtf8(it->first.toCString(true));
if(name=="TITLE") {
wave_data->
setTitle(QString::fromUtf8(it->second.begin()->toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="ARTIST") {
wave_data->
setArtist(QString::fromUtf8(it->second.begin()->toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="ALBUM") {
wave_data->
setAlbum(QString::fromUtf8(it->second.begin()->toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="COMPOSER") {
wave_data->
setComposer(QString::fromUtf8(it->second.begin()->toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="CONDUCTOR") {
wave_data->
setConductor(QString::fromUtf8(it->second.begin()->toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="PUBLISHER") {
wave_data->
setPublisher(QString::fromUtf8(it->second.begin()->toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="ISRC") {
wave_data->
setIsrc(QString::fromUtf8(it->second.begin()->toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="COPYRIGHT") {
wave_data->
setCopyrightNotice(QString::fromUtf8(it->second.begin()->
toCString(true)));
wave_data->setMetadataFound(true);
}
if(name=="YEAR") {
wave_data->
setReleaseYear(QString(it->second.begin()->toCString(true)).toInt());
wave_data->setMetadataFound(true);
}
if(name=="BPM") {
wave_data->
setBeatsPerMinute(QString(it->second.begin()->toCString(true)).toInt());
wave_data->setMetadataFound(true);
}
/*
printf("TAG: %s = ",it->first.toCString(true));
for(TagLib::StringList::ConstIterator it2=it->second.begin();it2!=
it->second.end();
++it2) {
printf("%s ",it2->toCString(true));
}
printf("\n");
*/
}
}
}

View File

@ -1014,6 +1014,10 @@ class RDWaveFile
double getNormalizeLevel() const;
void setNormalizeLevel(double level);
static QString formatText(Format fmt);
static QString typeText(Type type);
private:
RDWaveFile::Type GetType(int fd);
bool IsWav(int fd);

View File

@ -29,6 +29,7 @@ moc_%.cpp: %.h
noinst_PROGRAMS = audio_convert_test\
audio_export_test\
audio_import_test\
audio_metadata_test\
audio_peaks_test\
datedecode_test\
db_charset_test\
@ -53,6 +54,9 @@ audio_export_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support
dist_audio_import_test_SOURCES = audio_import_test.cpp audio_import_test.h
audio_import_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support
dist_audio_metadata_test_SOURCES = audio_metadata_test.cpp audio_metadata_test.h
audio_metadata_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support
dist_audio_peaks_test_SOURCES = audio_peaks_test.cpp audio_peaks_test.h
audio_peaks_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support

View File

@ -2,7 +2,7 @@
//
// Test the Rivendell file format converter.
//
// (C) Copyright 2010-2016 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2010-2018 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -29,11 +29,13 @@ MainObject::MainObject(QObject *parent)
:QObject(parent)
{
QString err_msg;
RDWaveData *wavedata=NULL;
destination_settings=new RDSettings();
start_point=-1;
end_point=-1;
speed_ratio=1.0;
metadata_cart=0;
bool ok=false;
RDAudioConvert::ErrorCode conv_err;
@ -131,6 +133,14 @@ MainObject::MainObject(QObject *parent)
destination_settings->setQuality(quality);
rda->cmdSwitch()->setProcessed(i,true);
}
if(rda->cmdSwitch()->key(i)=="--metadata-cart") {
metadata_cart=rda->cmdSwitch()->value(i).toUInt(&ok);
if((!ok)||(metadata_cart==0)||(metadata_cart>RD_MAX_CART_NUMBER)) {
fprintf(stderr,"audio_convert_test: invalid --metadata-cart\n");
exit(256);
}
rda->cmdSwitch()->setProcessed(i,true);
}
if(rda->cmdSwitch()->key(i)=="--normalization-level") {
int normalization_level=rda->cmdSwitch()->value(i).toInt(&ok);
if((!ok)||(normalization_level>0)) {
@ -162,11 +172,23 @@ MainObject::MainObject(QObject *parent)
fprintf(stderr,"audio_convert_test: --destination-bit-rate and --destination-quality are mutually exclusive\n");
exit(256);
}
if(metadata_cart>0) {
RDCart *cart=new RDCart(metadata_cart);
if(!cart->exists()) {
fprintf(stderr,"audio_convert_test: --metadata-cart does not exist\n");
exit(256);
}
wavedata=new RDWaveData();
cart->getMetadata(wavedata);
wavedata->setCutNumber(1);
delete cart;
}
RDAudioConvert *conv=new RDAudioConvert(this);
conv->setSourceFile(source_filename);
conv->setDestinationFile(destination_filename);
conv->setDestinationSettings(destination_settings);
conv->setDestinationWaveData(wavedata);
conv->setRange(start_point,end_point);
conv->setSpeedRatio(speed_ratio);
printf("Converting...\n");

View File

@ -27,7 +27,7 @@
#include <rdsettings.h>
#define AUDIO_CONVERT_TEST_USAGE "[options]\n\nTest the Rivendell audio converter routines\n\nOptions are:\n--source-file=<filename>\n\n--destination-file=<filename>\n\n--start-point=<msecs>\n\n--end-point=<msecs>\n\n--destination-format=<fmt>\n Supported formats are:\n 0 - PCM16 WAV\n 2 - MPEG Layer 2\n 3 - MPEG Layer 3\n 4 - FLAC\n 5 - OggVorbis\n 6 - MPEG Layer 2 WAV\n 7 - PCM24 WAV\n\n--destination-channels=<chans>\n\n--destination-sample-rate=<rate>\n\n--destination-bit-rate=<rate>\n\n--destination-quality=<qual>\n\n--normalization-level=<dbfs>\n\n--speed-ratio=<ratio>\n\n"
#define AUDIO_CONVERT_TEST_USAGE "[options]\n\nTest the Rivendell audio converter routines\n\nOptions are:\n--source-file=<filename>\n\n--destination-file=<filename>\n\n--start-point=<msecs>\n\n--end-point=<msecs>\n\n--destination-format=<fmt>\n Supported formats are:\n 0 - PCM16 WAV\n 2 - MPEG Layer 2\n 3 - MPEG Layer 3\n 4 - FLAC\n 5 - OggVorbis\n 6 - MPEG Layer 2 WAV\n 7 - PCM24 WAV\n\n--destination-channels=<chans>\n\n--destination-sample-rate=<rate>\n\n--destination-bit-rate=<rate>\n\n--destination-quality=<qual>\n\n--normalization-level=<dbfs>\n\n--speed-ratio=<ratio>\n\n--metadata-cart=<cartnum>\n\n"
class MainObject : public QObject
@ -41,6 +41,7 @@ class MainObject : public QObject
int start_point;
int end_point;
float speed_ratio;
unsigned metadata_cart;
RDSettings *destination_settings;
};

View File

@ -0,0 +1,82 @@
// audio_metadata_test.cpp
//
// Test the Rivendell audio file metadata reader.
//
// (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <qapplication.h>
#include <rdapplication.h>
#include <rdwavefile.h>
#include "audio_metadata_test.h"
MainObject::MainObject(QObject *parent)
:QObject(parent)
{
QString err_msg;
QString filename;
//
// Open the Database
//
rda=new RDApplication("audio_metadata_test","audio_metadata_test",
AUDIO_METADATA_TEST_USAGE,this);
if(!rda->open(&err_msg)) {
fprintf(stderr,"audio_metadata_test: %s\n",(const char *)err_msg.toUtf8());
exit(1);
}
for(unsigned i=0;i<rda->cmdSwitch()->keys();i++) {
if(rda->cmdSwitch()->key(i)=="--filename") {
filename=rda->cmdSwitch()->value(i);
rda->cmdSwitch()->setProcessed(i,true);
}
}
if(filename.isEmpty()) {
fprintf(stderr,"audio_metadata_test: missing --filename\n");
exit(256);
}
RDWaveData *wavedata=new RDWaveData();
RDWaveFile *wavefile=new RDWaveFile(filename);
if(!wavefile->openWave(wavedata)) {
fprintf(stderr,"audio_metadata_test: unable to open \"%s\"\n",
(const char *)filename.toUtf8());
exit(1);
}
printf("Type: %s\n",
(const char *)RDWaveFile::typeText(wavefile->type()).toUtf8());
if(wavedata->metadataFound()) {
printf("%s\n",(const char *)wavedata->dump().toUtf8());
}
else {
printf("No metadata found.\n");
}
delete wavefile;
delete wavedata;
exit(0);
}
int main(int argc,char *argv[])
{
QApplication a(argc,argv,false);
new MainObject();
return a.exec();
}

View File

@ -0,0 +1,36 @@
// audio_metadata_test.h
//
// Test the Rivendell audio file metadata reader.
//
// (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef AUDIO_METADATA_TEST_H
#define AUDIO_METADATA_TEST_H
#include <qobject.h>
#define AUDIO_METADATA_TEST_USAGE "--filename=<filename>\n\n"
class MainObject : public QObject
{
public:
MainObject(QObject *parent=0);
};
#endif // AUDIO_METADATA_TEST_H