changeset 173:eeed3498fe96 refactors

Merge from branch structure
author Chris Cannam
date Fri, 06 Feb 2015 18:41:35 +0000
parents d23dad16d6f9 (diff) 30d59e1e4232 (current diff)
children ef3c4b451c57
files src/Finder.cpp src/Finder.h src/MatchPipeline.cpp src/MatchPipeline.h src/MatchVampPlugin.cpp
diffstat 9 files changed, 421 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/match-vamp-plugin.n3	Fri Feb 06 18:09:18 2015 +0000
+++ b/match-vamp-plugin.n3	Fri Feb 06 18:41:35 2015 +0000
@@ -6,24 +6,26 @@
 @prefix dc:       <http://purl.org/dc/elements/1.1/> .
 @prefix af:       <http://purl.org/ontology/af/> .
 @prefix foaf:     <http://xmlns.com/foaf/0.1/> .
+@prefix doap:     <http://usefulinc.com/ns/doap#> .
 @prefix cc:       <http://web.resource.org/cc/> .
 @prefix :         <#> .
 
-<>  a   vamp:PluginDescription ;
-    foaf:maker          <http://www.vamp-plugins.org/doap.rdf#template-generator> ;
-    foaf:primaryTopic   <http://vamp-plugins.org/rdf/plugins/match-vamp-plugin> .
+<> a vamp:PluginDescription ;
+    foaf:maker         <http://vamp-plugins.org/rdf/template-generator> ;
+    foaf:primaryTopic  <http://vamp-plugins.org/rdf/plugins/match-vamp-plugin> .
 
-:maker
+:library_maker
     foaf:name "Simon Dixon and Chris Cannam" ;
     foaf:logo <http://vamp-plugins.org/rdf/plugins/makers/qm.png> ;
-    foaf:page <http://c4dm.eecs.qmul.ac.uk/> .
+    foaf:page <http://c4dm.eecs.qmul.ac.uk/> ;
+    .
 
 plugbase:library a  vamp:PluginLibrary ;
     vamp:identifier "match-vamp-plugin"  ; 
     dc:title "MATCH Vamp Plugin" ;
     dc:description """Vamp implementation of the MATCH audio alignment algorithm from Simon Dixon. Sonic Visualiser can use this for automatic time alignment among multiple audio files.""" ;
     vamp:available_plugin plugbase:match ; 
-    foaf:maker :maker ;
+    foaf:maker             :library_maker ; 
     foaf:page <http://code.soundsoftware.ac.uk/projects/match-vamp> ;
     .
 
@@ -31,15 +33,27 @@
     dc:title              "Match Performance Aligner" ;
     vamp:name             "Match Performance Aligner" ;
     dc:description        """Calculate alignment between two performances in separate channel inputs""" ;
-    foaf:maker            :maker ;
+    foaf:maker            :library_maker ;
     dc:rights             """GPL""" ;
 #   cc:license            <Place plugin license URI here and uncomment> ; 
     vamp:identifier       "match" ;
     vamp:vamp_API_version vamp:api_version_2 ;
-    owl:versionInfo       "1" ;
+    owl:versionInfo       "3" ;
     vamp:input_domain     vamp:FrequencyDomain ;
 
-
+    vamp:parameter   plugbase:match_param_freq1 ;
+    vamp:parameter   plugbase:match_param_freq2 ;
+    vamp:parameter   plugbase:match_param_usechroma ;
+    vamp:parameter   plugbase:match_param_usespecdiff ;
+    vamp:parameter   plugbase:match_param_framenorm ;
+    vamp:parameter   plugbase:match_param_metric ;
+    vamp:parameter   plugbase:match_param_distnorm ;
+    vamp:parameter   plugbase:match_param_silencethreshold ;
+    vamp:parameter   plugbase:match_param_noise ;
+    vamp:parameter   plugbase:match_param_gradientlimit ;
+    vamp:parameter   plugbase:match_param_zonewidth ;
+    vamp:parameter   plugbase:match_param_diagonalweight ;
+    vamp:parameter   plugbase:match_param_smooth ;
     vamp:parameter   plugbase:match_param_serialise ;
 
     vamp:output      plugbase:match_output_path ;
@@ -47,10 +61,155 @@
     vamp:output      plugbase:match_output_b_a ;
     vamp:output      plugbase:match_output_a_b_divergence ;
     vamp:output      plugbase:match_output_a_b_temporatio ;
