changeset 158:d6cdbd814c8c structure

Merge from refactors branch
author Chris Cannam
date Thu, 29 Jan 2015 13:29:48 +0000
parents 2b61e0cb6847 (current diff) d6c1556fadd0 (diff)
children 28c73e5db2eb
files src/MatchVampPlugin.cpp
diffstat 3 files changed, 77 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/DistanceMetric.cpp	Fri Jan 23 17:33:37 2015 +0000
+++ b/src/DistanceMetric.cpp	Thu Jan 29 13:29:48 2015 +0000
@@ -39,13 +39,44 @@
 {
     double d = 0;
     double sum = 0;
+    double eps = 1e-16;
 
     int featureSize = f1.size();
     assert(int(f2.size()) == featureSize);
 
-    for (int i = 0; i < featureSize; i++) {
-        d += fabs(f1[i] - f2[i]);
-        sum += fabs(f1[i]) + fabs(f2[i]);
+    if (m_params.metric == Cosine) {
+
+        double num = 0, denom1 = 0, denom2 = 0;
+        
+        for (int i = 0; i < featureSize; ++i) {
+            num += f1[i] * f2[i];
+            denom1 += f1[i] * f1[i];
+            denom2 += f2[i] * f2[i];
+        }
+
+        d = 1.0 - (num / (eps + sqrt(denom1 * denom2)));
+
+        if (m_params.noise == AddNoise) {
+            d += 1e-2;
+        }
+        if (d > 1.0) d = 1.0;
+        
+        return d; // normalisation param ignored
+
+    }
+
+    if (m_params.metric == Manhattan) {
+        for (int i = 0; i < featureSize; i++) {
+            d += fabs(f1[i] - f2[i]);
+            sum += fabs(f1[i]) + fabs(f2[i]);
+        }
+    } else {
+        // Euclidean
+        for (int i = 0; i < featureSize; i++) {
+            d += (f1[i] - f2[i]) * (f1[i] - f2[i]);
+            sum += fabs(f1[i]) + fabs(f2[i]);
+        }
+        d = sqrt(d);
     }
 
     double noise = 1e-3 * featureSize;
--- a/src/DistanceMetric.h	Fri Jan 23 17:33:37 2015 +0000
+++ b/src/DistanceMetric.h	Thu Jan 29 13:29:48 2015 +0000
@@ -22,6 +22,23 @@
 class DistanceMetric
 {
 public:
+    enum Metric {
+
+        /** Calculate the Manhattan distance between feature
+         *  vectors. If the vectors contain energy, as the default
+         *  MATCH feature does, this could be considered as a squared
+         *  Euclidean distance metric. */
+        Manhattan,
+
+        /** Calculate the Euclidean distance between feature vectors. */
+        Euclidean,
+
+        /** Calculate the cosine distance between feature vectors. The
+         *  normalisation setting will be ignored as the result is
+         *  already magnitude-independent. */
+        Cosine,
+    };
+
     enum DistanceNormalisation {
             
         /** Do not normalise distance metrics */
@@ -35,7 +52,7 @@
          *  of the sum of the frames. */
         NormaliseDistanceToLogSum,
     };
-
+    
     enum NoiseAddition {
 
         /** Don't add noise. */
@@ -49,22 +66,22 @@
     struct Parameters {
 
         Parameters() :
+            metric(Manhattan),
             norm(NormaliseDistanceToLogSum),
             noise(AddNoise)
         {}
 
-        /** Normalisation for distance metrics. */
+        Metric metric;
         DistanceNormalisation norm;
         NoiseAddition noise;
     };
     
     DistanceMetric(Parameters params);
     
-    /** Calculates the Manhattan distance between two vectors, with an
-     *  optional normalisation by the combined values in the
-     *  vectors. Since the vectors contain energy, this could be
-     *  considered as a squared Euclidean distance metric. Note that
-     *  normalisation assumes the values are all non-negative.
+    /** Calculates the distance in some metric between two vectors,
+     *  with an optional normalisation by the combined values in the
+     *  vectors. Note that normalisation assumes the values are all
+     *  non-negative.
      *
      *  @param f1 one of the vectors involved in the distance calculation
      *  @param f2 one of the vectors involved in the distance calculation
--- a/src/MatchVampPlugin.cpp	Fri Jan 23 17:33:37 2015 +0000
+++ b/src/MatchVampPlugin.cpp	Thu Jan 29 13:29:48 2015 +0000
@@ -215,6 +215,21 @@
     desc.isQuantized = false;
     list.push_back(desc);
 
+    desc.identifier = "metric";
+    desc.name = "Distance metric";
+    desc.description = "Metric for distance calculations.";
+    desc.minValue = 0;
+    desc.maxValue = 2;
+    desc.defaultValue = (int)m_defaultDParams.metric;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    desc.valueNames.clear();
+    desc.valueNames.push_back("Manhattan");
+    desc.valueNames.push_back("Euclidean");
+    desc.valueNames.push_back("Cosine");
+    list.push_back(desc);
+    desc.valueNames.clear();
+
     desc.identifier = "noise";
     desc.name = "Mix in Noise";
     desc.description = "Whether to mix in a small constant white noise term when calculating feature distance. This can improve alignment against sources containing cleanly synthesised audio.";
@@ -293,6 +308,8 @@
         return m_smooth ? 1.0 : 0.0;
     } else if (name == "silencethreshold") {
         return (float)m_fcParams.silenceThreshold;
+    } else if (name == "metric") {
+        return (int)m_dParams.metric;
     } else if (name == "noise") {
         return m_dParams.noise;
     }
@@ -323,6 +340,8 @@
         m_smooth = (value > 0.5);
     } else if (name == "silencethreshold") {
         m_fcParams.silenceThreshold = value;
+    } else if (name == "metric") {
+        m_dParams.metric = (DistanceMetric::Metric)(int(value + 0.1));
     } else if (name == "noise") {
         m_dParams.noise = (DistanceMetric::NoiseAddition)(int(value + 0.1));
     }