Mercurial > hg > silvet
changeset 306:af19bee9e53b livemode
Merge from default branch
author | Chris Cannam |
---|---|
date | Fri, 05 Dec 2014 16:47:06 +0000 |
parents | f5f3b50b2b9f (diff) 04a3c152e590 (current diff) |
children | 5a181a427ac8 |
files | src/Silvet.cpp |
diffstat | 10 files changed, 312 insertions(+), 72 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.inc Fri Dec 05 16:46:57 2014 +0000 +++ b/Makefile.inc Fri Dec 05 16:47:06 2014 +0000 @@ -20,8 +20,8 @@ PLUGIN := silvet$(PLUGIN_EXT) -PLUGIN_HEADERS := $(SRC_DIR)/Silvet.h $(SRC_DIR)/EM.h $(SRC_DIR)/Instruments.h -PLUGIN_SOURCES := $(SRC_DIR)/Silvet.cpp $(SRC_DIR)/EM.cpp $(SRC_DIR)/Instruments.cpp $(SRC_DIR)/libmain.cpp +PLUGIN_HEADERS := $(SRC_DIR)/Silvet.h $(SRC_DIR)/EM.h $(SRC_DIR)/Instruments.h $(SRC_DIR)/LiveInstruments.h +PLUGIN_SOURCES := $(SRC_DIR)/Silvet.cpp $(SRC_DIR)/EM.cpp $(SRC_DIR)/Instruments.cpp $(SRC_DIR)/LiveInstruments.cpp $(SRC_DIR)/libmain.cpp BQVEC_HEADERS := $(BQVEC_DIR)/Allocators.h $(BQVEC_DIR)/Restrict.h $(BQVEC_DIR)/VectorOps.h BQVEC_SOURCES := $(BQVEC_DIR)/Allocators.cpp
--- a/Makefile.linux Fri Dec 05 16:46:57 2014 +0000 +++ b/Makefile.linux Fri Dec 05 16:47:06 2014 +0000 @@ -1,12 +1,12 @@ -CFLAGS := -Wall -O3 -fopenmp -ffast-math -msse -msse2 -mfpmath=sse -ftree-vectorize -fPIC -I../vamp-plugin-sdk/ -DUSE_PTHREADS +CFLAGS := -Wall -O3 -ffast-math -msse -msse2 -mfpmath=sse -ftree-vectorize -fPIC -I../vamp-plugin-sdk/ -DUSE_PTHREADS #CFLAGS := -g -fPIC -I../vamp-plugin-sdk CXXFLAGS := $(CFLAGS) VAMPSDK_DIR := ../vamp-plugin-sdk -PLUGIN_LDFLAGS := -lgomp -shared -Wl,-Bsymbolic -Wl,-z,defs -Wl,--version-script=vamp-plugin.map -lpthread +PLUGIN_LDFLAGS := -shared -Wl,-Bsymbolic -Wl,-z,defs -Wl,--version-script=vamp-plugin.map -lpthread PLUGIN_EXT := .so
--- a/data/include/templates.h Fri Dec 05 16:46:57 2014 +0000 +++ b/data/include/templates.h Fri Dec 05 16:47:06 2014 +0000 @@ -6,7 +6,7 @@ /* note: intended to parse as both C and C++ */ #define SILVET_TEMPLATE_COUNT 14 /* Number of instruments */ -#define SILVET_TEMPLATE_NOTE_COUNT 88 /* Number of notes per instrument */ +#define SILVET_TEMPLATE_NOTE_COUNT 88 /* Number of notes per instrument */ #define SILVET_TEMPLATE_HEIGHT 545 /* Frequency bins per template */ #define SILVET_TEMPLATE_MAX_SHIFT 2 /* Zeros at either end of template */ #define SILVET_TEMPLATE_SIZE 549 /* Height + 2 * max shift space */
--- a/src/Instruments.cpp Fri Dec 05 16:46:57 2014 +0000 +++ b/src/Instruments.cpp Fri Dec 05 16:47:06 2014 +0000 @@ -19,16 +19,28 @@ #include <iostream> -const int InstrumentPack::templateNoteCount = SILVET_TEMPLATE_NOTE_COUNT; -const int InstrumentPack::templateHeight = SILVET_TEMPLATE_HEIGHT; -const int InstrumentPack::templateMaxShift = SILVET_TEMPLATE_MAX_SHIFT; -const int InstrumentPack::templateSize = SILVET_TEMPLATE_SIZE; - using std::string; using std::vector; using std::cerr; using std::endl; +InstrumentPack::InstrumentPack(int lowest, int highest, + std::string n, std::vector<Templates> tt) : + templateNoteCount(SILVET_TEMPLATE_NOTE_COUNT), + templateHeight(SILVET_TEMPLATE_HEIGHT), + templateMaxShift(SILVET_TEMPLATE_MAX_SHIFT), + templateSize(SILVET_TEMPLATE_SIZE), + lowestNote(lowest), + highestNote(highest), + maxPolyphony(5), + pitchSparsity(1.1), + sourceSparsity(1.2), + levelThreshold(5), + name(n), + templates(tt) +{ +} + const char *simpleInstruments[] = { // Each instrument has two consecutive slots, one for the pack // name and one for the template to look up
--- a/src/Instruments.h Fri Dec 05 16:46:57 2014 +0000 +++ b/src/Instruments.h Fri Dec 05 16:47:06 2014 +0000 @@ -32,10 +32,10 @@ class InstrumentPack { public: - static const int templateNoteCount; - static const int templateHeight; - static const int templateMaxShift; - static const int templateSize; + int templateNoteCount; + int templateHeight; + int templateMaxShift; + int templateSize; int lowestNote; int highestNote; @@ -60,15 +60,9 @@ private: InstrumentPack(int lowest, int highest, std::string n, - std::vector<Templates> tt) : - lowestNote(lowest), - highestNote(highest), - maxPolyphony(5), - pitchSparsity(1.1), - sourceSparsity(1.2), - levelThreshold(5), - name(n), - templates(tt) { } + std::vector<Templates> tt); + + friend class LiveAdapter; }; #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LiveInstruments.cpp Fri Dec 05 16:47:06 2014 +0000 @@ -0,0 +1,94 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Silvet + + A Vamp plugin for note transcription. + Centre for Digital Music, Queen Mary University of London. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "LiveInstruments.h" + +#include "data/include/templates.h" + +#include <iostream> + +using namespace std; + +InstrumentPack +LiveAdapter::adapt(const InstrumentPack &original) +{ + vector<InstrumentPack::Templates> templates; + +// cerr << "LiveAdapter: reduced template height is " << SILVET_TEMPLATE_HEIGHT/5 << endl; + + for (vector<InstrumentPack::Templates>::const_iterator i = + original.templates.begin(); + i != original.templates.end(); ++i) { + + InstrumentPack::Templates t; + t.lowestNote = i->lowestNote; + t.highestNote = i->highestNote; + t.data.resize(i->data.size()); + + for (int j = 0; j < int(i->data.size()); ++j) { + + t.data[j].resize(SILVET_TEMPLATE_HEIGHT/5); + + float sum = 0.f; + + for (int k = 0; k < SILVET_TEMPLATE_HEIGHT/5; ++k) { + + t.data[j][k] = 0.f; + + for (int m = 0; m < 5; ++m) { + t.data[j][k] += i->data[j][k * 5 + m + 2]; + } + + sum += t.data[j][k]; + } + + // re-normalise + if (sum > 0.f) { + for (int k = 0; k < (int)t.data[j].size(); ++k) { + t.data[j][k] *= 1.f / sum; + } + } + } + + templates.push_back(t); + } + + InstrumentPack live(original.lowestNote, + original.highestNote, + original.name, + templates); + + live.templateHeight = SILVET_TEMPLATE_HEIGHT/5; + live.templateMaxShift = 0; + live.templateSize = live.templateHeight; + + live.maxPolyphony = original.maxPolyphony; + live.pitchSparsity = original.pitchSparsity; + live.sourceSparsity = original.sourceSparsity; + live.levelThreshold = original.levelThreshold / 20; + + return live; +} + +vector<InstrumentPack> +LiveAdapter::adaptAll(const vector<InstrumentPack> &v) +{ + vector<InstrumentPack> out; + for (int i = 0; i < (int)v.size(); ++i) { + InstrumentPack p(LiveAdapter::adapt(v[i])); + out.push_back(p); + } + return out; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LiveInstruments.h Fri Dec 05 16:47:06 2014 +0000 @@ -0,0 +1,32 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Silvet + + A Vamp plugin for note transcription. + Centre for Digital Music, Queen Mary University of London. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef SILVET_LIVE_INSTRUMENTS_H +#define SILVET_LIVE_INSTRUMENTS_H + +#include "Instruments.h" + +/** + * Adapt an instrument pack into a "live" version, with fewer bins per + * octave and so lower CQ latency. + */ +class LiveAdapter +{ +public: + static InstrumentPack adapt(const InstrumentPack &original); + static std::vector<InstrumentPack> adaptAll(const std::vector<InstrumentPack> &); +}; + +#endif
--- a/src/Silvet.cpp Fri Dec 05 16:46:57 2014 +0000 +++ b/src/Silvet.cpp Fri Dec 05 16:47:06 2014 +0000 @@ -21,6 +21,7 @@ #include "MedianFilter.h" #include "constant-q-cpp/src/dsp/Resampler.h" #include "flattendynamics-ladspa.h" +#include "LiveInstruments.h" #include <vector> @@ -33,7 +34,9 @@ using Vamp::RealTime; static int processingSampleRate = 44100; -static int processingBPO = 60; + +static int binsPerSemitoneLive = 1; +static int binsPerSemitoneNormal = 5; static int minInputSampleRate = 100; static int maxInputSampleRate = 192000; @@ -41,10 +44,11 @@ Silvet::Silvet(float inputSampleRate) : Plugin(inputSampleRate), m_instruments(InstrumentPack::listInstrumentPacks()), + m_liveInstruments(LiveAdapter::adaptAll(m_instruments)), m_resampler(0), m_flattener(0), m_cq(0), - m_hqMode(true), + m_mode(HighQualityMode), m_fineTuning(false), m_instrument(0), m_colsPerSec(50) @@ -88,7 +92,7 @@ int Silvet::getPluginVersion() const { - return 2; + return 3; } string @@ -136,14 +140,15 @@ desc.identifier = "mode"; desc.name = "Processing mode"; desc.unit = ""; - desc.description = "Sets the tradeoff of processing speed against transcription quality. Draft mode modifies a number of internal parameters in favour of speed. Intensive mode (the default) will almost always produce better results."; + desc.description = "Sets the tradeoff of processing speed against transcription quality. Draft mode is tuned in favour of overall speed; Live mode is tuned in favour of lower latency; while Intensive mode (the default) will almost always produce the best results."; desc.minValue = 0; - desc.maxValue = 1; + desc.maxValue = 2; desc.defaultValue = 1; desc.isQuantized = true; desc.quantizeStep = 1; desc.valueNames.push_back("Draft (faster)"); desc.valueNames.push_back("Intensive (higher quality)"); + desc.valueNames.push_back("Live (lower latency)"); list.push_back(desc); desc.identifier = "instrument"; @@ -180,7 +185,7 @@ Silvet::getParameter(string identifier) const { if (identifier == "mode") { - return m_hqMode ? 1.f : 0.f; + return (float)(int)m_mode; } else if (identifier == "finetune") { return m_fineTuning ? 1.f : 0.f; } else if (identifier == "instrument") { @@ -193,7 +198,7 @@ Silvet::setParameter(string identifier, float value) { if (identifier == "mode") { - m_hqMode = (value > 0.5); + m_mode = (ProcessingMode)(int)(value + 0.5); } else if (identifier == "finetune") { m_fineTuning = (value > 0.5); } else if (identifier == "instrument") { @@ -246,18 +251,18 @@ d.description = "Filtered constant-Q time-frequency distribution as used as input to the expectation-maximisation algorithm."; d.unit = ""; d.hasFixedBinCount = true; - d.binCount = m_instruments[0].templateHeight; + d.binCount = getPack(0).templateHeight; d.binNames.clear(); if (m_cq) { char name[50]; - for (int i = 0; i < m_instruments[0].templateHeight; ++i) { + for (int i = 0; i < getPack(0).templateHeight; ++i) { // We have a 600-bin (10 oct 60-bin CQ) of which the // lowest-frequency 55 bins have been dropped, for a // 545-bin template. The native CQ bins go high->low // frequency though, so these are still the first 545 bins // as reported by getBinFrequency, though in reverse order float freq = m_cq->getBinFrequency - (m_instruments[0].templateHeight - i - 1); + (getPack(0).templateHeight - i - 1); sprintf(name, "%.1f Hz", freq); d.binNames.push_back(name); } @@ -275,10 +280,10 @@ d.description = "Pitch activation distribution resulting from expectation-maximisation algorithm, prior to note extraction."; d.unit = ""; d.hasFixedBinCount = true; - d.binCount = m_instruments[0].templateNoteCount; + d.binCount = getPack(0).templateNoteCount; d.binNames.clear(); if (m_cq) { - for (int i = 0; i < m_instruments[0].templateNoteCount; ++i) { + for (int i = 0; i < getPack(0).templateNoteCount; ++i) { d.binNames.push_back(noteName(i, 0, 1)); } } @@ -290,6 +295,35 @@ m_pitchOutputNo = list.size(); list.push_back(d); + d.identifier = "templates"; + d.name = "Templates"; + d.description = "Constant-Q spectral templates for the selected instrument pack."; + d.unit = ""; + d.hasFixedBinCount = true; + d.binCount = getPack(0).templateHeight; + d.binNames.clear(); + if (m_cq) { + char name[50]; + for (int i = 0; i < getPack(0).templateHeight; ++i) { + // We have a 600-bin (10 oct 60-bin CQ) of which the + // lowest-frequency 55 bins have been dropped, for a + // 545-bin template. The native CQ bins go high->low + // frequency though, so these are still the first 545 bins + // as reported by getBinFrequency, though in reverse order + float freq = m_cq->getBinFrequency + (getPack(0).templateHeight - i - 1); + sprintf(name, "%.1f Hz", freq); + d.binNames.push_back(name); + } + } + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleType = OutputDescriptor::FixedSampleRate; + d.sampleRate = m_colsPerSec; + d.hasDuration = false; + m_templateOutputNo = list.size(); + list.push_back(d); + return list; } @@ -346,7 +380,12 @@ float((shiftCount - shift) - int(shiftCount / 2) - 1) / shiftCount; } - return float(27.5 * pow(2.0, (note + pshift) / 12.0)); + float freq = float(27.5 * pow(2.0, (note + pshift) / 12.0)); + +// cerr << "note = " << note << ", shift = " << shift << ", shiftCount = " +// << shiftCount << ", obtained freq = " << freq << endl; + + return freq; } bool @@ -397,18 +436,32 @@ m_flattener = new FlattenDynamics(m_inputSampleRate); // before resampling m_flattener->reset(); + // this happens to be processingSampleRate / 3, and is the top + // freq used for the EM templates: + double maxFreq = 14700; + + if (m_mode == LiveMode) { + // We only have 12 bpo rather than 60, so we need the top bin + // to be the middle one of the top 5, i.e. 2/5 of a semitone + // lower than 14700 + maxFreq *= powf(2.0, -1.0 / 30.0); + } + double minFreq = 27.5; - if (!m_hqMode) { + if (m_mode != HighQualityMode) { // We don't actually return any notes from the bottom octave, // so we can just pad with zeros minFreq *= 2; } + int bpo = 12 * + (m_mode == LiveMode ? binsPerSemitoneLive : binsPerSemitoneNormal); + CQParameters params(processingSampleRate, minFreq, - processingSampleRate / 3, - processingBPO); + maxFreq, + bpo); params.q = 0.95; // MIREX code uses 0.8, but it seems 0.9 or lower // drops the FFT size to 512 from 1024 and alters @@ -421,14 +474,18 @@ m_cq = new CQSpectrogram(params, CQSpectrogram::InterpolateLinear); - m_colsPerSec = m_hqMode ? 50 : 25; +// cerr << "CQ bins = " << m_cq->getTotalBins() << endl; +// cerr << "CQ min freq = " << m_cq->getMinFrequency() << " (and for confirmation, freq of bin 0 = " << m_cq->getBinFrequency(0) << ")" << endl; + + m_colsPerSec = (m_mode == DraftMode ? 25 : 50); for (int i = 0; i < (int)m_postFilter.size(); ++i) { delete m_postFilter[i]; } m_postFilter.clear(); - for (int i = 0; i < m_instruments[0].templateNoteCount; ++i) { - m_postFilter.push_back(new MedianFilter<double>(3)); + int postFilterLength = 3; + for (int i = 0; i < getPack(0).templateNoteCount; ++i) { + m_postFilter.push_back(new MedianFilter<double>(postFilterLength)); } m_pianoRoll.clear(); m_inputGains.clear(); @@ -440,8 +497,11 @@ Silvet::FeatureSet Silvet::process(const float *const *inputBuffers, Vamp::RealTime timestamp) { + FeatureSet fs; + if (m_columnCount == 0) { m_startTime = timestamp; + insertTemplateFeatures(fs); } vector<float> flattened(m_blockSize); @@ -474,7 +534,7 @@ if (hadCount < resamplerLatency) { int stillToDrop = resamplerLatency - hadCount; if (stillToDrop >= int(data.size())) { - return FeatureSet(); + return fs; } else { data = vector<double>(data.begin() + stillToDrop, data.end()); } @@ -482,7 +542,7 @@ } Grid cqout = m_cq->process(data); - FeatureSet fs = transcribe(cqout); + transcribe(cqout, fs); return fs; } @@ -490,20 +550,42 @@ Silvet::getRemainingFeatures() { Grid cqout = m_cq->getRemainingOutput(); - FeatureSet fs = transcribe(cqout); + FeatureSet fs; + if (m_columnCount == 0) { + // process() was never called, but we still want these + insertTemplateFeatures(fs); + } else { + transcribe(cqout, fs); + } return fs; } -Silvet::FeatureSet -Silvet::transcribe(const Grid &cqout) +void +Silvet::insertTemplateFeatures(FeatureSet &fs) +{ + const InstrumentPack &pack = getPack(m_instrument); + for (int i = 0; i < int(pack.templates.size()) * pack.templateNoteCount; ++i) { + RealTime timestamp = RealTime::fromSeconds(double(i) / m_colsPerSec); + Feature f; + char buffer[50]; + sprintf(buffer, "Note %d", i + 1); + f.label = buffer; + f.hasTimestamp = true; + f.timestamp = timestamp; + f.values = pack.templates[i / pack.templateNoteCount] + .data[i % pack.templateNoteCount]; + fs[m_templateOutputNo].push_back(f); + } +} + +void +Silvet::transcribe(const Grid &cqout, Silvet::FeatureSet &fs) { Grid filtered = preProcess(cqout); - FeatureSet fs; - - if (filtered.empty()) return fs; + if (filtered.empty()) return; - const InstrumentPack &pack = m_instruments[m_instrument]; + const InstrumentPack &pack(getPack(m_instrument)); for (int i = 0; i < (int)filtered.size(); ++i) { Feature f; @@ -515,11 +597,11 @@ int width = filtered.size(); - int iterations = m_hqMode ? 20 : 10; + int iterations = (m_mode == HighQualityMode ? 20 : 10); Grid localPitches(width, vector<double>(pack.templateNoteCount, 0.0)); - bool wantShifts = m_hqMode && m_fineTuning; + bool wantShifts = (m_mode == HighQualityMode) && m_fineTuning; int shiftCount = 1; if (wantShifts) { shiftCount = pack.templateMaxShift * 2 + 1; @@ -542,7 +624,7 @@ } if (sum < columnThreshold) continue; - EM em(&pack, m_hqMode); + EM em(&pack, m_mode == HighQualityMode); em.setPitchSparsity(pack.pitchSparsity); em.setSourceSparsity(pack.sourceSparsity); @@ -593,8 +675,6 @@ fs[m_notesOutputNo].push_back(*fi); } } - - return fs; } Silvet::Grid @@ -616,7 +696,7 @@ // size we reduce to in a moment int latentColumns = m_cq->getLatency() / m_cq->getColumnHop(); - const InstrumentPack &pack = m_instruments[m_instrument]; + const InstrumentPack &pack(getPack(m_instrument)); for (int i = 0; i < width; ++i) { @@ -635,39 +715,42 @@ vector<double> outCol(pack.templateHeight); // In HQ mode, the CQ returns 600 bins and we ignore the - // lowest 55 of them. + // lowest 55 of them (assuming binsPerSemitone == 5). // - // In draft mode the CQ is an octave shorter, returning - // 540 bins, so we instead pad them with an additional 5 - // zeros. + // In draft and live mode the CQ is an octave shorter, + // returning 540 bins or equivalent, so we instead pad + // them with an additional 5 or equivalent zeros. // // We also need to reverse the column as we go, since the // raw CQ has the high frequencies first and we need it // the other way around. - if (m_hqMode) { + int bps = (m_mode == LiveMode ? + binsPerSemitoneLive : binsPerSemitoneNormal); + + if (m_mode == HighQualityMode) { for (int j = 0; j < pack.templateHeight; ++j) { - int ix = inCol.size() - j - 55; + int ix = inCol.size() - j - (11 * bps); outCol[j] = inCol[ix]; } } else { - for (int j = 0; j < 5; ++j) { + for (int j = 0; j < bps; ++j) { outCol[j] = 0.0; } - for (int j = 5; j < pack.templateHeight; ++j) { - int ix = inCol.size() - j + 4; + for (int j = bps; j < pack.templateHeight; ++j) { + int ix = inCol.size() - j + (bps-1); outCol[j] = inCol[ix]; } } vector<double> noiseLevel1 = - MedianFilter<double>::filter(40, outCol); + MedianFilter<double>::filter(8 * bps, outCol); for (int j = 0; j < pack.templateHeight; ++j) { noiseLevel1[j] = std::min(outCol[j], noiseLevel1[j]); } vector<double> noiseLevel2 = - MedianFilter<double>::filter(40, noiseLevel1); + MedianFilter<double>::filter(8 * bps, noiseLevel1); for (int j = 0; j < pack.templateHeight; ++j) { outCol[j] = std::max(outCol[j] - noiseLevel2[j], 0.0); } @@ -686,7 +769,7 @@ const vector<int> &bestShifts, bool wantShifts) { - const InstrumentPack &pack = m_instruments[m_instrument]; + const InstrumentPack &pack(getPack(m_instrument)); vector<double> filtered; @@ -835,7 +918,12 @@ } } - int v = round(strength * 2); + int v; + if (m_mode == LiveMode) { + v = round(strength * 30); + } else { + v = round(strength * 2); + } if (v > partVelocity) { partVelocity = v; }
--- a/src/Silvet.h Fri Dec 05 16:46:57 2014 +0000 +++ b/src/Silvet.h Fri Dec 05 16:47:06 2014 +0000 @@ -73,12 +73,27 @@ protected: const std::vector<InstrumentPack> m_instruments; + const std::vector<InstrumentPack> m_liveInstruments; + const InstrumentPack &getPack(int instrument) const { + if (m_mode == LiveMode) { + return m_liveInstruments[instrument]; + } else { + return m_instruments[instrument]; + } + } + Resampler *m_resampler; FlattenDynamics *m_flattener; CQSpectrogram *m_cq; - bool m_hqMode; + enum ProcessingMode { // ordered so draft==0 and hq==1 as in prior releases + DraftMode = 0, + HighQualityMode = 1, + LiveMode = 2, + }; + ProcessingMode m_mode; + bool m_fineTuning; int m_instrument; int m_colsPerSec; @@ -106,7 +121,9 @@ float getInputGainAt(Vamp::RealTime t); - FeatureSet transcribe(const Grid &); + void insertTemplateFeatures(FeatureSet &); + + void transcribe(const Grid &, FeatureSet &); string noteName(int n, int shift, int shiftCount) const; float noteFrequency(int n, int shift, int shiftCount) const; @@ -119,6 +136,7 @@ mutable int m_notesOutputNo; mutable int m_fcqOutputNo; mutable int m_pitchOutputNo; + mutable int m_templateOutputNo; }; #endif
--- a/testdata/evaluation/run.sh Fri Dec 05 16:46:57 2014 +0000 +++ b/testdata/evaluation/run.sh Fri Dec 05 16:47:06 2014 +0000 @@ -79,6 +79,8 @@ piece=`basename \`dirname "$infile" \`` arrangement=`basename "$infile" .wav` + + # Change this to the processing mode you want to test (e.g. 0 for draft) mode=1 echo