+    vamp:output      plugbase:match_output_a_features ;
+    vamp:output      plugbase:match_output_b_features ;
+    vamp:output      plugbase:match_output_a_cfeatures ;
+    vamp:output      plugbase:match_output_b_cfeatures ;
+    vamp:output      plugbase:match_output_overall_cost ;
+    .
+
+plugbase:match_param_freq1 a  vamp:Parameter ;
+    vamp:identifier     "freq1" ;
+    dc:title            "Tuning frequency of first input" ;
+    dc:format           "Hz" ;
+    vamp:min_value       220 ;
+    vamp:max_value       880 ;
+    vamp:unit           "Hz"  ;
+    vamp:default_value   440 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_freq2 a  vamp:Parameter ;
+    vamp:identifier     "freq2" ;
+    dc:title            "Tuning frequency of second input" ;
+    dc:format           "Hz" ;
+    vamp:min_value       220 ;
+    vamp:max_value       880 ;
+    vamp:unit           "Hz"  ;
+    vamp:default_value   440 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_usechroma a  vamp:QuantizedParameter ;
+    vamp:identifier     "usechroma" ;
+    dc:title            "Feature type" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       1 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   0 ;
+    vamp:value_names     ( "Spectral" "Chroma");
+    .
+plugbase:match_param_usespecdiff a  vamp:QuantizedParameter ;
+    vamp:identifier     "usespecdiff" ;
+    dc:title            "Use feature difference" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       1 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   1 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_framenorm a  vamp:QuantizedParameter ;
+    vamp:identifier     "framenorm" ;
+    dc:title            "Frame normalisation" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       2 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   1 ;
+    vamp:value_names     ( "None" "Sum to 1" "Long-term average");
+    .
+plugbase:match_param_metric a  vamp:QuantizedParameter ;
+    vamp:identifier     "metric" ;
+    dc:title            "Distance metric" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       2 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   0 ;
+    vamp:value_names     ( "Manhattan" "Euclidean" "Cosine");
+    .
+plugbase:match_param_distnorm a  vamp:QuantizedParameter ;
+    vamp:identifier     "distnorm" ;
+    dc:title            "Distance normalisation" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       2 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   2 ;
+    vamp:value_names     ( "None" "Sum of frames" "Log sum of frames");
+    .
+plugbase:match_param_silencethreshold a  vamp:Parameter ;
+    vamp:identifier     "silencethreshold" ;
+    dc:title            "Silence threshold" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       0.1 ;
+    vamp:unit           ""  ;
+    vamp:default_value   0.01 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_noise a  vamp:QuantizedParameter ;
+    vamp:identifier     "noise" ;
+    dc:title            "Add noise" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       1 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   1 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_gradientlimit a  vamp:QuantizedParameter ;
+    vamp:identifier     "gradientlimit" ;
+    dc:title            "Gradient limit" ;
+    dc:format           "" ;
+    vamp:min_value       1 ;
+    vamp:max_value       10 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   3 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_zonewidth a  vamp:QuantizedParameter ;
+    vamp:identifier     "zonewidth" ;
+    dc:title            "Search zone width" ;
+    dc:format           "s" ;
+    vamp:min_value       1 ;
+    vamp:max_value       60 ;
+    vamp:unit           "s" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   10 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_diagonalweight a  vamp:Parameter ;
+    vamp:identifier     "diagonalweight" ;
+    dc:title            "Diagonal weight" ;
+    dc:format           "" ;
+    vamp:min_value       1 ;
+    vamp:max_value       2 ;
+    vamp:unit           ""  ;
+    vamp:default_value   2 ;
+    vamp:value_names     ();
+    .
+plugbase:match_param_smooth a  vamp:QuantizedParameter ;
+    vamp:identifier     "smooth" ;
+    dc:title            "Use path smoothing" ;
+    dc:format           "" ;
+    vamp:min_value       0 ;
+    vamp:max_value       1 ;
+    vamp:unit           "" ;
+    vamp:quantize_step   1  ;
+    vamp:default_value   0 ;
+    vamp:value_names     ();
     .
 plugbase:match_param_serialise a  vamp:QuantizedParameter ;
     vamp:identifier     "serialise" ;
