You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
soundkonverter/src/metadata/tagengine.cpp

422 lines
17 KiB

#include "tagengine.h"
#include <tqfile.h>
// #include <taglib/attachedpictureframe.h>
#include <taglib/fileref.h>
#include <taglib/id3v1genres.h> //used to load genre list
#include <taglib/mpegfile.h>
#include <taglib/tag.h>
#include <taglib/tstring.h>
#include <taglib/tlist.h>
#include <taglib/apetag.h>
#include <taglib/id3v2tag.h>
#include <taglib/id3v1tag.h>
#include <taglib/mpcfile.h>
#include <taglib/mpegfile.h>
#include <taglib/oggfile.h>
#include <taglib/oggflacfile.h>
#include <taglib/vorbisfile.h>
#include <taglib/flacfile.h>
#include <taglib/textidentificationframe.h>
#include <taglib/uniquefileidentifierframe.h>
#include <taglib/xiphcomment.h>
#include "wavpack/wvfile.h"
#include "trueaudio/ttafile.h"
#include <config.h>
#ifdef HAVE_MP4V2
#include "mp4/mp4file.h"
#include "mp4/mp4tag.h"
#else
#include "m4a/mp4file.h"
#include "m4a/mp4itunestag.h"
#endif
#define TStringToTQString(s) TQString::fromUtf8((s).toCString(true))
// TODO COMPILATION tag
// FIXME BPM tag
TagData::TagData( const TQString& _artist, const TQString& _composer,
const TQString& _album, const TQString& _title,
const TQString& _genre, const TQString& _comment,
int _track, int _disc, int _year,
int _length, int _fileSize, int _bitrate, int _samplingRate )
{
artist = _artist;
composer = _composer;
album = _album;
title = _title;
genre = _genre;
comment = _comment;
track = _track;
disc = _disc;
year = _year;
length = _length;
fileSize = _fileSize;
bitrate = _bitrate;
samplingRate = _samplingRate;
}
TagData::~TagData()
{}
TagEngine::TagEngine()
{
TagLib::StringList genres = TagLib::ID3v1::genreList();
for( TagLib::StringList::ConstIterator it = genres.begin(), end = genres.end(); it != end; ++it )
genreList += TStringToTQString( (*it) );
genreList.sort();
}
TagEngine::~TagEngine()
{}
TagData* TagEngine::readTags( const TQString& file )
{
TagLib::FileRef fileref( TQFile::encodeName(file) );
TagData* tagData = new TagData();
if( !fileref.isNull() )
{
TagLib::Tag *tag = fileref.tag();
tagData->track = 0;
tagData->year = 0;
tagData->disc = 0;
tagData->track_gain = 210588; // 0 is a valid value
tagData->album_gain = 210588;
if( tag )
{
tagData->title = TStringToTQString( tag->title() ).stripWhiteSpace();
tagData->artist = TStringToTQString( tag->artist() ).stripWhiteSpace();
tagData->album = TStringToTQString( tag->album() ).stripWhiteSpace();
tagData->genre = TStringToTQString( tag->genre() ).stripWhiteSpace();
tagData->comment = TStringToTQString( tag->comment() ).stripWhiteSpace();
tagData->track = tag->track();
tagData->year = tag->year();
}
TagLib::AudioProperties *audioProperties = fileref.audioProperties();
if( audioProperties )
{
tagData->length = audioProperties->lengthInSeconds();
// TODO read all information
//tagData->fileSize = ;
// = audioProperties->channels();
//tagData->bitrate = audioProperties->bitrate();
tagData->samplingRate = audioProperties->sampleRate();
}
TQString disc;
TQString track_gain;
TQString album_gain;
if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) )
{
if ( file->ID3v2Tag() )
{
if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
disc = TStringToTQString( file->ID3v2Tag()->frameListMap()["TPOS"].front()->toString() ).stripWhiteSpace();
if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
tagData->composer = TStringToTQString( file->ID3v2Tag()->frameListMap()["TCOM"].front()->toString() ).stripWhiteSpace();
}
if ( file->APETag() )
{
if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
track_gain = TStringToTQString( file->APETag()->itemListMap()["REPLAYGAIN_TRACK_GAIN"].toString() ).stripWhiteSpace();
if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
album_gain = TStringToTQString( file->APETag()->itemListMap()["REPLAYGAIN_ALBUM_GAIN"].toString() ).stripWhiteSpace();
}
}
else if ( TagLib::Ogg::Vorbis::File *file = dynamic_cast<TagLib::Ogg::Vorbis::File *>( fileref.file() ) )
{
if ( file->tag() )
{
if ( !file->tag()->fieldListMap()[ "COMPOSER" ].isEmpty() )
tagData->composer = TStringToTQString( file->tag()->fieldListMap()["COMPOSER"].front() ).stripWhiteSpace();
if ( !file->tag()->fieldListMap()[ "DISCNUMBER" ].isEmpty() )
disc = TStringToTQString( file->tag()->fieldListMap()["DISCNUMBER"].front() ).stripWhiteSpace();
if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
track_gain = TStringToTQString( file->tag()->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].front() ).stripWhiteSpace();
if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
album_gain = TStringToTQString( file->tag()->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].front() ).stripWhiteSpace();
}
}
else if ( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) )
{
if ( file->xiphComment() )
{
if ( !file->xiphComment()->fieldListMap()[ "COMPOSER" ].isEmpty() )
tagData->composer = TStringToTQString( file->xiphComment()->fieldListMap()["COMPOSER"].front() ).stripWhiteSpace();
if ( !file->xiphComment()->fieldListMap()[ "DISCNUMBER" ].isEmpty() )
disc = TStringToTQString( file->xiphComment()->fieldListMap()["DISCNUMBER"].front() ).stripWhiteSpace();
if ( !file->xiphComment()->fieldListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
track_gain = TStringToTQString( file->xiphComment()->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].front() ).stripWhiteSpace();
if ( !file->xiphComment()->fieldListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
album_gain = TStringToTQString( file->xiphComment()->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].front() ).stripWhiteSpace();
}
/*if ( file->tag() )
{
if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
track_gain = TStringToTQString( file->tag()->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].front() ).stripWhiteSpace();
if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
album_gain = TStringToTQString( file->tag()->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].front() ).stripWhiteSpace();
}*/
}
else if ( TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File *>( fileref.file() ) )
{
TagLib::MP4::Tag *mp4tag = dynamic_cast<TagLib::MP4::Tag *>( file->tag() );
if( mp4tag )
{
tagData->composer = TStringToTQString( mp4tag->composer() );
disc = TQString::number( mp4tag->disk() );
}
}
/* else if ( TagLib::MPC::File *file = dynamic_cast<TagLib::MPC::File *>( fileref.file() ) )
{
if ( file->APETag() )
{
if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
track_gain = TStringToTQString( file->APETag()->itemListMap()["REPLAYGAIN_TRACK_GAIN"].toString() ).stripWhiteSpace();
if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
album_gain = TStringToTQString( file->APETag()->itemListMap()["REPLAYGAIN_ALBUM_GAIN"].toString() ).stripWhiteSpace();
}
}*/
else if ( TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File *>( fileref.file() ) )
{
if ( file->APETag() )
{
if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
track_gain = TStringToTQString( file->APETag()->itemListMap()["REPLAYGAIN_TRACK_GAIN"].toString() ).stripWhiteSpace();
if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
album_gain = TStringToTQString( file->APETag()->itemListMap()["REPLAYGAIN_ALBUM_GAIN"].toString() ).stripWhiteSpace();
}
}
else if ( TagLib::TTA::File *file = dynamic_cast<TagLib::TTA::File *>( fileref.file() ) )
{
if ( file->ID3v2Tag() )
{
if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
disc = TStringToTQString( file->ID3v2Tag()->frameListMap()["TPOS"].front()->toString() ).stripWhiteSpace();
if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
tagData->composer = TStringToTQString( file->ID3v2Tag()->frameListMap()["TCOM"].front()->toString() ).stripWhiteSpace();
}
}
if( !disc.isEmpty() )
{
int i = disc.find('/');
if( i != -1 )
// disc.right( i ).toInt() is total number of discs, we don't use this at the moment
tagData->disc = disc.left( i ).toInt();
else
tagData->disc = disc.toInt();
}
if( !track_gain.isEmpty() )
{
int i = track_gain.find(' ');
if( i != -1 )
tagData->track_gain = track_gain.left( i ).toFloat();
else
tagData->track_gain = track_gain.toFloat();
}
if( !album_gain.isEmpty() )
{
int i = album_gain.find(' ');
if( i != -1 )
tagData->album_gain = album_gain.left( i ).toFloat();
else
tagData->album_gain = album_gain.toFloat();
}
return tagData;
}
return 0;
}
bool TagEngine::writeTags( const TQString& file, TagData* tagData )
{
if( !tagData ) tagData = new TagData();
//Set default codec to UTF-8 (see bugs 111246 and 111232)
TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding( TagLib::String::UTF8 );
TagLib::FileRef fileref( TQFile::encodeName(file), false );
if ( !fileref.isNull() )
{
TagLib::Tag* tag = fileref.tag();
if ( tag )
{
tag->setTitle( QStringToTString(tagData->title) );
tag->setArtist( QStringToTString(tagData->artist) );
tag->setAlbum( QStringToTString(tagData->album) );
tag->setTrack( tagData->track );
tag->setYear( tagData->year );
tag->setComment( QStringToTString(tagData->comment) );
tag->setGenre( QStringToTString(tagData->genre) );
}
else
{
return false;
}
if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) )
{
if ( file->ID3v2Tag() )
{
if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
{
file->ID3v2Tag()->frameListMap()[ "TPOS" ].front()->setText( QStringToTString( TQString::number(tagData->disc) ) );
}
else
{
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TPOS", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
frame->setText( QStringToTString( TQString::number(tagData->disc) ) );
file->ID3v2Tag()->addFrame( frame );
}
if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
{
file->ID3v2Tag()->frameListMap()[ "TCOM" ].front()->setText( QStringToTString( tagData->composer ) );
}
else
{
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TCOM", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
frame->setText( QStringToTString( tagData->composer ) );
file->ID3v2Tag()->addFrame( frame );
}
// HACK sets the id3v2 genre tag as string
if ( !file->ID3v2Tag()->frameListMap()[ "TCON" ].isEmpty() )
{
file->ID3v2Tag()->frameListMap()[ "TCON" ].front()->setText( QStringToTString( tagData->genre ) );
}
else
{
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TCON", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
frame->setText( QStringToTString( tagData->genre ) );
file->ID3v2Tag()->addFrame( frame );
}
// HACK sets the id3v2 year tag
if ( !file->ID3v2Tag()->frameListMap()[ "TYER" ].isEmpty() )
{
file->ID3v2Tag()->frameListMap()[ "TYER" ].front()->setText( QStringToTString( TQString::number(tagData->year) ) );
}
else
{
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TYER", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
frame->setText( QStringToTString( TQString::number(tagData->year) ) );
file->ID3v2Tag()->addFrame( frame );
}
}
}
else if ( TagLib::Ogg::Vorbis::File *file = dynamic_cast<TagLib::Ogg::Vorbis::File *>( fileref.file() ) )
{
if ( file->tag() )
{
file->tag()->addField( "COMPOSER", QStringToTString( tagData->composer ), true );
file->tag()->addField( "DISCNUMBER", QStringToTString( TQString::number(tagData->disc) ), true );
}
}
else if ( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) )
{
if ( file->xiphComment() )
{
file->xiphComment()->addField( "COMPOSER", QStringToTString( tagData->composer ), true );
file->xiphComment()->addField( "DISCNUMBER", QStringToTString( TQString::number(tagData->disc) ), true );
}
}
else if ( TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File *>( fileref.file() ) )
{
TagLib::MP4::Tag *mp4tag = dynamic_cast<TagLib::MP4::Tag *>( file->tag() );
if( mp4tag )
{
mp4tag->setComposer( QStringToTString( tagData->composer ) );
mp4tag->setDisk( tagData->disc );
}
}
if ( TagLib::TTA::File *file = dynamic_cast<TagLib::TTA::File *>( fileref.file() ) )
{
if ( file->ID3v2Tag() )
{
if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
{
file->ID3v2Tag()->frameListMap()[ "TPOS" ].front()->setText( QStringToTString( TQString::number(tagData->disc) ) );
}
else
{
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TPOS", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
frame->setText( QStringToTString( TQString::number(tagData->disc) ) );
file->ID3v2Tag()->addFrame( frame );
}
if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
{
file->ID3v2Tag()->frameListMap()[ "TCOM" ].front()->setText( QStringToTString( tagData->composer ) );
}
else
{
TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TCOM", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
frame->setText( QStringToTString( tagData->composer ) );
file->ID3v2Tag()->addFrame( frame );
}
}
}
return fileref.save();
}
return false;
}
// bool TagEngine::canWrite( TQString format )
// {
// format = format.lower();
//
// if( format == "ogg" ||
// format == "flac" || format == "fla" ||
// format == "mp3" || // TODO mp2 ?
// format == "mpc" ||
// format == "aac" ||
// format == "ape" || format == "mac" ||
// format == "aa" ||
// format == "m4a" || format == "m4b" || format == "m4p" || format == "mp4" || format == "m4v" || format == "mp4v" ||
// format == "ra" || format == "rv" || format == "rm" || format == "rmj" || format == "rmvb" ||
// format == "wma" || format == "asf" )
// {
// return true;
// }
// else {
// return false;
// }
// }