diff options
26 files changed, 1091 insertions, 988 deletions
diff --git a/build/depends.py b/build/depends.py index c5129e6ea2..d038d26b92 100644 --- a/build/depends.py +++ b/build/depends.py @@ -659,6 +659,7 @@ class MixxxCore(Feature): "upgrade.cpp", "soundsource.cpp", + "soundsourcetaglib.cpp", "sharedglcontext.cpp", "widget/controlwidgetconnection.cpp", diff --git a/plugins/soundsourcem4a/SConscript b/plugins/soundsourcem4a/SConscript index 1f3672142e..96df047098 100644 --- a/plugins/soundsourcem4a/SConscript +++ b/plugins/soundsourcem4a/SConscript @@ -11,8 +11,9 @@ Import('build') # On Posix default SCons.LIBPREFIX = 'lib', on Windows default SCons.LIBPREFIX = '' m4a_sources = [ - "soundsource.cpp", # required to subclass soundsource "soundsourcem4a.cpp", # MP4/M4A Support through FAAD/libmp4v2 + "soundsourcetaglib.cpp", # TagLib dependencies + "soundsource.cpp", # required to subclass SoundSource "sampleutil.cpp", # utility functions ] diff --git a/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp b/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp index 4d226947ca..d6503f7239 100644 --- a/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp +++ b/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp @@ -124,6 +124,10 @@ static MP4TrackId mp4_get_track(MP4FileHandle *handle) return MP4_INVALID_TRACK_ID; } +static void mp4_init(struct input_plugin_data *ip_data) { + memset(ip_data, 0, sizeof(*ip_data)); +} + static int mp4_open(struct input_plugin_data *ip_data) { struct mp4_private *priv; diff --git a/plugins/soundsourcem4a/soundsourcem4a.cpp b/plugins/soundsourcem4a/soundsourcem4a.cpp index 963a4156c9..c8399d7555 100644 --- a/plugins/soundsourcem4a/soundsourcem4a.cpp +++ b/plugins/soundsourcem4a/soundsourcem4a.cpp @@ -15,6 +15,7 @@ ***************************************************************************/ #include "soundsourcem4a.h" +#include "soundsourcetaglib.h" #include "sampleutil.h" #include <taglib/mp4file.h> @@ -41,7 +42,8 @@ SoundSourceM4A::SoundSourceM4A(QString qFileName) // Initialize variables to invalid values in case loading fails. mp4file = MP4_INVALID_FILE_HANDLE; filelength = 0; - memset(&ipd, 0, sizeof(ipd)); + setType("m4a"); + mp4_init(&ipd); } SoundSourceM4A::~SoundSourceM4A() { @@ -61,7 +63,7 @@ Result SoundSourceM4A::open() //Initialize the FAAD2 decoder... initializeDecoder(); - //qDebug() << "SSM4A: channels:" << m_iChannels + //qDebug() << "SSM4A: channels:" << getChannels() // << "filelength:" << filelength // << "Sample Rate:" << m_iSampleRate; return OK; @@ -70,8 +72,7 @@ Result SoundSourceM4A::open() int SoundSourceM4A::initializeDecoder() { // Copy QString to char[] buffer for mp4_open to read from later - QByteArray qbaFileName; - qbaFileName = m_qFilename.toLocal8Bit(); + const QByteArray qbaFileName(getFilename().toLocal8Bit()); int bytes = qbaFileName.length() + 1; ipd.filename = new char[bytes]; strncpy(ipd.filename, qbaFileName.constData(), bytes); @@ -84,7 +85,7 @@ int SoundSourceM4A::initializeDecoder() int mp4_open_status = mp4_open(&ipd); if (mp4_open_status != 0) { qWarning() << "SSM4A::initializeDecoder failed" - << m_qFilename << " with status:" << mp4_open_status; + << getFilename() << " with status:" << mp4_open_status; return ERR; } @@ -93,8 +94,8 @@ int SoundSourceM4A::initializeDecoder() Q_ASSERT(mp); mp4file = mp->mp4.handle; filelength = mp4_total_samples(&ipd); - m_iSampleRate = mp->sample_rate; - m_iChannels = mp->channels; + setSampleRate(mp->sample_rate); + setChannels(mp->channels); return OK; } @@ -106,10 +107,10 @@ long SoundSourceM4A::seek(long filepos){ //qDebug() << "SSM4A::seek()" << filepos; - // qDebug() << "MP4SEEK: seek time:" << filepos / (m_iChannels * m_iSampleRate) ; + // qDebug() << "MP4SEEK: seek time:" << filepos / (getChannels() * m_iSampleRate) ; int position = mp4_seek_sample(&ipd, filepos); - //int position = mp4_seek(&ipd, filepos / (m_iChannels * m_iSampleRate)); + //int position = mp4_seek(&ipd, filepos / (getChannels() * m_iSampleRate)); return position; } @@ -125,7 +126,7 @@ unsigned SoundSourceM4A::read(volatile unsigned long size, const SAMPLE* destina // sample is 16-bits = 2 bytes here, so we multiply size by channels to // get the number of bytes we want to decode. - int total_bytes_to_decode = size * m_iChannels; + int total_bytes_to_decode = size * getChannels(); int total_bytes_decoded = 0; int num_bytes_req = 4096; char* buffer = (char*)destination; @@ -148,7 +149,7 @@ unsigned SoundSourceM4A::read(volatile unsigned long size, const SAMPLE* destina // At this point *destination should be filled. If mono : double all samples // (L => R) - if (m_iChannels == 1) { + if (getChannels() == 1) { SampleUtil::doubleMonoToDualMono(as_buffer, total_bytes_decoded / 2); } @@ -168,30 +169,40 @@ unsigned SoundSourceM4A::read(volatile unsigned long size, const SAMPLE* destina inline long unsigned SoundSourceM4A::length(){ return filelength; - //return m_iChannels * mp4_duration(&ipd) * m_iSampleRate; + //return getChannels() * mp4_duration(&ipd) * m_iSampleRate; } Result SoundSourceM4A::parseHeader(){ - setType("m4a"); - TagLib::MP4::File f(getFilename().toLocal8Bit().constData()); - bool result = processTaglibFile(f); - TagLib::MP4::Tag* tag = f.tag(); + if (!readFileHeader(this, f)) { + return ERR; + } - if (tag) { - processMP4Tag(tag); + TagLib::MP4::Tag *mp4(f.tag()); + if (mp4) { + readMP4Tag(this, *mp4); + } else { + // fallback + const TagLib::Tag *tag(f.tag()); + if (tag) { + readTag(this, *tag); + } else { + return ERR; + } } - if (result) - return OK; - return ERR; + return OK; } QImage SoundSourceM4A::parseCoverArt() { - setType("m4a"); TagLib::MP4::File f(getFilename().toLocal8Bit().constData()); - return getCoverInMP4Tag(f.tag()); + TagLib::MP4::Tag *mp4(f.tag()); + if (mp4) { + return getCoverInMP4Tag(*mp4); + } else { + return QImage(); + } } QList<QString> SoundSourceM4A::supportedFileExtensions() diff --git a/plugins/soundsourcemediafoundation/SConscript b/plugins/soundsourcemediafoundation/SConscript index a0284db8cd..0fc749c542 100644 --- a/plugins/soundsourcemediafoundation/SConscript +++ b/plugins/soundsourcemediafoundation/SConscript @@ -18,7 +18,7 @@ if int(build.flags['mediafoundation']): else:
env["LINKFLAGS"].remove("/subsystem:windows,5.01")
ssmediafoundation_bin = env.SharedLibrary('soundsourcemediafoundation',
- ['soundsource.cpp', 'soundsourcemediafoundation.cpp'],
+ ['soundsource.cpp', 'soundsourcetaglib.cpp', 'soundsourcemediafoundation.cpp'],
LINKCOM = [env['LINKCOM'],
'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1'])
Return("ssmediafoundation_bin")
diff --git a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp index e3c4aac68e..2016ca406e 100644 --- a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp +++ b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.cpp @@ -30,6 +30,7 @@ #include <propvarutil.h> #include "soundsourcemediafoundation.h" +#include "soundsourcetaglib.h" const int kBitsPerSample = 16; const int kNumChannels = 2; @@ -50,7 +51,6 @@ template<class T> static void safeRelease(T **ppT) SoundSourceMediaFoundation::SoundSourceMediaFoundation(QString filename) : SoundSource(filename) - , m_file(filename) , m_pReader(NULL) , m_pAudioType(NULL) , m_wcFilename(NULL) @@ -66,8 +66,9 @@ SoundSourceMediaFoundation::SoundSourceMediaFoundation(QString filename) { // these are always the same, might as well just stick them here // -bkgood - m_iChannels = kNumChannels; - m_iSampleRate = kSampleRate; + setType("m4a"); + setChannels(kNumChannels); + setSampleRate(kSampleRate); // http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/35c6a451-3507-40c8-9d1c-8d4edde7c0cc // gives maximum path + file length as 248 + 260, using that -bkgood @@ -88,11 +89,11 @@ SoundSourceMediaFoundation::~SoundSourceMediaFoundation() Result SoundSourceMediaFoundation::open() { if (sDebug) { - qDebug() << "open()" << m_qFilename; + qDebug() << "open()" << getFilename(); } - QString qurlStr(m_qFilename); - int wcFilenameLength(m_qFilename.toWCharArray(m_wcFilename)); + QString qurlStr(getFilename()); + int wcFilenameLength(getFilename().toWCharArray(m_wcFilename)); // toWCharArray does not append a null terminator to the string! m_wcFilename[wcFilenameLength] = '\0'; @@ -114,7 +115,7 @@ Result SoundSourceMediaFoundation::open() // Create the source reader to read the input file. hr = MFCreateSourceReaderFromURL(m_wcFilename, NULL, &m_pReader); if (FAILED(hr)) { - qWarning() << "SSMF: Error opening input file:" << m_qFilename; + qWarning() << "SSMF: Error opening input file:" << getFilename(); return ERR; } @@ -375,26 +376,38 @@ inline unsigned long SoundSourceMediaFoundation::length() Result SoundSourceMediaFoundation::parseHeader() { - setType("m4a"); - // Must be toLocal8Bit since Windows fopen does not do UTF-8 TagLib::MP4::File f(getFilename().toLocal8Bit().constData()); - bool result = processTaglibFile(f); - TagLib::MP4::Tag* tag = f.tag(); - if (tag) { - processMP4Tag(tag); + if (!readFileHeader(this, f)) { + return ERR; } - if (result) - return OK; - return ERR; + TagLib::MP4::Tag *mp4(f.tag()); + if (mp4) { + readMP4Tag(this, *mp4); + } else { + // fallback + const TagLib::Tag *tag(f.tag()); + if (tag) { + readTag(this, *tag); + } else { + return ERR; + } + } + + return OK; } QImage SoundSourceMediaFoundation::parseCoverArt() { setType("m4a"); TagLib::MP4::File f(getFilename().toLocal8Bit().constData()); - return getCoverInMP4Tag(f.tag()); + TagLib::MP4::Tag *mp4(f.tag()); + if (mp4) { + return Mixxx::getCoverInMP4Tag(*mp4); + } else { + return QImage(); + } } // static @@ -567,15 +580,15 @@ bool SoundSourceMediaFoundation::readProperties() // QuadPart isn't available on compilers that don't support _int64. Visual // Studio 6.0 introduced the type in 1998, so I think we're safe here // -bkgood - m_iDuration = secondsFromMF(prop.hVal.QuadPart); + setDuration(secondsFromMF(prop.hVal.QuadPart)); m_mfDuration = prop.hVal.QuadPart; - qDebug() << "SSMF: Duration:" << m_iDuration; + qDebug() << "SSMF: Duration:" << getDuration(); PropVariantClear(&prop); // presentation attribute MF_PD_AUDIO_ENCODING_BITRATE only exists for // presentation descriptors, one of which MFSourceReader is not. // Therefore, we calculate it ourselves. - m_iBitrate = kBitsPerSample * kSampleRate * kNumChannels; + setBitrate(kBitsPerSample * kSampleRate * kNumChannels); return true; } diff --git a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h index 9599d1e1c1..96794568f7 100644 --- a/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h +++ b/plugins/soundsourcemediafoundation/soundsourcemediafoundation.h @@ -58,7 +58,6 @@ class SoundSourceMediaFoundation : public Mixxx::SoundSource { static inline qint64 mfFromSeconds(qreal sec); static inline qint64 frameFromMF(qint64 mf); static inline qint64 mfFromFrame(qint64 frame); - QFile m_file; IMFSourceReader *m_pReader; IMFMediaType *m_pAudioType; wchar_t *m_wcFilename; diff --git a/plugins/soundsourcewv/SConscript b/plugins/soundsourcewv/SConscript index 33843b80fc..984e3bddc5 100644 --- a/plugins/soundsourcewv/SConscript +++ b/plugins/soundsourcewv/SConscript @@ -11,8 +11,9 @@ Import('build') # On Posix default SCons.LIBPREFIX = 'lib', on Windows default SCons.LIBPREFIX = '' wv_sources = [ - "soundsource.cpp", # required to subclass soundsource "soundsourcewv.cpp", # Wavpack support + "soundsourcetaglib.cpp", # TagLib dependencies + "soundsource.cpp", # required to subclass SoundSource "sampleutil.cpp", # utility functions ] diff --git a/plugins/soundsourcewv/soundsourcewv.cpp b/plugins/soundsourcewv/soundsourcewv.cpp index 87ba22b64b..301e8ee088 100644 --- a/plugins/soundsourcewv/soundsourcewv.cpp +++ b/plugins/soundsourcewv/soundsourcewv.cpp @@ -5,17 +5,19 @@ #include <QtDebug> -#include <taglib/wavpackfile.h> - #include "soundsourcewv.h" +#include "soundsourcetaglib.h" #include "sampleutil.h" +#include <taglib/wavpackfile.h> namespace Mixxx { -SoundSourceWV::SoundSourceWV(QString qFilename) : SoundSource(qFilename) -{ - // Initialize variables to invalid values in case loading fails. - filewvc=NULL; +SoundSourceWV::SoundSourceWV(QString qFilename) + : SoundSource(qFilename), + filewvc(NULL), + Bps(0), + filelength(0) { + setType("wv"); } @@ -36,12 +38,12 @@ QList<QString> SoundSourceWV::supportedFileExtensions() Result SoundSourceWV::open() { - QByteArray qBAFilename = m_qFilename.toLocal8Bit(); - char msg[80]; //hold posible error message + QByteArray qBAFilename(getFilename().toLocal8Bit()); + char msg[80]; //hold possible error message - filewvc = WavpackOpenFileInput(qBAFilename.constData(), msg,OPEN_2CH_MAX | OPEN_WVC,0); + filewvc = WavpackOpenFileInput(qBAFilename.constData(), msg, OPEN_2CH_MAX | OPEN_WVC,0); if (!filewvc) { - qDebug() << "SSWV::open: failed to open file : "<<msg; + qDebug() << "SSWV::open: failed to open file : "<< msg; return ERR; } if (WavpackGetMode(filewvc) & MODE_FLOAT) { @@ -52,11 +54,11 @@ Result SoundSourceWV::open() } // wavpack_open succeeded -> populate variables filelength = WavpackGetNumSamples(filewvc); - m_iSampleRate=WavpackGetSampleRate(filewvc); - m_iChannels=WavpackGetReducedChannels(filewvc); + setSampleRate(WavpackGetSampleRate(filewvc)); + setChannels(WavpackGetReducedChannels(filewvc)); Bps=WavpackGetBytesPerSample(filewvc); - qDebug () << "SSWV::open: opened filewvc with filelength: "<<filelength<<" SampleRate: " << m_iSampleRate - << " channels: " << m_iChannels << " bytes per samp: "<<Bps; + qDebug () << "SSWV::open: opened filewvc with filelength: "<<filelength<<" SampleRate: " << getSampleRate() + << " channels: " << getChannels() << " bytes per samp: "<<Bps; if (Bps>2) { qDebug() << "SSWV::open: warning: input file has > 2 bytes per sample, will be truncated to 16bits"; } @@ -82,15 +84,15 @@ unsigned SoundSourceWV::read(volatile unsigned long size, const SAMPLE* destinat //tempbuffer is fixed size : WV_BUF_LENGTH of uint32 while (sampsread != size) { timesamps=(size-sampsread)>>1; //timesamps still remaining - if (timesamps > (WV_BUF_LENGTH/m_iChannels)) { //if requested size requires more than one buffer filling - timesamps=(WV_BUF_LENGTH/m_iChannels); //tempbuffer must hold (timesamps * channels) samples + if (timesamps > (WV_BUF_LENGTH / getChannels())) { //if requested size requires more than one buffer filling + timesamps=(WV_BUF_LENGTH / getChannels()); //tempbuffer must hold (timesamps * channels) samples qDebug() << "SSWV::read : performance warning, size requested > buffer size !"; } tsdone=WavpackUnpackSamples(filewvc, tempbuffer, timesamps); //fill temp buffer with timesamps*4bytes*channels //data is right justified, format_samples() fixes that. - SoundSourceWV::format_samples(Bps, (char *) (dest + (sampsread>>1)*m_iChannels), tempbuffer, tsdone*m_iChannels); + SoundSourceWV::format_samples(Bps, (char *) (dest + (sampsread>>1) * getChannels()), tempbuffer, tsdone*getChannels()); //this will unpack the 4byte/sample //output of wUnpackSamples(), sign-extending or truncating to output 16bit / sample. //specifying dest+sampsread should resume the conversion where it was left if size requested @@ -104,7 +106,7 @@ unsigned SoundSourceWV::read(volatile unsigned long size, const SAMPLE* destinat } - if (m_iChannels==1) { //if MONO : expand array to double it's size; see ssov.cpp + if (getChannels() == 1) { //if MONO : expand array to double it's size; see ssov.cpp SampleUtil::doubleMonoToDualMono(dest, sampsread / 2); } @@ -119,29 +121,37 @@ inline long unsigned SoundSourceWV::length(){ Result SoundSourceWV::parseHeader() { - setType("wv"); - - QByteArray qBAFilename = m_qFilename.toLocal8Bit(); + const QByteArray qBAFilename(getFilename().toLocal8Bit()); TagLib::WavPack::File f(qBAFilename.constData()); - // Takes care of all the default metadata - bool result = processTaglibFile(f); + if (!readFileHeader(this, f)) { + return ERR; + } TagLib::APE::Tag *ape = f.APETag(); if (ape) { - processAPETag(ape); + readAPETag(this, *ape); + } else { + // fallback + const TagLib::Tag *tag(f.tag()); + if (tag) { + readTag(this, *tag); + } else { + return ERR; + } } - if (result) - return OK; - return ERR; + return OK; } QImage SoundSourceWV::parseCoverArt() { - setType("wv"); - TagLib::WavPack::File f(m_qFilename.toLocal8Bit().constData()); + TagLib::WavPack::File f(getFilename().toLocal8Bit().constData()); TagLib::APE::Tag *ape = f.APETag(); - return getCoverInAPETag(ape); + if (ape) { + return Mixxx::getCoverInAPETag(*ape); + } else { + return QImage(); + } } void SoundSourceWV::format_samples(int Bps, char *dst, int32_t *src, uint32_t count) diff --git a/plugins/soundsourcewv/soundsourcewv.h b/plugins/soundsourcewv/soundsourcewv.h index a0a84af72c..a013e42a01 100644 --- a/plugins/soundsourcewv/soundsourcewv.h +++ b/plugins/soundsourcewv/soundsourcewv.h @@ -35,9 +35,9 @@ class SoundSourceWV : public SoundSource { QImage parseCoverArt(); static QList<QString> supportedFileExtensions(); private: + WavpackContext * filewvc; //works as a file handle to access the wv file. int Bps; unsigned long filelength; - WavpackContext * filewvc; //works as a file handle to access the wv file. int32_t tempbuffer[WV_BUF_LENGTH]; //hax ! legacy from cmus. this is 64k*4bytes. void format_samples(int, char *, int32_t *, uint32_t); }; diff --git a/src/soundsource.cpp b/src/soundsource.cpp index 19741158f3..2a2a787b67 100644 --- a/src/soundsource.cpp +++ b/src/soundsource.cpp @@ -17,18 +17,6 @@ #include <QtDebug> -#include <taglib/attachedpictureframe.h> -#include <taglib/audioproperties.h> -#include <taglib/flacpicture.h> -#include <taglib/id3v1tag.h> -#include <taglib/id3v2frame.h> -#include <taglib/id3v2header.h> -#include <taglib/tag.h> -#include <taglib/textidentificationframe.h> -#include <taglib/tmap.h> -#include <taglib/tstringlist.h> -#include <taglib/vorbisfile.h> -#include <taglib/wavpackfile.h> #include "soundsource.h" #include "util/math.h" @@ -36,607 +24,61 @@ namespace Mixxx { -// static -const bool SoundSource::s_bDebugMetadata = false; - -/* - SoundSource is an Uber-class for the reading and decoding of audio-files. - Each class must have the following member functions: - initializer with a filename - seek() - read() - length() - In addition there must be a static member: - int ParseHeader(TrackInfoObject *Track) - which is used for parsing header information, like trackname,length etc. The - return type is int: 0 for OK, -1 for an error. - */ -SoundSource::SoundSource(QString qFilename) - : m_qFilename(qFilename), - m_fReplayGain(0.0f), - m_fBPM(0.0f), - m_iDuration(0), - m_iBitrate(0), - m_iSampleRate(0), - m_iChannels(0) { -} - -SoundSource::~SoundSource() { -} - -QList<long> *SoundSource::getCuePoints() -{ - return 0; -} - -QString SoundSource::getFilename() -{ - return m_qFilename; -} - -float SoundSource::str2bpm( QString sBpm ) { - float bpm = sBpm.toFloat(); - if(bpm < 60) bpm = 0; - while( bpm > 300 ) bpm = bpm / 10.; - return bpm; -} - -QString SoundSource::getArtist() -{ - return m_sArtist; -} -QString SoundSource::getTitle() -{ - return m_sTitle; -} -QString SoundSource::getAlbum() -{ - return m_sAlbum; -} -QString SoundSource::getAlbumArtist() -{ - return m_sAlbumArtist; -} -QString SoundSource::getType() -{ - return m_sType; -} -QString SoundSource::getComment() -{ - return m_sComment; -} -QString SoundSource::getYear() -{ - return m_sYear; -} -QString SoundSource::getGenre() -{ - return m_sGenre; -} -QString SoundSource::getComposer() -{ - return m_sComposer; -} -QString SoundSource::getGrouping() -{ - return m_sGrouping; -} -QString SoundSource::getTrackNumber() -{ - return m_sTrackNumber; -} -float SoundSource::getReplayGain() -{ - return m_fReplayGain; -} -float SoundSource::getBPM() -{ - return m_fBPM; -} -int SoundSource::getDuration() -{ - return m_iDuration; -} -int SoundSource::getBitrate() -{ - return m_iBitrate; -} -unsigned int SoundSource::getSampleRate() -{ - return m_iSampleRate; -} -int SoundSource::getChannels() +namespace { - return m_iChannels; -} - -void SoundSource::setArtist(QString artist) -{ - m_sArtist = artist; -} -void SoundSource::setTitle(QString title) -{ - m_sTitle = title; -} -void SoundSource::setAlbumArtist(QString albumArtist) -{ - m_sAlbumArtist = albumArtist; -} -void SoundSource::setAlbum(QString album) -{ - m_sAlbum = album; -} -void SoundSource::setComment(QString comment) -{ - m_sComment = comment; -} -void SoundSource::setType(QString type) -{ - m_sType = type; -} -void SoundSource::setYear(QString year) -{ - m_sYear = year; -} -void SoundSource::setGenre(QString genre) -{ - m_sGenre = genre; -} -void SoundSource::setComposer(QString composer) -{ - m_sComposer = composer; -} -void SoundSource::setGrouping(QString grouping) -{ - m_sGrouping = grouping; -} -void SoundSource::setTrackNumber(QString trackNumber) -{ - m_sTrackNumber = trackNumber; -} -void SoundSource::setReplayGain(float replaygain) -{ - m_fReplayGain = replaygain; -} -void SoundSource::setBPM(float bpm) -{ - m_fBPM = bpm; -} -void SoundSource::setDuration(int duration) -{ - m_iDuration = duration; -} -void SoundSource::setBitrate(int bitrate) -{ - m_iBitrate = bitrate; -} -void SoundSource::setSampleRate(unsigned int samplerate) -{ - m_iSampleRate = samplerate; -} -void SoundSource::setChannels(int channels) -{ - m_iChannels = channels; -} -QString SoundSource::getKey(){ - return m_sKey; -} -void SoundSource::setKey(QString key){ - m_sKey = key; -} - -QString SoundSource::toQString(TagLib::String tstring) const { - if (tstring == TagLib::String::null) { - return QString(); - } - return TStringToQString(tstring); -} - -bool SoundSource::processTaglibFile(TagLib::File& f) { - if (s_bDebugMetadata) - qDebug() << "Parsing" << getFilename(); - - if (f.isValid()) { - TagLib::Tag *tag = f.tag(); - if (tag) { - QString title = toQString(tag->title()); - setTitle(title); - - QString artist = toQString(tag->artist()); - setArtist(artist); - - QString album = toQString(tag->album()); - setAlbum(album); - - QString comment = toQString(tag->comment()); - setComment(comment); - - QString genre = toQString(tag->genre()); - setGenre(genre); - - int iYear = tag->year(); - QString year = ""; - if (iYear > 0) { - year = QString("%1").arg(iYear); - setYear(year); - } - - int iTrack = tag->track(); - QString trackNumber = ""; - if (iTrack > 0) { - trackNumber = QString("%1").arg(iTrack); - setTrackNumber(trackNumber); - } + const float BPM_ZERO = 0.0f; + const float BPM_MIN = 60.0f; + const float BPM_MAX = 300.0f; - if (s_bDebugMetadata) - qDebug() << "TagLib" << "title" << title << "artist" << artist << "album" << album << "comment" << comment << "genre" << genre << "year" << year << "trackNumber" << trackNumber; - } - - TagLib::AudioProperties *properties = f.audioProperties(); - if (properties) { - int lengthSeconds = properties->length(); - int bitrate = properties->bitrate(); - int sampleRate = properties->sampleRate(); - int channels = properties->channels(); - - if (s_bDebugMetadata) - qDebug() << "TagLib" << "length" << lengthSeconds << "bitrate" << bitrate << "sampleRate" << sampleRate << "channels" << channels; - - setDuration(lengthSeconds); - setBitrate(bitrate); - setSampleRate(sampleRate); - setChannels(channels); - } - - // If we didn't get any audio properties, this was a failure. - return (properties!=NULL); - } - return false; -} - -void SoundSource::parseReplayGainString (QString sReplayGain) { - QString ReplayGainstring = sReplayGain.remove( " dB" ); - float fReplayGain = db2ratio(ReplayGainstring.toFloat()); - // I found some mp3s of mine with replaygain tag set to 0dB even if not normalized. - // This is because of Rapid Evolution 3, I suppose. I prefer to rescan them by setting value to 0 (i.e. rescan via analyserrg) - if (fReplayGain == 1.0f) { - fReplayGain = 0.0f; - } - setReplayGain(fReplayGain); -} - -void SoundSource::processBpmString(QString tagName, QString sBpm) { - if (s_bDebugMetadata) - qDebug() << tagName << "BPM" << sBpm; - if (sBpm.length() > 0) { - float fBpm = str2bpm(sBpm); - if (fBpm > 0) - setBPM(fBpm); - } -} - -bool SoundSource::processID3v2Tag(TagLib::ID3v2::Tag* id3v2) { - - // Print every frame in the file. - if (s_bDebugMetadata) { - TagLib::ID3v2::FrameList::ConstIterator it = id3v2->frameList().begin(); - for(; it != id3v2->frameList().end(); it++) { - qDebug() << "ID3V2" << (*it)->frameID().data() << "-" - << toQString((*it)->toString()); - } - } - - TagLib::ID3v2::FrameList bpmFrame = id3v2->frameListMap()["TBPM"]; - if (!bpmFrame.isEmpty()) { - QString sBpm = toQString(bpmFrame.front()->toString()); - processBpmString("ID3v2", sBpm); - } - - TagLib::ID3v2::FrameList keyFrame = id3v2->frameListMap()["TKEY"]; - if (!keyFrame.isEmpty()) { - QString sKey = toQString(keyFrame.front()->toString()); - setKey(sKey); - } - // Foobar2000-style ID3v2.3.0 tags - // TODO: Check if everything is ok. - TagLib::ID3v2::FrameList frames = id3v2->frameListMap()["TXXX"]; - for ( TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it ) { - TagLib::ID3v2::UserTextIdentificationFrame* ReplayGainframe = - dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>( *it ); - if ( ReplayGainframe && ReplayGainframe->fieldList().size() >= 2 ) - { - QString desc = toQString( ReplayGainframe->description() ).toLower(); - if ( desc == "replaygain_album_gain" ){ - QString sReplayGain = toQString( ReplayGainframe->fieldList()[1]); |