-    dc:title            "Serialise Plugin Invocations" ;
+    dc:title            "Serialise plugin invocations" ;
     dc:format           "" ;
     vamp:min_value       0 ;
     vamp:max_value       1 ;
@@ -62,7 +221,7 @@
 plugbase:match_output_path a  vamp:SparseOutput ;
     vamp:identifier       "path" ;
     dc:title              "Path" ;
-    dc:description        "Alignment path"  ;
+    dc:description        """Alignment path"""  ;
     vamp:fixed_bin_count  "true" ;
     vamp:unit             "" ;
     a                     vamp:QuantizedOutput ;
@@ -77,7 +236,7 @@
 plugbase:match_output_a_b a  vamp:SparseOutput ;
     vamp:identifier       "a_b" ;
     dc:title              "A-B Timeline" ;
-    dc:description        "Timing in performance B corresponding to moments in performance A"  ;
+    dc:description        """Timing in performance B corresponding to moments in performance A"""  ;
     vamp:fixed_bin_count  "true" ;
     vamp:unit             "sec" ;
     vamp:bin_count        1 ;
@@ -90,7 +249,7 @@
 plugbase:match_output_b_a a  vamp:SparseOutput ;
     vamp:identifier       "b_a" ;
     dc:title              "B-A Timeline" ;
-    dc:description        "Timing in performance A corresponding to moments in performance B"  ;
+    dc:description        """Timing in performance A corresponding to moments in performance B"""  ;
     vamp:fixed_bin_count  "true" ;
     vamp:unit             "sec" ;
     vamp:bin_count        1 ;
@@ -103,7 +262,7 @@
 plugbase:match_output_a_b_divergence a  vamp:SparseOutput ;
     vamp:identifier       "a_b_divergence" ;
     dc:title              "A-B Divergence" ;
-    dc:description        "Difference between timings in performances A and B"  ;
+    dc:description        """Difference between timings in performances A and B"""  ;
     vamp:fixed_bin_count  "true" ;
     vamp:unit             "sec" ;
     vamp:bin_count        1 ;
@@ -116,7 +275,7 @@
 plugbase:match_output_a_b_temporatio a  vamp:SparseOutput ;
     vamp:identifier       "a_b_temporatio" ;
     dc:title              "A-B Tempo Ratio" ;
-    dc:description        "Ratio of tempi between performances A and B"  ;
+    dc:description        """Ratio of tempi between performances A and B"""  ;
     vamp:fixed_bin_count  "true" ;
     vamp:unit             "" ;
     vamp:bin_count        1 ;
@@ -126,4 +285,59 @@
 #   vamp:computes_feature      <Place feature attribute URI here and uncomment> ;
 #   vamp:computes_signal_type  <Place signal type URI here and uncomment> ;
     .
+plugbase:match_output_a_features a  vamp:DenseOutput ;
+    vamp:identifier       "a_features" ;
+    dc:title              "Raw A Features" ;
+    dc:description        """Spectral features extracted from performance A"""  ;
+    vamp:fixed_bin_count  "true" ;
+    vamp:unit             "" ;
+    vamp:bin_count        84 ;
+#   vamp:computes_event_type   <Place event type URI here and uncomment> ;
+#   vamp:computes_feature      <Place feature attribute URI here and uncomment> ;
+#   vamp:computes_signal_type  <Place signal type URI here and uncomment> ;
+    .
+plugbase:match_output_b_features a  vamp:DenseOutput ;
+    vamp:identifier       "b_features" ;
+    dc:title              "Raw B Features" ;
+    dc:description        """Spectral features extracted from performance B"""  ;
+    vamp:fixed_bin_count  "true" ;
+    vamp:unit             "" ;
+    vamp:bin_count        84 ;
+#   vamp:computes_event_type   <Place event type URI here and uncomment> ;
+#   vamp:computes_feature      <Place feature attribute URI here and uncomment> ;
+#   vamp:computes_signal_type  <Place signal type URI here and uncomment> ;
+    .
+plugbase:match_output_a_cfeatures a  vamp:DenseOutput ;
+    vamp:identifier       "a_cfeatures" ;
+    dc:title              "Conditioned A Features" ;
+    dc:description        """Spectral features extracted from performance A, after normalisation and conditioning"""  ;
+    vamp:fixed_bin_count  "true" ;
+    vamp:unit             "" ;
+    vamp:bin_count        84 ;
+#   vamp:computes_event_type   <Place event type URI here and uncomment> ;
+#   vamp:computes_feature      <Place feature attribute URI here and uncomment> ;
+#   vamp:computes_signal_type  <Place signal type URI here and uncomment> ;
+    .
+plugbase:match_output_b_cfeatures a  vamp:DenseOutput ;
+    vamp:identifier       "b_cfeatures" ;
+    dc:title              "Conditioned B Features" ;
+    dc:description        """Spectral features extracted from performance B, after norrmalisation and conditioning"""  ;
+    vamp:fixed_bin_count  "true" ;
+    vamp:unit             "" ;
+    vamp:bin_count        84 ;
+#   vamp:computes_event_type   <Place event type URI here and uncomment> ;
+#   vamp:computes_feature      <Place feature attribute URI here and uncomment> ;
+#   vamp:computes_signal_type  <Place signal type URI here and uncomment> ;
+    .
+plugbase:match_output_overall_cost a  vamp:DenseOutput ;
+    vamp:identifier       "overall_cost" ;
+    dc:title              "Overall Cost" ;
+    dc:description        """Normalised overall path cost for the cheapest path"""  ;
+    vamp:fixed_bin_count  "true" ;
+    vamp:unit             "" ;
+    vamp:bin_count        1 ;
+#   vamp:computes_event_type   <Place event type URI here and uncomment> ;
+#   vamp:computes_feature      <Place feature attribute URI here and uncomment> ;
+#   vamp:computes_signal_type  <Place signal type URI here and uncomment> ;
+    .
 
