Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/soundsource.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           soundsource.cpp  -  description
00003                              -------------------
00004     begin                : Wed Feb 20 2002
00005     copyright            : (C) 2002 by Tue and Ken Haste Andersen
00006     email                :
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 *                                                                         *
00011 *   This program is free software; you can redistribute it and/or modify  *
00012 *   it under the terms of the GNU General Public License as published by  *
00013 *   the Free Software Foundation; either version 2 of the License, or     *
00014 *   (at your option) any later version.                                   *
00015 *                                                                         *
00016 ***************************************************************************/
00017 
00018 #include <QtDebug>
00019 
00020 #include <taglib/tag.h>
00021 #include <taglib/audioproperties.h>
00022 #include <taglib/vorbisfile.h>
00023 #include <taglib/id3v2frame.h>
00024 #include <taglib/id3v2header.h>
00025 #include <taglib/id3v1tag.h>
00026 #include <taglib/tmap.h>
00027 #include <taglib/tstringlist.h>
00028 #include <taglib/textidentificationframe.h>
00029 #include <taglib/wavpackfile.h>
00030 
00031 #include "soundsource.h"
00032 
00033 namespace Mixxx
00034 {
00035 
00036 // static
00037 const bool SoundSource::s_bDebugMetadata = false;
00038 
00039 /*
00040    SoundSource is an Uber-class for the reading and decoding of audio-files.
00041    Each class must have the following member functions:
00042    initializer with a filename
00043    seek()
00044    read()
00045    length()
00046    In addition there must be a static member:
00047    int ParseHeader(TrackInfoObject *Track)
00048    which is used for parsing header information, like trackname,length etc. The
00049    return type is int: 0 for OK, -1 for an error.
00050  */
00051 SoundSource::SoundSource(QString qFilename)
00052 {
00053     m_qFilename = qFilename;
00054     m_iSampleRate = 0;
00055     m_fBPM = 0.0f;
00056     m_fReplayGain = 0.0f;
00057     m_iDuration = 0;
00058     m_iBitrate = 0;
00059     m_iChannels = 0;
00060     m_sKey = "";
00061 }
00062 
00063 SoundSource::~SoundSource()
00064 {
00065 }
00066 
00067 
00068 QList<long> *SoundSource::getCuePoints()
00069 {
00070     return 0;
00071 }
00072 
00073 QString SoundSource::getFilename()
00074 {
00075     return m_qFilename;
00076 }
00077 
00078 float SoundSource::str2bpm( QString sBpm ) {
00079   float bpm = sBpm.toFloat();
00080   if(bpm < 60) bpm = 0;
00081   while( bpm > 300 ) bpm = bpm / 10.;
00082   return bpm;
00083 }
00084 
00085 QString SoundSource::getArtist()
00086 {
00087     return m_sArtist;
00088 }
00089 QString SoundSource::getTitle()
00090 {
00091     return m_sTitle;
00092 }
00093 QString SoundSource::getAlbum()
00094 {
00095     return m_sAlbum;
00096 }
00097 QString SoundSource::getType()
00098 {
00099     return m_sType;
00100 }
00101 QString SoundSource::getComment()
00102 {
00103     return m_sComment;
00104 }
00105 QString SoundSource::getYear()
00106 {
00107     return m_sYear;
00108 }
00109 QString SoundSource::getGenre()
00110 {
00111     return m_sGenre;
00112 }
00113 QString SoundSource::getTrackNumber()
00114 {
00115     return m_sTrackNumber;
00116 }
00117 float SoundSource::getReplayGain()
00118 {
00119         return m_fReplayGain;
00120 }
00121 float SoundSource::getBPM()
00122 {
00123     return m_fBPM;
00124 }
00125 int SoundSource::getDuration()
00126 {
00127     return m_iDuration;
00128 }
00129 int SoundSource::getBitrate()
00130 {
00131     return m_iBitrate;
00132 }
00133 unsigned int SoundSource::getSampleRate()
00134 {
00135     return m_iSampleRate;
00136 }
00137 int SoundSource::getChannels()
00138 {
00139     return m_iChannels;
00140 }
00141 
00142 void SoundSource::setArtist(QString artist)
00143 {
00144     m_sArtist = artist;
00145 }
00146 void SoundSource::setTitle(QString title)
00147 {
00148     m_sTitle = title;
00149 }
00150 void SoundSource::setAlbum(QString album)
00151 {
00152     m_sAlbum = album;
00153 }
00154 void SoundSource::setComment(QString comment)
00155 {
00156     m_sComment = comment;
00157 }
00158 void SoundSource::setType(QString type)
00159 {
00160     m_sType = type;
00161 }
00162 void SoundSource::setYear(QString year)
00163 {
00164     m_sYear = year;
00165 }
00166 void SoundSource::setGenre(QString genre)
00167 {
00168     m_sGenre = genre;
00169 }
00170 void SoundSource::setTrackNumber(QString trackNumber)
00171 {
00172     m_sTrackNumber = trackNumber;
00173 }
00174 void SoundSource::setReplayGain(float replaygain)
00175 {
00176         m_fReplayGain = replaygain;
00177 }
00178 void SoundSource::setBPM(float bpm)
00179 {
00180     m_fBPM = bpm;
00181 }
00182 void SoundSource::setDuration(int duration)
00183 {
00184     m_iDuration = duration;
00185 }
00186 void SoundSource::setBitrate(int bitrate)
00187 {
00188     m_iBitrate = bitrate;
00189 }
00190 void SoundSource::setSampleRate(unsigned int samplerate)
00191 {
00192     m_iSampleRate = samplerate;
00193 }
00194 void SoundSource::setChannels(int channels)
00195 {
00196     m_iChannels = channels;
00197 }
00198 QString SoundSource::getKey(){
00199     return m_sKey;
00200 }
00201 void SoundSource::setKey(QString key){
00202     m_sKey = key;
00203 }
00204 
00205 bool SoundSource::processTaglibFile(TagLib::File& f) {
00206     if (s_bDebugMetadata)
00207         qDebug() << "Parsing" << getFilename();
00208 
00209     if (f.isValid()) {
00210         TagLib::Tag *tag = f.tag();
00211         if (tag) {
00212             QString title = TStringToQString(tag->title());
00213             setTitle(title);
00214 
00215             QString artist = TStringToQString(tag->artist());
00216             setArtist(artist);
00217 
00218             QString album = TStringToQString(tag->album());
00219             setAlbum(album);
00220 
00221             QString comment = TStringToQString(tag->comment());
00222             setComment(comment);
00223 
00224             QString genre = TStringToQString(tag->genre());
00225             setGenre(genre);
00226 
00227             int iYear = tag->year();
00228             QString year = "";
00229             if (iYear > 0) {
00230                 year = QString("%1").arg(iYear);
00231                 setYear(year);
00232             }
00233 
00234             int iTrack = tag->track();
00235             QString trackNumber = "";
00236             if (iTrack > 0) {
00237                 trackNumber = QString("%1").arg(tag->track());
00238                 setTrackNumber(trackNumber);
00239             }
00240 
00241             if (s_bDebugMetadata)
00242                 qDebug() << "TagLib" << "title" << title << "artist" << artist << "album" << album << "comment" << comment << "genre" << genre << "year" << year << "trackNumber" << trackNumber;
00243         }
00244 
00245         TagLib::AudioProperties *properties = f.audioProperties();
00246         if (properties) {
00247             int lengthSeconds = properties->length();
00248             int bitrate = properties->bitrate();
00249             int sampleRate = properties->sampleRate();
00250             int channels = properties->channels();
00251 
00252             if (s_bDebugMetadata)
00253                 qDebug() << "TagLib" << "length" << lengthSeconds << "bitrate" << bitrate << "sampleRate" << sampleRate << "channels" << channels;
00254 
00255             setDuration(lengthSeconds);
00256             setBitrate(bitrate);
00257             setSampleRate(sampleRate);
00258             setChannels(channels);
00259         }
00260 
00261         // If we didn't get any audio properties, this was a failure.
00262         return properties;
00263     }
00264     return false;
00265 }
00266 
00267 void SoundSource::parseReplayGainString (QString sReplayGain) {
00268     QString ReplayGainstring = sReplayGain.remove( " dB" );
00269     float fReplayGain = pow(10,(ReplayGainstring.toFloat())/20);
00270     //I found some mp3s of mine with replaygain tag set to 0dB even if not normalized.
00271     //This is because of Rapid Evolution 3, I suppose. I prefer to rescan them by setting value to 0 (i.e. rescan via analyserrg)
00272     if(fReplayGain==1.0f){
00273         fReplayGain= 0.0f;
00274     }
00275     setReplayGain(fReplayGain);
00276 }
00277 
00278 void SoundSource::processBpmString(QString tagName, QString sBpm) {
00279     if (s_bDebugMetadata)
00280         qDebug() << tagName << "BPM" << sBpm;
00281     if (sBpm.length() > 0) {
00282         float fBpm = str2bpm(sBpm);
00283         if (fBpm > 0)
00284             setBPM(fBpm);
00285     }
00286 }
00287 
00288 bool SoundSource::processID3v2Tag(TagLib::ID3v2::Tag* id3v2) {
00289 
00290     // Print every frame in the file.
00291     if (s_bDebugMetadata) {
00292         TagLib::ID3v2::FrameList::ConstIterator it = id3v2->frameList().begin();
00293         for(; it != id3v2->frameList().end(); it++) {
00294             qDebug() << "ID3V2" << (*it)->frameID().data() << "-"
00295                     << TStringToQString((*it)->toString());
00296         }
00297     }
00298 
00299     TagLib::ID3v2::FrameList bpmFrame = id3v2->frameListMap()["TBPM"];
00300     if (!bpmFrame.isEmpty()) {
00301         QString sBpm = TStringToQString(bpmFrame.front()->toString());
00302         processBpmString("ID3v2", sBpm);
00303     }
00304 
00305     TagLib::ID3v2::FrameList keyFrame = id3v2->frameListMap()["TKEY"];
00306     if (!keyFrame.isEmpty()) {
00307         QString sKey = TStringToQString(keyFrame.front()->toString());
00308         setKey(sKey);
00309     }
00310     // Foobar2000-style ID3v2.3.0 tags
00311     // TODO: Check if everything is ok.
00312     TagLib::ID3v2::FrameList frames = id3v2->frameListMap()["TXXX"];
00313     for ( TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it ) {
00314         TagLib::ID3v2::UserTextIdentificationFrame* ReplayGainframe =
00315                 dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>( *it );
00316         if ( ReplayGainframe && ReplayGainframe->fieldList().size() >= 2 )
00317         {
00318             QString desc = TStringToQString( ReplayGainframe->description() ).toLower();
00319             if ( desc == "replaygain_album_gain" ){
00320                 QString sReplayGain = TStringToQString( ReplayGainframe->fieldList()[1]);
00321                 parseReplayGainString(sReplayGain);
00322             }
00323             if ( desc == "replaygain_track_gain" ){
00324                 QString sReplayGain = TStringToQString( ReplayGainframe->fieldList()[1]);
00325                 parseReplayGainString(sReplayGain);
00326             }
00327         }
00328     }
00329     return true;
00330 }
00331 
00332 bool SoundSource::processAPETag(TagLib::APE::Tag* ape) {
00333     if (s_bDebugMetadata) {
00334         for(TagLib::APE::ItemListMap::ConstIterator it = ape->itemListMap().begin();
00335                 it != ape->itemListMap().end(); ++it) {
00336                 qDebug() << "APE" << TStringToQString((*it).first) << "-" << TStringToQString((*it).second.toString());
00337         }
00338     }
00339 
00340     if (ape->itemListMap().contains("BPM")) {
00341         QString sBpm = TStringToQString(ape->itemListMap()["BPM"].toString());
00342         processBpmString("APE", sBpm);
00343     }
00344 
00345     if (ape->itemListMap().contains("REPLAYGAIN_ALBUM_GAIN")) {
00346         QString sReplayGain = TStringToQString(ape->itemListMap()["REPLAYGAIN_ALBUM_GAIN"].toString());
00347         parseReplayGainString(sReplayGain);
00348     }
00349 
00350     //Prefer track gain over album gain.
00351     if (ape->itemListMap().contains("REPLAYGAIN_TRACK_GAIN")) {
00352         QString sReplayGain = TStringToQString(ape->itemListMap()["REPLAYGAIN_TRACK_GAIN"].toString());
00353         parseReplayGainString(sReplayGain);
00354     }
00355     return true;
00356 }
00357 
00358 bool SoundSource::processXiphComment(TagLib::Ogg::XiphComment* xiph) {
00359     if (s_bDebugMetadata) {
00360         for (TagLib::Ogg::FieldListMap::ConstIterator it = xiph->fieldListMap().begin();
00361                 it != xiph->fieldListMap().end(); ++it) {
00362             qDebug() << "XIPH" << TStringToQString((*it).first) << "-" << TStringToQString((*it).second.toString());
00363         }
00364     }
00365 
00366     // Some tags use "BPM" so check for that.
00367     if (xiph->fieldListMap().contains("BPM")) {
00368         TagLib::StringList bpmString = xiph->fieldListMap()["BPM"];
00369         QString sBpm = TStringToQString(bpmString.toString());
00370         processBpmString("XIPH-BPM", sBpm);
00371     }
00372 
00373     // Give preference to the "TEMPO" tag which seems to be more standard
00374     if (xiph->fieldListMap().contains("TEMPO")) {
00375         TagLib::StringList bpmString = xiph->fieldListMap()["TEMPO"];
00376         QString sBpm = TStringToQString(bpmString.toString());
00377         processBpmString("XIPH-TEMPO", sBpm);
00378     }
00379 
00380     if (xiph->fieldListMap().contains("REPLAYGAIN_ALBUM_GAIN")) {
00381         TagLib::StringList rgainString = xiph->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"];
00382         QString sReplayGain = TStringToQString(rgainString.toString());
00383         parseReplayGainString(sReplayGain);
00384     }
00385 
00386     if (xiph->fieldListMap().contains("REPLAYGAIN_TRACK_GAIN")) {
00387         TagLib::StringList rgainString = xiph->fieldListMap()["REPLAYGAIN_TRACK_GAIN"];
00388         QString sReplayGain = TStringToQString(rgainString.toString());
00389         parseReplayGainString(sReplayGain);
00390     }
00391 
00392     /*
00393      * Reading key code information
00394      * Unlike, ID3 tags, there's no standard or recommendation on how to store 'key' code
00395      *
00396      * Luckily, there are only a few tools for that, e.g., Rapid Evolution (RE).
00397      * Assuming no distinction between start and end key, RE uses a "INITIALKEY"
00398      * or a "KEY" vorbis comment.
00399      */
00400     if (xiph->fieldListMap().contains("KEY")) {
00401         TagLib::StringList keyStr = xiph->fieldListMap()["KEY"];
00402         QString key = TStringToQString(keyStr.toString());
00403         setKey(key);
00404     }
00405 
00406     if (getKey() == "" && xiph->fieldListMap().contains("INITIALKEY")) {
00407         TagLib::StringList keyStr = xiph->fieldListMap()["INITIALKEY"];
00408         QString key = TStringToQString(keyStr.toString());
00409         setKey(key);
00410     }
00411     return true;
00412 }
00413 
00414 bool SoundSource::processMP4Tag(TagLib::MP4::Tag* mp4) {
00415     if (s_bDebugMetadata) {
00416         for(TagLib::MP4::ItemListMap::ConstIterator it = mp4->itemListMap().begin();
00417             it != mp4->itemListMap().end(); ++it) {
00418             qDebug() << "MP4" << TStringToQString((*it).first) << "-" << TStringToQString((*it).second.toStringList().toString());
00419         }
00420     }
00421 
00422     // Get BPM
00423     if (mp4->itemListMap().contains("tmpo")) {
00424         QString sBpm = TStringToQString(mp4->itemListMap()["tmpo"].toStringList().toString());
00425         processBpmString("MP4", sBpm);
00426     }
00427     // Get KEY (conforms to Rapid Evolution)
00428     if (mp4->itemListMap().contains("----:com.apple.iTunes:KEY")) {
00429         QString key = TStringToQString(mp4->itemListMap()["----:com.apple.iTunes:KEY"].toStringList().toString());
00430         setKey(key);
00431     }
00432 
00433     return true;
00434 }
00435 
00436 } //namespace Mixxx
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines