changeset 333:1afaf98dbf11

* Factor out uses of "Sonic Visualiser" in "common" code to applicationName() * Add ability to show work title + artist in top-left of pane (thinking of Vect but may be useful in SV in future) * A few other generalisations useful for Vect
author Chris Cannam
date Fri, 09 Nov 2007 17:46:58 +0000
parents 13e5870040e6
children aa8dbac62024
files data/fileio/AudioFileReader.h data/fileio/MP3FileReader.cpp data/fileio/MP3FileReader.h data/fileio/OggVorbisFileReader.cpp data/fileio/OggVorbisFileReader.h data/fileio/QuickTimeFileReader.cpp data/model/AlignmentModel.cpp data/model/EditableDenseThreeDimensionalModel.cpp data/model/EditableDenseThreeDimensionalModel.h data/model/Model.cpp data/model/Model.h data/model/SparseModel.h data/model/WaveFileModel.cpp data/model/WaveFileModel.h plugin/transform/FeatureExtractionModelTransformer.cpp plugin/transform/PluginTransformer.cpp plugin/transform/PluginTransformer.h plugin/transform/TransformFactory.cpp
diffstat 18 files changed, 166 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/data/fileio/AudioFileReader.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/fileio/AudioFileReader.h	Fri Nov 09 17:46:58 2007 +0000
@@ -47,6 +47,13 @@
      */
     virtual QString getTitle() const { return ""; }
 