--- a/src/FeatureExtractor.cpp	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/FeatureExtractor.cpp	Fri Feb 06 18:41:35 2015 +0000
@@ -24,7 +24,7 @@
 
 using namespace std;
 
-//#define DEBUG_FEATURE_EXTRACTOR 1
+#define DEBUG_FEATURE_EXTRACTOR 1
 
 FeatureExtractor::FeatureExtractor(Parameters parameters) :
     m_params(parameters)
@@ -70,12 +70,15 @@
 void
 FeatureExtractor::makeStandardFrequencyMap()
 {
+    double refFreq = m_params.referenceFrequency;
     double binWidth = m_params.sampleRate / m_params.fftSize;
     int crossoverBin = (int)(2 / (pow(2, 1/12.0) - 1));
-    int crossoverMidi = lrint(log(crossoverBin*binWidth/440.0)/
+    int crossoverMidi = lrint(log(crossoverBin * binWidth / refFreq)/
                               log(2.0) * 12 + 69);
 
-    // freq = 440 * Math.pow(2, (midi-69)/12.0) / binWidth;
+#ifdef DEBUG_FEATURE_EXTRACTOR
+    cerr << "FeatureExtractor::makeStandardFrequencyMap: refFreq = " << refFreq << endl;
+#endif
     
     int i = 0;
     while (i <= crossoverBin) {
@@ -84,17 +87,23 @@
     }
 
     while (i <= m_params.fftSize/2) {
-        double midi = log(i*binWidth/440.0) / log(2.0) * 12 + 69;
+        double midi = log(i * binWidth / refFreq) / log(2.0) * 12 + 69;
         if (midi > 127) midi = 127;
         int target = crossoverBin + lrint(midi) - crossoverMidi;
         if (target >= m_featureSize) target = m_featureSize - 1;
         m_freqMap[i++] = target;
     }
+
+#ifdef DEBUG_FEATURE_EXTRACTOR
+    cerr << "FeatureExtractor: crossover bin is " << crossoverBin << " for midi "
+         << crossoverMidi << endl;
+#endif
 }
 
 void
 FeatureExtractor::makeChromaFrequencyMap()
 {
+    double refFreq = m_params.referenceFrequency;
     double binWidth = m_params.sampleRate / m_params.fftSize;
     int crossoverBin = (int)(1 / (pow(2, 1/12.0) - 1));
     int i = 0;
@@ -102,7 +111,7 @@
         m_freqMap[i++] = 0;
     }
     while (i <= m_params.fftSize/2) {
-        double midi = log(i*binWidth/440.0) / log(2.0) * 12 + 69;
+        double midi = log(i * binWidth / refFreq) / log(2.0) * 12 + 69;
         m_freqMap[i++] = (lrint(midi)) % 12 + 1;
     }
 }
