# HG changeset patch # User Chris Cannam # Date 1183384418 0 # Node ID 822bd7fd526c0b7237a8b82de30cb83c05ba46f0 # Parent 840dd5e6400fc47d487a4b1bb782da154a555e1b * Add support for reading mp3 and Ogg file title tags diff -r 840dd5e6400f -r 822bd7fd526c data/data.pro --- a/data/data.pro Tue Jun 26 12:27:47 2007 +0000 +++ b/data/data.pro Mon Jul 02 13:53:38 2007 +0000 @@ -1,6 +1,6 @@ TEMPLATE = lib -SV_UNIT_PACKAGES = fftw3f sndfile mad oggz fishsound +SV_UNIT_PACKAGES = fftw3f sndfile mad id3tag oggz fishsound load(../sv.prf) CONFIG += sv staticlib qt thread warn_on stl rtti exceptions diff -r 840dd5e6400f -r 822bd7fd526c data/fileio/AudioFileReader.h --- a/data/fileio/AudioFileReader.h Tue Jun 26 12:27:47 2007 +0000 +++ b/data/fileio/AudioFileReader.h Mon Jul 02 13:53:38 2007 +0000 @@ -34,6 +34,13 @@ size_t getChannelCount() const { return m_channelCount; } size_t getSampleRate() const { return m_sampleRate; } + /** + * Return the title of the work in the audio file, if known. This + * may be implemented by subclasses that support file tagging. + * This is not the same thing as the file name. + */ + virtual QString getTitle() const { return ""; } + /** * The subclass implementations of this function must be * thread-safe -- that is, safe to call from multiple threads with diff -r 840dd5e6400f -r 822bd7fd526c data/fileio/MP3FileReader.cpp --- a/data/fileio/MP3FileReader.cpp Tue Jun 26 12:27:47 2007 +0000 +++ b/data/fileio/MP3FileReader.cpp Mon Jul 02 13:53:38 2007 +0000 @@ -25,6 +25,10 @@ #include +#ifdef HAVE_ID3TAG +#include +#endif + #include #include #include @@ -95,6 +99,8 @@ ::close(fd); + loadTags(); + if (decodeMode == DecodeAtOnce) { m_progress = new QProgressDialog @@ -135,6 +141,43 @@ } void +MP3FileReader::loadTags() +{ + m_title = ""; + +#ifdef HAVE_ID3TAG + + id3_file *file = id3_file_open(m_path.toLocal8Bit().data(), + ID3_FILE_MODE_READONLY); + if (!file) return; + + id3_tag *tag = id3_file_tag(file); + + if (tag) { + id3_frame *frame = id3_tag_findframe(tag, "TIT2", 0); // work title + + if (frame && frame->nfields >= 2) { + unsigned int nstrings = id3_field_getnstrings(&frame->fields[1]); + + if (nstrings > 0) { + id3_ucs4_t const *ustr = id3_field_getstrings(&frame->fields[1], 0); + + if (ustr) { + id3_utf8_t *u8str = id3_ucs4_utf8duplicate(ustr); + if (u8str) { + m_title = QString::fromUtf8((const char *)u8str); + free(u8str); + } + } + } + } + } + + id3_file_close(file); +#endif +} + +void MP3FileReader::DecodeThread::run() { if (!m_reader->decode(m_reader->m_filebuffer, m_reader->m_fileSize)) { diff -r 840dd5e6400f -r 822bd7fd526c data/fileio/MP3FileReader.h --- a/data/fileio/MP3FileReader.h Tue Jun 26 12:27:47 2007 +0000 +++ b/data/fileio/MP3FileReader.h Mon Jul 02 13:53:38 2007 +0000 @@ -40,6 +40,8 @@ virtual QString getError() const { return m_error; } + virtual QString getTitle() const { return m_title; } + static void getSupportedExtensions(std::set &extensions); virtual int getDecodeCompletion() const { return m_completion; } @@ -51,6 +53,7 @@ protected: QString m_path; QString m_error; + QString m_title; size_t m_fileSize; double m_bitrateNum; size_t m_bitrateDenom; @@ -87,6 +90,8 @@ }; DecodeThread *m_decodeThread; + + void loadTags(); }; #endif diff -r 840dd5e6400f -r 822bd7fd526c data/fileio/OggVorbisFileReader.cpp --- a/data/fileio/OggVorbisFileReader.cpp Tue Jun 26 12:27:47 2007 +0000 +++ b/data/fileio/OggVorbisFileReader.cpp Mon Jul 02 13:53:38 2007 +0000 @@ -40,6 +40,7 @@ m_progress(0), m_fileSize(0), m_bytesRead(0), + m_commentsRead(false), m_cancelled(false), m_completion(0), m_decodeThread(0) @@ -163,6 +164,15 @@ { OggVorbisFileReader *reader = (OggVorbisFileReader *)data; + if (!reader->m_commentsRead) { + const FishSoundComment *comment = fish_sound_comment_first_byname + (fs, "TITLE"); + if (comment && comment->value) { + reader->m_title = QString::fromUtf8(comment->value); + } + reader->m_commentsRead = true; + } + if (reader->m_channelCount == 0) { FishSoundInfo fsinfo; fish_sound_command(fs, FISH_SOUND_GET_INFO, diff -r 840dd5e6400f -r 822bd7fd526c data/fileio/OggVorbisFileReader.h --- a/data/fileio/OggVorbisFileReader.h Tue Jun 26 12:27:47 2007 +0000 +++ b/data/fileio/OggVorbisFileReader.h Mon Jul 02 13:53:38 2007 +0000 @@ -43,6 +43,8 @@ virtual QString getError() const { return m_error; } + virtual QString getTitle() const { return m_title; } + static void getSupportedExtensions(std::set &extensions); virtual int getDecodeCompletion() const { return m_completion; } @@ -54,12 +56,14 @@ protected: QString m_path; QString m_error; + QString m_title; OGGZ *m_oggz; FishSound *m_fishSound; QProgressDialog *m_progress; size_t m_fileSize; size_t m_bytesRead; + bool m_commentsRead; bool m_cancelled; int m_completion; diff -r 840dd5e6400f -r 822bd7fd526c data/model/WaveFileModel.cpp --- a/data/model/WaveFileModel.cpp Tue Jun 26 12:27:47 2007 +0000 +++ b/data/model/WaveFileModel.cpp Mon Jul 02 13:53:38 2007 +0000 @@ -47,7 +47,8 @@ m_exiting(false) { m_reader = AudioFileReaderFactory::createReader(path); - setObjectName(QFileInfo(path).fileName()); + setObjectName(m_reader->getTitle()); + if (objectName() == "") setObjectName(QFileInfo(path).fileName()); if (isOK()) fillCache(); } @@ -60,7 +61,8 @@ m_exiting(false) { m_reader = AudioFileReaderFactory::createReader(path); - setObjectName(QFileInfo(originalLocation).fileName()); + setObjectName(m_reader->getTitle()); + if (objectName() == "") setObjectName(QFileInfo(originalLocation).fileName()); if (isOK()) fillCache(); } @@ -73,7 +75,8 @@ m_exiting(false) { m_reader = reader; - setObjectName(QFileInfo(path).fileName()); + setObjectName(m_reader->getTitle()); + if (objectName() == "") setObjectName(QFileInfo(path).fileName()); fillCache(); }