diff align/Align.cpp @ 767:dd742e566e60 pitch-align

Make a start on further alignment methods
author Chris Cannam
date Thu, 21 May 2020 16:21:57 +0100
parents 6429a164b7e1
children 1b1960009be6
line wrap: on
line diff
--- a/align/Align.cpp	Wed May 06 11:45:27 2020 +0100
+++ b/align/Align.cpp	Thu May 21 16:21:57 2020 +0100
@@ -13,20 +13,65 @@
 */
 
 #include "Align.h"
+
+#include "LinearAligner.h"
 #include "TransformAligner.h"
+#include "TransformDTWAligner.h"
 #include "ExternalProgramAligner.h"
+
 #include "framework/Document.h"
 
+#include "transform/Transform.h"
+#include "transform/TransformFactory.h"
+
 #include <QSettings>
 #include <QTimer>
 
+using std::make_shared;
+
+QString
+Align::getAlignmentTypeTag(AlignmentType type)
+{
+    switch (type) {
+    case NoAlignment:
+    default:
+        return "no-alignment";
+    case LinearAlignment:
+        return "linear-alignment";
+    case TrimmedLinearAlignment:
+        return "trimmed-linear-alignment";
+    case MATCHAlignment:
+        return "match-alignment";
+    case MATCHAlignmentWithPitchCompare:
+        return "match-alignment-with-pitch";
+    case SungPitchContourAlignment:
+        return "sung-pitch-alignment";
+    case TransformDrivenDTWAlignment:
+        return "transform-driven-alignment";
+    case ExternalProgramAlignment:
+        return "external-program-alignment";
+    }
+}
+
+Align::AlignmentType
+Align::getAlignmentTypeForTag(QString tag)
+{
+    for (int i = 0; i <= int(LastAlignmentType); ++i) {
+        if (tag == getAlignmentTypeTag(AlignmentType(i))) {
+            return AlignmentType(i);
+        }
+    }
+    return NoAlignment;
+}
+
 void
 Align::alignModel(Document *doc,
                   ModelId reference,
                   ModelId toAlign)
 {
-    addAligner(doc, reference, toAlign);
-    m_aligners[toAlign]->begin();
+    if (addAligner(doc, reference, toAlign)) {
+        m_aligners[toAlign]->begin();
+    }
 }
 
 void
@@ -34,23 +79,24 @@
                          ModelId reference,
                          ModelId toAlign)
 {
-    addAligner(doc, reference, toAlign);
-    int delay = 500 + 500 * int(m_aligners.size());
+    int delay = 700 * int(m_aligners.size());
     if (delay > 3500) {
         delay = 3500;
     }
+    if (!addAligner(doc, reference, toAlign)) {
+        return;
+    }
     SVCERR << "Align::scheduleAlignment: delaying " << delay << "ms" << endl;
     QTimer::singleShot(delay, m_aligners[toAlign].get(), SLOT(begin()));
 }
 