--- a/src/FeatureExtractor.h	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/FeatureExtractor.h	Fri Feb 06 18:41:35 2015 +0000
@@ -48,7 +48,8 @@
         Parameters(float rate_, int fftSize_) :
             sampleRate(rate_),
             useChromaFrequencyMap(false),
-            fftSize(fftSize_)
+            fftSize(fftSize_),
+            referenceFrequency(440.0)
         {}
 
         /** Sample rate of audio */
@@ -62,6 +63,9 @@
          *  in is already in the frequency domain, so this expresses
          *  the size of the frame that the caller will be providing. */
         int fftSize;
+
+        /** Frequency of concert A */
+        double referenceFrequency;
     };
 
     /**
--- a/src/Finder.cpp	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/Finder.cpp	Fri Feb 06 18:41:35 2015 +0000
@@ -407,6 +407,19 @@
 }
 #endif
 
+double
+Finder::getOverallCost()
+{
+    int ex = m_m->getOtherFrameCount() - 1;
+    int ey = m_m->getFrameCount() - 1;
+
+    if (ex < 0 || ey < 0) {
+        return 0;
+    }
+
+    return m_m->getPathCost(ey, ex);
+}
+
 int
 Finder::retrievePath(bool smooth, vector<int> &pathx, vector<int> &pathy)
 {
--- a/src/Finder.h	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/Finder.h	Fri Feb 06 18:41:35 2015 +0000
@@ -106,6 +106,12 @@
      */
     int retrievePath(bool smooth, std::vector<int> &pathx, std::vector<int> &pathy);
 
+    /**
+     * Get the path cost for the overall path to the end of both
+     * sources.
+     */
+    double getOverallCost();
+    
 protected:
 #ifdef PERFORM_ERROR_CHECKS
     struct ErrorPosition {
--- a/src/MatchPipeline.cpp	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/MatchPipeline.cpp	Fri Feb 06 18:41:35 2015 +0000
@@ -20,9 +20,10 @@
 MatchPipeline::MatchPipeline(FeatureExtractor::Parameters feParams,
 			     FeatureConditioner::Parameters fcParams,
                              DistanceMetric::Parameters dParams,
-			     Matcher::Parameters matchParams) :
+			     Matcher::Parameters matchParams,
+                             double secondReferenceFrequency) :
     m_fe1(feParams),
-    m_fe2(feParams),
+    m_fe2(paramsWithFreq(feParams, secondReferenceFrequency)),
     m_fc1(fcParams),
     m_fc2(fcParams),
     m_pm1(matchParams, dParams, 0),
@@ -39,6 +40,14 @@
 {
 }
 
+FeatureExtractor::Parameters
+MatchPipeline::paramsWithFreq(FeatureExtractor::Parameters params, double freq)
+{
+    if (freq == 0.0) return params;
+    params.referenceFrequency = freq;
+    return params;
+}
+
 void
 MatchPipeline::feedFrequencyDomainAudio(const float *arr1, const float *arr2)
 {
@@ -145,5 +154,9 @@
     return m_feeder.retrieveForwardPath(pathx, pathy);
 }
 
+double
+MatchPipeline::getOverallCost()
+{
+    return m_feeder.getFinder()->getOverallCost();
+}
 
-
--- a/src/MatchPipeline.h	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/MatchPipeline.h	Fri Feb 06 18:41:35 2015 +0000
@@ -35,11 +35,18 @@
      *      -> Features
      *          -> Conditioned features
      *              -> Matcher
+     *
+     * Only one set of FeatureExtractor::Parameters is provided; this
+     * contains a single reference frequency, but it's possible the
+     * two input streams may have different tuning frequencies. A
+     * separate frequency for the second input can be provided here as
+     * an optional parameter if needed.
      */
     MatchPipeline(FeatureExtractor::Parameters feParams,
 		  FeatureConditioner::Parameters fcParams,
                   DistanceMetric::Parameters dParams,
-		  Matcher::Parameters matchParams);
+		  Matcher::Parameters matchParams,
+                  double secondReferenceFrequency = 0.0);
 
     ~MatchPipeline();
 
@@ -103,7 +110,15 @@
      * See MatchFeatureFeeder::retrieveForwardPath for more details.
      */
     void retrieveForwardPath(std::vector<int> &pathx, std::vector<int> &pathy);
