changeset 271:822bd7fd526c

* Add support for reading mp3 and Ogg file title tags
author Chris Cannam
date Mon, 02 Jul 2007 13:53:38 +0000
parents 840dd5e6400f
children 8bbc9e336475
files data/data.pro data/fileio/AudioFileReader.h data/fileio/MP3FileReader.cpp data/fileio/MP3FileReader.h data/fileio/OggVorbisFileReader.cpp data/fileio/OggVorbisFileReader.h data/model/WaveFileModel.cpp
diffstat 7 files changed, 76 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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
--- 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 <iostream>
 
+#ifdef HAVE_ID3TAG
+#include <id3tag.h>
+#endif
+
 #include <QApplication>
 #include <QFileInfo>
 #include <QProgressDialog>
@@ -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)) {
--- 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<QString> &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
--- 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,
--- 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<QString> &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;
  
--- 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();
 }