-void
+bool
 Align::addAligner(Document *doc,
                   ModelId reference,
                   ModelId toAlign)
 {
-    bool useProgram;
-    QString program;
-    getAlignerPreference(useProgram, program);
+    QString additionalData;
+    AlignmentType type = getAlignmentPreference(additionalData);
     
     std::shared_ptr<Aligner> aligner;
 
@@ -60,21 +106,67 @@
         // replaced and its aligner destroyed.
         
         QMutexLocker locker(&m_mutex);
-    
-        if (useProgram && (program != "")) {
-            m_aligners[toAlign] =
-                std::make_shared<ExternalProgramAligner>(doc,
-                                                         reference,
-                                                         toAlign,
-                                                         program);
-        } else {
-            m_aligners[toAlign] =
-                std::make_shared<TransformAligner>(doc,
-                                                   reference,
-                                                   toAlign);
+
+        switch (type) {
+
+        case NoAlignment:
+            return false;
+
+        case LinearAlignment:
+        case TrimmedLinearAlignment: {
+            bool trimmed = (type == TrimmedLinearAlignment);
+            aligner = make_shared<LinearAligner>(doc,
+                                                 reference,
+                                                 toAlign,
+                                                 trimmed);
+            break;
         }
 
-        aligner = m_aligners[toAlign];
+        case MATCHAlignment:
+        case MATCHAlignmentWithPitchCompare: {
+
+            bool withTuningDifference =
+                (type == MATCHAlignmentWithPitchCompare);
+            
+            aligner = make_shared<TransformAligner>(doc,
+                                                    reference,
+                                                    toAlign,
+                                                    withTuningDifference);
+            break;
+        }
+
+        case SungPitchContourAlignment:
+        {
+            auto refModel = ModelById::get(reference);
+            if (!refModel) return false;
+            
+            Transform transform = TransformFactory::getInstance()->
+                getDefaultTransformFor("vamp:pyin:pyin:smoothedpitchtrack",
+                                       refModel->getSampleRate());
+
+            transform.setParameter("outputunvoiced", 2.f);
+            
+            aligner = make_shared<TransformDTWAligner>
+                (doc,
+                 reference,
+                 toAlign,
+                 transform,
+                 TransformDTWAligner::RiseFall);
+            break;
+        }
+        
+        case TransformDrivenDTWAlignment:
+            throw std::logic_error("Not yet implemented"); //!!!
+
+        case ExternalProgramAlignment: {
+            aligner = make_shared<ExternalProgramAligner>(doc,
+                                                          reference,
+                                                          toAlign,
+                                                          additionalData);
+        }
+        }
+
+        m_aligners[toAlign] = aligner;
     }
 
     connect(aligner.get(), SIGNAL(complete(ModelId)),
@@ -82,27 +174,57 @@
 
     connect(aligner.get(), SIGNAL(failed(ModelId, QString)),
             this, SLOT(alignerFailed(ModelId, QString)));
+
+    return true;
+}
+
+Align::AlignmentType
+Align::getAlignmentPreference(QString &additionalData)
+{
+    QSettings settings;
+    settings.beginGroup("Alignment");
+
+    QString tag = settings.value
+        ("alignment-type", getAlignmentTypeTag(MATCHAlignment)).toString();
+
+    AlignmentType type = getAlignmentTypeForTag(tag);
+
+    if (type == TransformDrivenDTWAlignment) {
+        additionalData = settings.value("alignment-transform", "").toString();
+    } else if (type == ExternalProgramAlignment) {
+        additionalData = settings.value("alignment-program", "").toString();
+    }
+
+    settings.endGroup();
+    return type;
 }
 
 void
-Align::getAlignerPreference(bool &useProgram, QString &program)
+Align::setAlignmentPreference(AlignmentType type, QString additionalData)
 {
     QSettings settings;
-    settings.beginGroup("Preferences");
-    useProgram = settings.value("use-external-alignment", false).toBool();
-    program = settings.value("external-alignment-program", "").toString();
+    settings.beginGroup("Alignment");
+
+    QString tag = getAlignmentTypeTag(type);
+    settings.setValue("alignment-type", tag);
+
+    if (type == TransformDrivenDTWAlignment) {
+        settings.setValue("alignment-transform", additionalData);
+    } else if (type == ExternalProgramAlignment) {
+        settings.setValue("alignment-program", additionalData);
+    }
+
     settings.endGroup();
 }
 
 bool
 Align::canAlign() 
 {
-    bool useProgram;
-    QString program;
-    getAlignerPreference(useProgram, program);
+    QString additionalData;
+    AlignmentType type = getAlignmentPreference(additionalData);
 
-    if (useProgram) {
-        return ExternalProgramAligner::isAvailable(program);
+    if (type == ExternalProgramAlignment) {
+        return ExternalProgramAligner::isAvailable(additionalData);
     } else {
         return TransformAligner::isAvailable();
     }