-    
+
+    /**
+     * Get the path cost for the overall path to the end of both
+     * sources.
+     *
+     * See Finder::getOverallCost for more details.
+     */
+    double getOverallCost();
+
 private:
     FeatureExtractor m_fe1;
     FeatureExtractor m_fe2;
@@ -120,6 +135,8 @@
     vector<double> m_c1;
     vector<double> m_c2;
     bool aboveThreshold(const vector<double> &f);
+    FeatureExtractor::Parameters paramsWithFreq(FeatureExtractor::Parameters,
+                                                double);
 };
 
 #endif
--- a/src/MatchVampPlugin.cpp	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/MatchVampPlugin.cpp	Fri Feb 06 18:41:35 2015 +0000
@@ -62,6 +62,7 @@
     m_defaultParams(defaultStepTime),
     m_feParams(inputSampleRate, m_blockSize),
     m_defaultFeParams(inputSampleRate, m_blockSize),
+    m_secondReferenceFrequency(m_defaultFeParams.referenceFrequency),
     m_fcParams(),
     m_defaultFcParams(),
     m_dParams(),
@@ -146,19 +147,56 @@
 
     ParameterDescriptor desc;
 
-    desc.identifier = "serialise";
-    desc.name = "Serialise Plugin Invocations";
-    desc.description = "Reduce potential memory load at the expense of multiprocessor performance by serialising multi-threaded plugin runs";
+    desc.identifier = "freq1";
+    desc.name = "Tuning frequency of first input";
+    desc.description = "Tuning frequency (concert A) for the reference audio.";
+    desc.minValue = 220.0;
+    desc.maxValue = 880.0;
+    desc.defaultValue = (float)m_defaultFeParams.referenceFrequency;
+    desc.isQuantized = false;
+    desc.unit = "Hz";
+    list.push_back(desc);
+
+    desc.identifier = "freq2";
+    desc.name = "Tuning frequency of second input";
+    desc.description = "Tuning frequency (concert A) for the other audio.";
+    desc.minValue = 220.0;
+    desc.maxValue = 880.0;
+    desc.defaultValue = (float)m_defaultFeParams.referenceFrequency;
+    desc.isQuantized = false;
+    desc.unit = "Hz";
+    list.push_back(desc);
+
+    desc.unit = "";
+    
+    desc.identifier = "usechroma";
+    desc.name = "Feature type";
+    desc.description = "Whether to use warped spectrogram or chroma frequency map";
     desc.minValue = 0;
     desc.maxValue = 1;
-    desc.defaultValue = 0;
+    desc.defaultValue = m_defaultFeParams.useChromaFrequencyMap ? 1 : 0;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    desc.valueNames.clear();
+    desc.valueNames.push_back("Spectral");
+    desc.valueNames.push_back("Chroma");
+    list.push_back(desc);
+
+    desc.valueNames.clear();
+
+    desc.identifier = "usespecdiff";
+    desc.name = "Use feature difference";
+    desc.description = "Whether to use half-wave rectified feature-to-feature difference instead of straight spectral or chroma feature";
+    desc.minValue = 0;
+    desc.maxValue = 1;
+    desc.defaultValue = (int)m_defaultFcParams.order;
     desc.isQuantized = true;
     desc.quantizeStep = 1;
     list.push_back(desc);
 
     desc.identifier = "framenorm";
-    desc.name = "Frame Normalisation";
-    desc.description = "Type of normalisation to use for frequency-domain audio features";
+    desc.name = "Frame normalisation";
+    desc.description = "Type of normalisation to use for features";
     desc.minValue = 0;
     desc.maxValue = 2;
     desc.defaultValue = (int)m_defaultFcParams.norm;
@@ -166,54 +204,11 @@
     desc.quantizeStep = 1;
     desc.valueNames.clear();
     desc.valueNames.push_back("None");
-    desc.valueNames.push_back("Sum To 1");
-    desc.valueNames.push_back("Long-Term Average");
+    desc.valueNames.push_back("Sum to 1");
+    desc.valueNames.push_back("Long-term average");
     list.push_back(desc);
     desc.valueNames.clear();