+    /**
+     * Return the "maker" of the work in the audio file, if known.
+     * This could represent almost anything (band, composer,
+     * conductor, artist etc).
+     */
+    virtual QString getMaker() const { return ""; }
+
     /** 
      * Return interleaved samples for count frames from index start.
      * The resulting sample block will contain count *
--- a/data/fileio/MP3FileReader.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/fileio/MP3FileReader.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -168,48 +168,12 @@
         return;
     }
 
-    id3_frame *frame = id3_tag_findframe(tag, "TIT2", 0); // work title
-    if (!frame) {
-#ifdef DEBUG_ID3TAG
-        std::cerr << "MP3FileReader::loadTags: No work title in ID3 tag" << std::endl;
-#endif
-        id3_file_close(file);
-        return;
-    }
-        
-    if (frame->nfields < 2) {
-        std::cerr << "MP3FileReader::loadTags: WARNING: Not enough fields (" << frame->nfields << ") for work title in ID3 tag" << std::endl;
-        id3_file_close(file);
-        return;
-    }
+    m_title = loadTag(tag, "TIT2"); // work title
+    if (m_title == "") m_title = loadTag(tag, "TIT1");
 
-    unsigned int nstrings = id3_field_getnstrings(&frame->fields[1]);
-    if (nstrings == 0) {
-#ifdef DEBUG_ID3TAG
-        std::cerr << "MP3FileReader::loadTags: No data for work title in ID3 tag" << std::endl;
-#endif
-        id3_file_close(file);
-        return;
-    }
+    m_maker = loadTag(tag, "TPE1"); // "lead artist"
+    if (m_maker == "") m_maker = loadTag(tag, "TPE2");
 
-    id3_ucs4_t const *ustr = id3_field_getstrings(&frame->fields[1], 0);
-    if (!ustr) {
-#ifdef DEBUG_ID3TAG
-        std::cerr << "MP3FileReader::loadTags: Invalid or absent data for work title in ID3 tag" << std::endl;
-#endif
-        id3_file_close(file);
-        return;
-    }
-        
-    id3_utf8_t *u8str = id3_ucs4_utf8duplicate(ustr);
-    if (!u8str) {
-        std::cerr << "MP3FileReader::loadTags: ERROR: Internal error: Failed to convert UCS4 to UTF8 in ID3 title" << std::endl;
-        id3_file_close(file);
-        return;
-    }
-        
-    m_title = QString::fromUtf8((const char *)u8str);
-    free(u8str);
     id3_file_close(file);
 
 #else
@@ -218,7 +182,56 @@
               << std::endl;
 #endif
 #endif
+}
 
+QString
+MP3FileReader::loadTag(void *vtag, const char *name)
+{
+#ifdef HAVE_ID3TAG
+    id3_tag *tag = (id3_tag *)vtag;
+
+    id3_frame *frame = id3_tag_findframe(tag, name, 0);
+    if (!frame) {
+#ifdef DEBUG_ID3TAG
+        std::cerr << "MP3FileReader::loadTags: No \"" << name << "\" in ID3 tag" << std::endl;
+#endif
+        return "";
+    }
+        
+    if (frame->nfields < 2) {
+        std::cerr << "MP3FileReader::loadTags: WARNING: Not enough fields (" << frame->nfields << ") for \"" << name << "\" in ID3 tag" << std::endl;
+        return "";
+    }
+
+    unsigned int nstrings = id3_field_getnstrings(&frame->fields[1]);
+    if (nstrings == 0) {
+#ifdef DEBUG_ID3TAG
+        std::cerr << "MP3FileReader::loadTags: No data for \"" << name << "\" in ID3 tag" << std::endl;
+#endif
+        return "";
+    }
+
+    id3_ucs4_t const *ustr = id3_field_getstrings(&frame->fields[1], 0);
+    if (!ustr) {
+#ifdef DEBUG_ID3TAG
+        std::cerr << "MP3FileReader::loadTags: Invalid or absent data for \"" << name << "\" in ID3 tag" << std::endl;
+#endif
+        return "";
+    }
+        
+    id3_utf8_t *u8str = id3_ucs4_utf8duplicate(ustr);
+    if (!u8str) {
+        std::cerr << "MP3FileReader::loadTags: ERROR: Internal error: Failed to convert UCS4 to UTF8 in ID3 title" << std::endl;
+        return "";
+    }
+        
+    QString rv = QString::fromUtf8((const char *)u8str);
+    free(u8str);
+    return rv;
+
+#else
+    return "";
+#endif
 }
 
 void
--- a/data/fileio/MP3FileReader.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/fileio/MP3FileReader.h	Fri Nov 09 17:46:58 2007 +0000
@@ -61,6 +61,7 @@
     QString m_path;
     QString m_error;
     QString m_title;
+    QString m_maker;
     size_t m_fileSize;
     double m_bitrateNum;
     size_t m_bitrateDenom;
@@ -101,6 +102,7 @@
     DecodeThread *m_decodeThread;
 
     void loadTags();
+    QString loadTag(void *vtag, const char *name);
 };
 
 #endif
--- a/data/fileio/OggVorbisFileReader.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/fileio/OggVorbisFileReader.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -173,10 +173,19 @@
     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);
+        {
+            const FishSoundComment *comment = fish_sound_comment_first_byname
+                (fs, "TITLE");
+            if (comment && comment->value) {
+                reader->m_title = QString::fromUtf8(comment->value);
+            }
+        }
+        {
+            const FishSoundComment *comment = fish_sound_comment_first_byname
+                (fs, "ARTIST");
+            if (comment && comment->value) {
+                reader->m_maker = QString::fromUtf8(comment->value);
+            }
         }
         reader->m_commentsRead = true;
     }
--- a/data/fileio/OggVorbisFileReader.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/fileio/OggVorbisFileReader.h	Fri Nov 09 17:46:58 2007 +0000
@@ -46,6 +46,7 @@
     virtual QString getError() const { return m_error; }
 
     virtual QString getTitle() const { return m_title; }
+    virtual QString getMaker() const { return m_maker; }
     
     static void getSupportedExtensions(std::set<QString> &extensions);
     static bool supportsExtension(QString ext);
@@ -63,6 +64,7 @@
     QString m_path;
     QString m_error;
     QString m_title;
+    QString m_maker;
 
     OGGZ *m_oggz;
     FishSound *m_fishSound;
--- a/data/fileio/QuickTimeFileReader.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/fileio/QuickTimeFileReader.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -26,7 +26,7 @@
 #include <QFileInfo>
 #include <QProgressDialog>
 
-#ifdef WIN32
+#ifdef _WIN32
 #include <QTML.h>
 #include <Movies.h>
 #else
--- a/data/model/AlignmentModel.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/AlignmentModel.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -150,8 +150,8 @@
     if (!m_pathComplete) {
         int completion = 0;
         m_path->isReady(&completion);
-        std::cerr << "AlignmentModel::pathCompletionChanged: completion = "
-                  << completion << std::endl;
+//        std::cerr << "AlignmentModel::pathCompletionChanged: completion = "
+//                  << completion << std::endl;
         m_pathComplete = (completion == 100);
         if (m_pathComplete) {
             constructReversePath();
--- a/data/model/EditableDenseThreeDimensionalModel.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/EditableDenseThreeDimensionalModel.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -244,7 +244,7 @@
 }
 
 void
-EditableDenseThreeDimensionalModel::setCompletion(int completion)
+EditableDenseThreeDimensionalModel::setCompletion(int completion, bool update)
 {
     if (m_completion != completion) {
 	m_completion = completion;
@@ -256,7 +256,8 @@
 
 	} else if (!m_notifyOnAdd) {
 
-	    if (m_sinceLastNotifyMin >= 0 &&
+	    if (update &&
+                m_sinceLastNotifyMin >= 0 &&
 		m_sinceLastNotifyMax >= 0) {
 		emit modelChanged(m_sinceLastNotifyMin,
 				  m_sinceLastNotifyMax + m_resolution);
--- a/data/model/EditableDenseThreeDimensionalModel.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/EditableDenseThreeDimensionalModel.h	Fri Nov 09 17:46:58 2007 +0000
@@ -106,7 +106,7 @@
     virtual void setBinName(size_t n, QString);
     virtual void setBinNames(std::vector<QString> names);
 
-    virtual void setCompletion(int completion);
+    virtual void setCompletion(int completion, bool update = true);
     virtual int getCompletion() const { return m_completion; }
 
     virtual QString toDelimitedDataString(QString delimiter) const;
--- a/data/model/Model.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/Model.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -56,6 +56,8 @@
     m_sourceModel = model;
 
     if (m_sourceModel) {
+        connect(m_sourceModel, SIGNAL(alignmentCompletionChanged()),
+                this, SIGNAL(alignmentCompletionChanged()));
         connect(m_sourceModel, SIGNAL(aboutToBeDeleted()),
                 this, SLOT(sourceModelAboutToBeDeleted()));
     }
@@ -96,35 +98,64 @@
 const Model *
 Model::getAlignmentReference() const
 {
-    if (!m_alignment) return this;
+    if (!m_alignment) {
+        if (m_sourceModel) return m_sourceModel->getAlignmentReference();
+        return this;
+    }
     return m_alignment->getReferenceModel();
 }
 
 size_t
 Model::alignToReference(size_t frame) const
 {
-    if (!m_alignment) return frame;
-    return m_alignment->toReference(frame);
+    if (!m_alignment) {
+        if (m_sourceModel) return m_sourceModel->alignToReference(frame);
+        else return frame;
+    }
+    size_t refFrame = m_alignment->toReference(frame);
+    //!!! this should be totally wrong, but because alignToReference and
+    // alignFromReference are the wrong way around, it's right... *sigh*
+    if (refFrame > getEndFrame()) refFrame = getEndFrame();
+    return refFrame;
 }
 
 size_t
 Model::alignFromReference(size_t refFrame) const
 {
-    if (!m_alignment) return refFrame;
-    return m_alignment->fromReference(refFrame);
+    if (!m_alignment) {
+        if (m_sourceModel) return m_sourceModel->alignFromReference(refFrame);
+        else return refFrame;
+    }
+    size_t frame = m_alignment->fromReference(refFrame);
+    return frame;
 }
 
 int
 Model::getAlignmentCompletion() const
 {
 //    std::cerr << "Model::getAlignmentCompletion" << std::endl;
-    if (!m_alignment) return 100;
+    if (!m_alignment) {
+        if (m_sourceModel) return m_sourceModel->getAlignmentCompletion();
+        else return 100;
+    }
     int completion = 0;
     (void)m_alignment->isReady(&completion);
 //    std::cerr << " -> " << completion << std::endl;
     return completion;
 }
 
+QString
+Model::getTitle() const
+{
+    if (m_sourceModel) return m_sourceModel->getTitle();
+}
+
+QString
+Model::getMaker() const
+{
+    if (m_sourceModel) return m_sourceModel->getMaker();
+}
+
 void
 Model::toXml(QTextStream &stream, QString indent,
              QString extraAttributes) const
--- a/data/model/Model.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/Model.h	Fri Nov 09 17:46:58 2007 +0000
@@ -67,6 +67,16 @@
     virtual size_t getNativeRate() const { return getSampleRate(); }
 
     /**
+     * Return the "work title" of the model, if known.
+     */
+    virtual QString getTitle() const;
+
+    /**
+     * Return the "artist" or "maker" of the model, if known.
+     */
+    virtual QString getMaker() const;
+
+    /**
      * Return a copy of this model.
      *
      * If the model is not editable, this may be effectively a shallow
--- a/data/model/SparseModel.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/SparseModel.h	Fri Nov 09 17:46:58 2007 +0000
@@ -127,7 +127,7 @@
         return ready;
     }
 
-    virtual void setCompletion(int completion);
+    virtual void setCompletion(int completion, bool update = true);
     virtual int getCompletion() const { return m_completion; }
 
     virtual bool hasTextLabels() const { return m_hasTextLabels; }
@@ -511,7 +511,7 @@
 
 template <typename PointType>
 void
-SparseModel<PointType>::setCompletion(int completion)
+SparseModel<PointType>::setCompletion(int completion, bool update)
 {
 //    std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl;
 
@@ -529,7 +529,8 @@
 
 	} else if (!m_notifyOnAdd) {
 
-	    if (m_sinceLastNotifyMin >= 0 &&
+	    if (update &&
+                m_sinceLastNotifyMin >= 0 &&
 		m_sinceLastNotifyMax >= 0) {
 		emit modelChanged(m_sinceLastNotifyMin, m_sinceLastNotifyMax);
 		m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
--- a/data/model/WaveFileModel.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/WaveFileModel.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -158,6 +158,22 @@
     return rate;
 }
 
+QString
+WaveFileModel::getTitle() const
+{
+    QString title;
+    if (m_reader) title = m_reader->getTitle();
+    if (title == "") title = objectName();
+    return title;
+}
+
+QString
+WaveFileModel::getMaker() const
+{
+    if (m_reader) return m_reader->getMaker();
+    return "";
+}
+    
 size_t
 WaveFileModel::getData(int channel, size_t start, size_t count,
                        float *buffer) const
--- a/data/model/WaveFileModel.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/data/model/WaveFileModel.h	Fri Nov 09 17:46:58 2007 +0000
@@ -48,6 +48,9 @@
     size_t getSampleRate() const;
     size_t getNativeRate() const;
 
+    QString getTitle() const;
+    QString getMaker() const;
+
     virtual Model *clone() const;
 
     float getValueMinimum() const { return -1.0f; }
--- a/plugin/transform/FeatureExtractionModelTransformer.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/plugin/transform/FeatureExtractionModelTransformer.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -216,6 +216,8 @@
         
         m_output = model;
     }
+
+    if (m_output) m_output->setSourceModel(m_input);
 }
 
 FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer()
@@ -527,27 +529,27 @@
 
 	SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
 	if (!model) return;
-	model->setCompletion(completion);
+	model->setCompletion(completion, m_context.updates);
 
     } else if (binCount == 1) {
 
 	SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
 	if (!model) return;
-	model->setCompletion(completion);
+	model->setCompletion(completion, m_context.updates);
 
     } else if (m_descriptor->sampleType ==
 	       Vamp::Plugin::OutputDescriptor::VariableSampleRate) {
 
 	NoteModel *model = getOutput<NoteModel>();
 	if (!model) return;
-	model->setCompletion(completion);
+	model->setCompletion(completion, m_context.updates);
 
     } else {
 
 	EditableDenseThreeDimensionalModel *model =
             getOutput<EditableDenseThreeDimensionalModel>();
 	if (!model) return;
-	model->setCompletion(completion);
+	model->setCompletion(completion, m_context.updates);
     }
 }
 
--- a/plugin/transform/PluginTransformer.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/plugin/transform/PluginTransformer.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -33,7 +33,8 @@
     windowType(HanningWindow),
     startFrame(0),
     duration(0),
-    sampleRate(0)
+    sampleRate(0),
+    updates(true)
 {
 }
 
@@ -46,7 +47,8 @@
     windowType(_wt),
     startFrame(0),
     duration(0),
-    sampleRate(0)
+    sampleRate(0),
+    updates(true)
 {
 }
 
--- a/plugin/transform/PluginTransformer.h	Wed Nov 07 14:53:12 2007 +0000
+++ b/plugin/transform/PluginTransformer.h	Fri Nov 09 17:46:58 2007 +0000
@@ -51,6 +51,7 @@
         size_t startFrame;
         size_t duration;    // 0 -> whole thing
         float sampleRate;   // 0 -> model's rate
+        bool updates;
     };
 
 protected:
--- a/plugin/transform/TransformFactory.cpp	Wed Nov 07 14:53:12 2007 +0000
+++ b/plugin/transform/TransformFactory.cpp	Fri Nov 09 17:46:58 2007 +0000
@@ -426,6 +426,7 @@
 bool
 TransformFactory::haveTransform(TransformId identifier)
 {
+    if (m_transforms.empty()) populateTransforms();
     return (m_transforms.find(identifier) != m_transforms.end());
 }