-
-    desc.identifier = "distnorm";
-    desc.name = "Distance Normalisation";
-    desc.description = "Type of normalisation to use for distance metric";
-    desc.minValue = 0;
-    desc.maxValue = 2;
-    desc.defaultValue = (int)m_defaultDParams.norm;
-    desc.isQuantized = true;
-    desc.quantizeStep = 1;
-    desc.valueNames.clear();
-    desc.valueNames.push_back("None");
-    desc.valueNames.push_back("Sum of Frames");
-    desc.valueNames.push_back("Log Sum of Frames");
-    list.push_back(desc);
-    desc.valueNames.clear();
-
-    desc.identifier = "usespecdiff";
-    desc.name = "Use Spectral Difference";
-    desc.description = "Whether to use half-wave rectified spectral difference instead of straight spectrum";
-    desc.minValue = 0;
-    desc.maxValue = 1;
-    desc.defaultValue = (int)m_defaultFcParams.order;
-    desc.isQuantized = true;
-    desc.quantizeStep = 1;
-    list.push_back(desc);
-
-    desc.identifier = "usechroma";
-    desc.name = "Use Chroma Frequency Map";
-    desc.description = "Whether to use a chroma frequency map instead of the default warped spectrogram";
-    desc.minValue = 0;
-    desc.maxValue = 1;
-    desc.defaultValue = m_defaultFeParams.useChromaFrequencyMap ? 1 : 0;
-    desc.isQuantized = true;
-    desc.quantizeStep = 1;
-    list.push_back(desc);
-
-    desc.identifier = "silencethreshold";
-    desc.name = "Silence Threshold";
-    desc.description = "Total frame energy threshold below which a feature will be regarded as silent";
-    desc.minValue = 0;
-    desc.maxValue = 1;
     desc.defaultValue = (float)m_defaultFcParams.silenceThreshold;
-    desc.isQuantized = false;
-    list.push_back(desc);
 
     desc.identifier = "metric";
     desc.name = "Distance metric";
@@ -230,8 +225,32 @@
     list.push_back(desc);
     desc.valueNames.clear();
 
+    desc.identifier = "distnorm";
+    desc.name = "Distance normalisation";
+    desc.description = "Type of normalisation to use for distance metric";
+    desc.minValue = 0;
+    desc.maxValue = 2;
+    desc.defaultValue = (int)m_defaultDParams.norm;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    desc.valueNames.clear();
+    desc.valueNames.push_back("None");
+    desc.valueNames.push_back("Sum of frames");
+    desc.valueNames.push_back("Log sum of frames");
+    list.push_back(desc);
+    desc.valueNames.clear();
+
+    desc.identifier = "silencethreshold";
+    desc.name = "Silence threshold";
+    desc.description = "Total frame energy threshold below which a feature will be regarded as silent";
+    desc.minValue = 0;
+    desc.maxValue = 0.1f;
+    desc.defaultValue = (float)m_defaultFcParams.silenceThreshold;
+    desc.isQuantized = false;
+    list.push_back(desc);
+
     desc.identifier = "noise";
-    desc.name = "Mix in Noise";
+    desc.name = "Add 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.";
     desc.minValue = 0;
     desc.maxValue = 1;
@@ -241,7 +260,7 @@
     list.push_back(desc);
     
     desc.identifier = "gradientlimit";
-    desc.name = "Gradient Limit";
+    desc.name = "Gradient limit";
     desc.description = "Limit of number of frames that will be accepted from one source without a frame from the other source being accepted";
     desc.minValue = 1;
     desc.maxValue = 10;
@@ -251,7 +270,7 @@
     list.push_back(desc);
 
     desc.identifier = "zonewidth";
-    desc.name = "Search Zone Width";
+    desc.name = "Search zone width";
     desc.description = "Width of the search zone (error margin) either side of the ongoing match position, in seconds";
     desc.minValue = 1;
     desc.maxValue = 60;
@@ -262,7 +281,7 @@
     list.push_back(desc);
 
     desc.identifier = "diagonalweight";
-    desc.name = "Diagonal Weight";
+    desc.name = "Diagonal weight";
     desc.description = "Weight applied to cost of diagonal step relative to horizontal or vertical step. The default of 2.0 is good for gross tracking of quite different performances; closer to 1.0 produces a smoother path for performances more similar in tempo";
     desc.minValue = 1.0;
     desc.maxValue = 2.0;
@@ -272,7 +291,7 @@
     list.push_back(desc);
     
     desc.identifier = "smooth";
-    desc.name = "Smooth Path";
+    desc.name = "Use path smoothing";
     desc.description = "Smooth the path by replacing steps with diagonals. (This was enabled by default in earlier versions of the MATCH plugin, but the default now is to produce an un-smoothed path.)";
     desc.minValue = 0;
     desc.maxValue = 1;
@@ -282,6 +301,16 @@
     desc.unit = "";
     list.push_back(desc);
 
+    desc.identifier = "serialise";
+    desc.name = "Serialise plugin invocations";
+    desc.description = "Reduce potential memory load at the expense of multiprocessor performance by serialising multi-threaded plugin runs";
+    desc.minValue = 0;
+    desc.maxValue = 1;
+    desc.defaultValue = 0;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    list.push_back(desc);
+    
     return list;
 }
 
@@ -312,6 +341,10 @@
         return (int)m_dParams.metric;
     } else if (name == "noise") {
         return m_dParams.noise;
+    } else if (name == "freq1") {
+        return (float)m_feParams.referenceFrequency;
+    } else if (name == "freq2") {
+        return (float)m_secondReferenceFrequency;
     }
     
     return 0.0;
@@ -344,6 +377,10 @@
         m_dParams.metric = (DistanceMetric::Metric)(int(value + 0.1));
     } else if (name == "noise") {
         m_dParams.noise = (DistanceMetric::NoiseAddition)(int(value + 0.1));
+    } else if (name == "freq1") {
+        m_feParams.referenceFrequency = value;
+    } else if (name == "freq2") {
+        m_secondReferenceFrequency = value;
     }
 }
 
@@ -365,7 +402,11 @@
     m_params.hopTime = m_stepTime;
     m_feParams.fftSize = m_blockSize;
 
-    m_pipeline = new MatchPipeline(m_feParams, m_fcParams, m_dParams, m_params);
+    cerr << "creating pipeline with m_secondReferenceFrequency = "
+         << m_secondReferenceFrequency << endl;
+    m_pipeline = new MatchPipeline(m_feParams, m_fcParams, m_dParams, m_params,
+                                   m_secondReferenceFrequency);
+    cerr << "done" << endl;
 }
 
 bool
@@ -532,6 +573,19 @@
     m_cbFeaturesOutNo = list.size();
     list.push_back(desc);
 
+    desc.identifier = "overall_cost";
+    desc.name = "Overall Cost";
+    desc.description = "Normalised overall path cost for the cheapest path";
+    desc.unit = "";
+    desc.hasFixedBinCount = true;
+    desc.binCount = 1;
+    desc.hasKnownExtents = false;
+    desc.isQuantized = false;
+    desc.sampleType = OutputDescriptor::FixedSampleRate;
+    desc.sampleRate = 1;
+    m_overallCostOutNo = list.size();
+    list.push_back(desc);
+    
     return list;
 }
 
@@ -610,6 +664,12 @@
     std::vector<int> pathy;
     int len = m_pipeline->retrievePath(m_smooth, pathx, pathy);
 
+    double cost = m_pipeline->getOverallCost();
+    Feature costFeature;
+    costFeature.hasTimestamp = false;
+    costFeature.values.push_back((float)cost);
+    returnFeatures[m_overallCostOutNo].push_back(costFeature);
+    
     int prevx = 0;
     int prevy = 0;
 
--- a/src/MatchVampPlugin.h	Fri Feb 06 18:09:18 2015 +0000
+++ b/src/MatchVampPlugin.h	Fri Feb 06 18:41:35 2015 +0000
@@ -78,14 +78,13 @@
     bool m_smooth;
 
     int m_frameNo;
-    int m_lastFrameIn1;
-    int m_lastFrameIn2;
     
     Matcher::Parameters m_params;
     Matcher::Parameters m_defaultParams;
 
     FeatureExtractor::Parameters m_feParams;
     FeatureExtractor::Parameters m_defaultFeParams;
+    double m_secondReferenceFrequency;
 
     FeatureConditioner::Parameters m_fcParams;
     FeatureConditioner::Parameters m_defaultFcParams;
@@ -102,6 +101,7 @@
     mutable int m_bFeaturesOutNo;
     mutable int m_caFeaturesOutNo;
     mutable int m_cbFeaturesOutNo;
+    mutable int m_overallCostOutNo;
 
 #ifdef _WIN32
     static HANDLE m_serialisingMutex;