Mercurial > hg > nnls-chroma
changeset 172:d95c4cdef8af
Merge
author | Chris Cannam |
---|---|
date | Mon, 02 Nov 2015 11:32:30 +0000 |
parents | 7de720f503a5 (diff) c40de221b5df (current diff) |
children | d22f69c2b025 |
files | CITATION Chordino.cpp Makefile.osx NNLSBase.cpp |
diffstat | 13 files changed, 337 insertions(+), 178 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Thu Sep 05 17:30:38 2013 +0100 +++ b/.hgtags Mon Nov 02 11:32:30 2015 +0000 @@ -1,3 +1,8 @@ 12fd1d3ccd6e0072fc4be295e7a1e383e84912a1 0.1 12fd1d3ccd6e0072fc4be295e7a1e383e84912a1 0.1 dab7e7bfeba17478fa6c5af050c6270026ad635b 0.2 +2cd99c0810f28abe2fcbf2c50a29fee20b910ae4 mirex2013 +9e9267d6d78a8e67f2a4dc1aac4ea1aab135f4f0 v1.0 +0a743c2dac6aa0eaa093d5291c697e51eac1035e v1.1 +0a743c2dac6aa0eaa093d5291c697e51eac1035e v1.1 +ba9310bcc3fcb3c58c99d25837b6f62662666b7d v1.1
--- a/Chordino.cpp Thu Sep 05 17:30:38 2013 +0100 +++ b/Chordino.cpp Mon Nov 02 11:32:30 2015 +0000 @@ -121,7 +121,7 @@ list.push_back(whiteningParam); ParameterDescriptor spectralShapeParam; - spectralShapeParam.identifier = "spectralshape"; + spectralShapeParam.identifier = "s"; spectralShapeParam.name = "spectral shape"; spectralShapeParam.description = "Determines how individual notes in the note dictionary look: higher values mean more dominant higher harmonics."; spectralShapeParam.unit = ""; @@ -167,6 +167,9 @@ int index = 0; + float featureRate = + (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + OutputDescriptor d7; d7.identifier = "simplechord"; d7.name = "Chord Estimate"; @@ -178,7 +181,7 @@ d7.isQuantized = false; d7.sampleType = OutputDescriptor::VariableSampleRate; d7.hasDuration = false; - d7.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + d7.sampleRate = featureRate; list.push_back(d7); m_outputChords = index++; @@ -196,7 +199,7 @@ chordnotes.quantizeStep = 1; chordnotes.sampleType = OutputDescriptor::VariableSampleRate; chordnotes.hasDuration = true; - chordnotes.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + chordnotes.sampleRate = featureRate; list.push_back(chordnotes); m_outputChordnotes = index++; @@ -210,6 +213,7 @@ d8.hasKnownExtents = false; d8.isQuantized = false; d8.sampleType = OutputDescriptor::FixedSampleRate; + d8.sampleRate = featureRate; d8.hasDuration = false; list.push_back(d8); m_outputHarmonicChange = index++; @@ -224,6 +228,7 @@ loglikelihood.hasKnownExtents = false; loglikelihood.isQuantized = false; loglikelihood.sampleType = OutputDescriptor::FixedSampleRate; + loglikelihood.sampleRate = featureRate; loglikelihood.hasDuration = false; list.push_back(loglikelihood); m_outputLoglikelihood = index++; @@ -295,7 +300,7 @@ calculate a tuned log-frequency spectrogram (currentTunedSpec): use the tuning estimated above (kinda f0) to perform linear interpolation on the existing log-frequency spectrogram (kinda currentLogSpectrum). **/ - cerr << endl << "[Chordino Plugin] Tuning Log-Frequency Spectrogram ... "; + if (debug_on) cerr << endl << "[Chordino Plugin] Tuning Log-Frequency Spectrogram ... "; int count = 0; @@ -346,7 +351,7 @@ tunedSpec.push_back(currentTunedSpec); count++; } - cerr << "done." << endl; + if (debug_on) cerr << "done." << endl; /** Semitone spectrum and chromagrams Semitone-spaced log-frequency spectrum derived from the tuned log-freq spectrum above. the spectrum @@ -355,9 +360,9 @@ bass and treble stacked onto each other). **/ if (m_useNNLS == 0) { - cerr << "[Chordino Plugin] Mapping to semitone spectrum and chroma ... "; + if (debug_on) cerr << "[Chordino Plugin] Mapping to semitone spectrum and chroma ... "; } else { - cerr << "[Chordino Plugin] Performing NNLS and mapping to chroma ... "; + if (debug_on) cerr << "[Chordino Plugin] Performing NNLS and mapping to chroma ... "; } @@ -368,7 +373,7 @@ FeatureList chromaList; - + bool clipwarned = false; for (FeatureList::iterator it = tunedSpec.begin(); it != tunedSpec.end(); ++it) { Feature currentTunedSpec = *it; // logfreq spectrum @@ -449,7 +454,7 @@ vector<float> origchroma = chroma; chroma.insert(chroma.begin(), basschroma.begin(), basschroma.end()); // just stack the both chromas currentChromas.values = chroma; - + if (m_doNormalizeChroma > 0) { vector<float> chromanorm = vector<float>(3,0); switch (int(m_doNormalizeChroma)) { @@ -489,15 +494,22 @@ for (int iChord = 0; iChord < nChord; iChord++) { tempchordvalue = 0; for (int iBin = 0; iBin < 12; iBin++) { - tempchordvalue += m_chorddict[24 * iChord + iBin] * chroma[iBin]; + tempchordvalue += m_chorddict[24 * iChord + iBin] * chroma[iBin]; } for (int iBin = 12; iBin < 24; iBin++) { tempchordvalue += m_chorddict[24 * iChord + iBin] * chroma[iBin]; } if (iChord == nChord-1) tempchordvalue *= .7; if (tempchordvalue < 0) tempchordvalue = 0.0; - tempchordvalue = pow(1.3,tempchordvalue); - sumchordvalue+=tempchordvalue; + if (tempchordvalue > 200.0) { + if (!clipwarned) { + cerr << "WARNING: interim chroma contains extreme chord value " << tempchordvalue << ", clipping this and any others that appear" << endl; + clipwarned = true; + } + tempchordvalue = 200.0; + } + tempchordvalue = pow(1.3, tempchordvalue); + sumchordvalue += tempchordvalue; currentChordSalience.push_back(tempchordvalue); } if (sumchordvalue > 0) { @@ -511,11 +523,11 @@ count++; } - cerr << "done." << endl; + if (debug_on) cerr << "done." << endl; vector<Feature> oldnotes; - cerr << "[Chordino Plugin] HMM Chord Estimation ... "; + if (debug_on) cerr << "[Chordino Plugin] HMM Chord Estimation ... "; int oldchord = nChord-1; double selftransprob = 0.99; @@ -534,7 +546,6 @@ vector<double> scale; vector<int> chordpath = ViterbiPath(init, trans, chordogram, delta, &scale); - Feature chord_feature; // chord estimate chord_feature.hasTimestamp = true; chord_feature.timestamp = timestamps[0]; @@ -543,7 +554,6 @@ chordchange[0] = 0; for (int iFrame = 1; iFrame < (int)chordpath.size(); ++iFrame) { - // cerr << chordpath[iFrame] << endl; if (chordpath[iFrame] != oldchord ) { // chord Feature chord_feature; // chord estimate @@ -570,7 +580,11 @@ } /* calculating simple chord change prob */ for (int iChord = 0; iChord < nChord; iChord++) { - chordchange[iFrame-1] += delta[(iFrame-1)*nChord + iChord] * log(delta[(iFrame-1)*nChord + iChord]/delta[iFrame*nChord + iChord]); + double num = delta[(iFrame-1) * nChord + iChord]; + double denom = delta[iFrame * nChord + iChord]; + double eps = 1e-7; + if (denom < eps) denom = eps; + chordchange[iFrame-1] += num * log(num / denom + eps); } } @@ -596,19 +610,20 @@ fsOut[m_outputChordnotes].push_back(oldnotes[iNote]); } - cerr << "done." << endl; - + if (debug_on) cerr << "done." << endl; + for (int iFrame = 0; iFrame < nFrame; iFrame++) { Feature chordchange_feature; chordchange_feature.hasTimestamp = true; chordchange_feature.timestamp = timestamps[iFrame]; chordchange_feature.values.push_back(chordchange[iFrame]); - // cerr << chordchange[iFrame] << endl; +// cerr << "putting value " << chordchange[iFrame] << " at time " << chordchange_feature.timestamp << endl; fsOut[m_outputHarmonicChange].push_back(chordchange_feature); } + + free(delta); // for (int iFrame = 0; iFrame < nFrame; iFrame++) cerr << fsOut[m_outputHarmonicChange][iFrame].values[0] << endl; - return fsOut; }
--- a/Makefile.linux Thu Sep 05 17:30:38 2013 +0100 +++ b/Makefile.linux Mon Nov 02 11:32:30 2015 +0000 @@ -1,30 +1,29 @@ - -PLUGIN_LIBRARY_NAME = nnls-chroma - -PLUGIN_CODE_OBJECTS = chromamethods.o NNLSBase.o NNLSChroma.o Chordino.o Tuning.o plugins.o nnls.o viterbi.o - -VAMP_SDK_DIR = ../vamp-plugin-sdk - - -ARCHFLAGS = -O3 -ftree-vectorize -ffast-math -#ARCHFLAGS = -g - -CFLAGS = $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC -CXXFLAGS = $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC -PLUGIN_EXT = .so -PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) -LDFLAGS = -shared -Wl,-soname=$(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -Wl,--version-script=vamp-plugin.map - - -$(PLUGIN): $(PLUGIN_CODE_OBJECTS) - $(CXX) -o $@ $^ $(LDFLAGS) - -nnls.o: nnls.c # not nnls.f - -clean: - rm -f *.o - -# DO NOT DELETE + +PLUGIN_LIBRARY_NAME = nnls-chroma + +PLUGIN_CODE_OBJECTS = chromamethods.o NNLSBase.o NNLSChroma.o Chordino.o Tuning.o plugins.o nnls.o viterbi.o + +VAMP_SDK_DIR = ../vamp-plugin-sdk + +ARCHFLAGS = -O3 -ftree-vectorize -ffast-math +#ARCHFLAGS = -g + +CFLAGS += $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC +CXXFLAGS += $(ARCHFLAGS) -I$(VAMP_SDK_DIR) -Wall -fPIC +PLUGIN_EXT = .so +PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) +LDFLAGS += -shared -Wl,-soname=$(PLUGIN) -L$(VAMP_SDK_DIR) -lvamp-sdk -Wl,--version-script=vamp-plugin.map + + +$(PLUGIN): $(PLUGIN_CODE_OBJECTS) + $(CXX) -o $@ $^ $(LDFLAGS) + +nnls.o: nnls.c # not nnls.f + +clean: + rm -f *.o + +# DO NOT DELETE Chordino.o: Chordino.h NNLSBase.h chromamethods.h nnls.h viterbi.h chromamethods.o: chromamethods.h nnls.h
--- a/Makefile.mingw Thu Sep 05 17:30:38 2013 +0100 +++ b/Makefile.mingw Mon Nov 02 11:32:30 2015 +0000 @@ -5,23 +5,25 @@ VAMP_SDK_DIR = ../vamp-plugin-sdk -CC=gcc -CXX=g++ +# Allow the invoker to specify a particular set of tools through +# TOOLPREFIX, e.g. for cross-compile +CC=$(TOOLPREFIX)gcc +CXX=$(TOOLPREFIX)g++ OPTFLAGS = -O2 -ffast-math -CFLAGS = $(OPTFLAGS) -I$(VAMP_SDK_DIR) -Wall -CXXFLAGS = $(OPTFLAGS) -I$(VAMP_SDK_DIR) -I../boost_1_44_0 -Wall +CFLAGS += $(OPTFLAGS) -I$(VAMP_SDK_DIR) -Wall +CXXFLAGS += $(OPTFLAGS) -I$(VAMP_SDK_DIR) -I../boost_1_44_0 -Wall PLUGIN_EXT = .dll PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) -LDFLAGS = -shared -fno-exceptions -static-libgcc -Wl,-soname=$(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -Wl,--version-script=vamp-plugin.map +LDFLAGS += -shared -static -fno-exceptions -static-libgcc -Wl,-soname=$(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -Wl,--retain-symbols-file=vamp-plugin.list $(PLUGIN): $(PLUGIN_CODE_OBJECTS) $(CXX) -o $@ $^ $(LDFLAGS) clean: - del *.o + $(RM) *.o
--- a/Makefile.osx Thu Sep 05 17:30:38 2013 +0100 +++ b/Makefile.osx Mon Nov 02 11:32:30 2015 +0000 @@ -12,12 +12,12 @@ ## Uncomment these for an OS/X native build using command-line tools: -ARCHFLAGS = -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -mmacosx-version-min=10.5 -arch i386 -arch x86_64 -CFLAGS = $(ARCHFLAGS) -Wall -fPIC -g -O3 -CXXFLAGS = $(CFLAGS) -I$(VAMP_SDK_DIR) -I$(BOOST_ROOT) -I. +ARCHFLAGS ?= -isysroot /Developer/SDKs/MacOSX10.6.sdk -mmacosx-version-min=10.6 -arch i386 +CFLAGS += $(ARCHFLAGS) -Wall -fPIC -g -O3 +CXXFLAGS += $(CFLAGS) -I$(VAMP_SDK_DIR) -I$(BOOST_ROOT) PLUGIN_EXT = .dylib PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) -LDFLAGS = $(ARCHFLAGS) -dynamiclib -install_name $(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -exported_symbols_list vamp-plugin.list -framework Accelerate +LDFLAGS += $(ARCHFLAGS) -dynamiclib -install_name $(PLUGIN) $(VAMP_SDK_DIR)/libvamp-sdk.a -exported_symbols_list vamp-plugin.list -framework Accelerate $(PLUGIN): $(PLUGIN_CODE_OBJECTS)
--- a/NNLSBase.cpp Thu Sep 05 17:30:38 2013 +0100 +++ b/NNLSBase.cpp Mon Nov 02 11:32:30 2015 +0000 @@ -81,7 +81,7 @@ if (debug_on) cerr << "--> getPluginVersion" << endl; // Increment this each time you release a version that behaves // differently from the previous one - return 3; + return 5; } string @@ -267,6 +267,8 @@ void NNLSBase::setParameter(string identifier, float value) { +// cerr << "setParameter (" << identifier << ") -> " << value << endl; + if (debug_on) cerr << "--> setParameter" << endl; if (identifier == "useNNLS") { m_useNNLS = (int) value;
--- a/NNLSChroma.cpp Thu Sep 05 17:30:38 2013 +0100 +++ b/NNLSChroma.cpp Mon Nov 02 11:32:30 2015 +0000 @@ -84,6 +84,9 @@ int index = 0; + float featureRate = + (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + OutputDescriptor logfreqspecOutput; logfreqspecOutput.identifier = "logfreqspec"; logfreqspecOutput.name = "Log-Frequency Spectrum"; @@ -95,7 +98,7 @@ logfreqspecOutput.isQuantized = false; logfreqspecOutput.sampleType = OutputDescriptor::FixedSampleRate; logfreqspecOutput.hasDuration = false; - logfreqspecOutput.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + logfreqspecOutput.sampleRate = featureRate; list.push_back(logfreqspecOutput); m_outputLogfreqspec = index++; @@ -110,7 +113,7 @@ tunedlogfreqspecOutput.isQuantized = false; tunedlogfreqspecOutput.sampleType = OutputDescriptor::FixedSampleRate; tunedlogfreqspecOutput.hasDuration = false; - tunedlogfreqspecOutput.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + tunedlogfreqspecOutput.sampleRate = featureRate; list.push_back(tunedlogfreqspecOutput); m_outputTunedlogfreqspec = index++; @@ -125,7 +128,7 @@ semitonespectrumOutput.isQuantized = false; semitonespectrumOutput.sampleType = OutputDescriptor::FixedSampleRate; semitonespectrumOutput.hasDuration = false; - semitonespectrumOutput.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + semitonespectrumOutput.sampleRate = featureRate; list.push_back(semitonespectrumOutput); m_outputSemitonespectrum = index++; @@ -141,7 +144,7 @@ chromaOutput.isQuantized = false; chromaOutput.sampleType = OutputDescriptor::FixedSampleRate; chromaOutput.hasDuration = false; - chromaOutput.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + chromaOutput.sampleRate = featureRate; list.push_back(chromaOutput); m_outputChroma = index++; @@ -157,7 +160,7 @@ basschromaOutput.isQuantized = false; basschromaOutput.sampleType = OutputDescriptor::FixedSampleRate; basschromaOutput.hasDuration = false; - basschromaOutput.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + basschromaOutput.sampleRate = featureRate; list.push_back(basschromaOutput); m_outputBasschroma = index++; @@ -173,7 +176,7 @@ bothchromaOutput.isQuantized = false; bothchromaOutput.sampleType = OutputDescriptor::FixedSampleRate; bothchromaOutput.hasDuration = false; - bothchromaOutput.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + bothchromaOutput.sampleRate = featureRate; list.push_back(bothchromaOutput); m_outputBothchroma = index++; return list; @@ -244,7 +247,7 @@ calculate a tuned log-frequency spectrogram (f2): use the tuning estimated above (kinda f0) to perform linear interpolation on the existing log-frequency spectrogram (kinda f1). **/ - cerr << endl << "[NNLS Chroma Plugin] Tuning Log-Frequency Spectrogram ... "; + if (debug_on) cerr << endl << "[NNLS Chroma Plugin] Tuning Log-Frequency Spectrogram ... "; float tempValue = 0; @@ -294,7 +297,7 @@ fsOut[m_outputTunedlogfreqspec].push_back(f2); count++; } - cerr << "done." << endl; + if (debug_on) cerr << "done." << endl; /** Semitone spectrum and chromagrams Semitone-spaced log-frequency spectrum derived from the tuned log-freq spectrum above. the spectrum @@ -303,9 +306,9 @@ bass and treble stacked onto each other). **/ if (m_useNNLS == 0) { - cerr << "[NNLS Chroma Plugin] Mapping to semitone spectrum and chroma ... "; + if (debug_on) cerr << "[NNLS Chroma Plugin] Mapping to semitone spectrum and chroma ... "; } else { - cerr << "[NNLS Chroma Plugin] Performing NNLS and mapping to chroma ... "; + if (debug_on) cerr << "[NNLS Chroma Plugin] Performing NNLS and mapping to chroma ... "; } @@ -471,7 +474,7 @@ fsOut[m_outputBothchroma].push_back(f6); count++; } - cerr << "done." << endl; + if (debug_on) cerr << "done." << endl; return fsOut;
--- a/README Thu Sep 05 17:30:38 2013 +0100 +++ b/README Mon Nov 02 11:32:30 2015 +0000 @@ -78,5 +78,25 @@ ### References and Credits ### +If you make use of this software for any public or commercial purpose, +we ask you to kindly mention the authors and Queen Mary, University of +London in your user-visible documentation. We're very happy to see +this sort of use, but would much appreciate being credited, separately +from the requirements of the software license itself (see below). + +If you make use of this software for academic purposes, please cite: + Mauch, Matthias and Dixon, Simon: [*Approximate Note Transcription for the Improved Identification of Difficult Chords*](http://schall-und-mauch.de/artificialmusicality/?p=89), Proceedings of the 11th International Society for Music Information Retrieval Conference (ISMIR 2010), 2010. +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. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>.
--- a/Tuning.cpp Thu Sep 05 17:30:38 2013 +0100 +++ b/Tuning.cpp Mon Nov 02 11:32:30 2015 +0000 @@ -126,8 +126,8 @@ d10.maxValue = 452.89; d10.isQuantized = false; d10.sampleType = OutputDescriptor::FixedSampleRate; + d10.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; d10.hasDuration = false; - // d10.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; list.push_back(d10); m_outputLocalTuning = index++;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chordextract.cpp Mon Nov 02 11:32:30 2015 +0000 @@ -0,0 +1,149 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + NNLS-Chroma / Chordino + + Audio feature extraction plugins for chromagram and chord + estimation. + + Centre for Digital Music, Queen Mary University of London. + This file copyright 2014 QMUL. + + 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. +*/ + +/* + Extract chords from an audio file, read using libsndfile. Works by + constructing the plugin as a C++ class directly, and using plugin + adapters from the Vamp Host SDK to provide input. + + You can compile this with e.g. the following (Linux example): + + $ g++ -D_VAMP_PLUGIN_IN_HOST_NAMESPACE -O2 -ffast-math chordextract.cpp Chordino.cpp NNLSBase.cpp chromamethods.cpp viterbi.cpp nnls.c -o chordextract -lsndfile -lvamp-hostsdk -ldl + + But the same idea should work on any platform, so long as the Boost + Tokenizer headers and the Vamp Host SDK library are available and + the _VAMP_PLUGIN_IN_HOST_NAMESPACE preprocessor symbol is defined + throughout. +*/ + +#define _VAMP_PLUGIN_IN_HOST_NAMESPACE 1 + +#include <vamp-hostsdk/PluginInputDomainAdapter.h> +#include <vamp-hostsdk/PluginBufferingAdapter.h> + +#include "Chordino.h" + +#include <sndfile.h> + +#include <iostream> +#include <string> + +using namespace std; +using namespace Vamp; +using namespace Vamp::HostExt; + +int main(int argc, char **argv) +{ + const char *myname = argv[0]; + + if (argc != 2) { + cerr << "usage: " << myname << " file.wav" << endl; + return 2; + } + + const char *infile = argv[1]; + + SF_INFO sfinfo; + SNDFILE *sndfile = sf_open(infile, SFM_READ, &sfinfo); + + if (!sndfile) { + cerr << myname << ": Failed to open input file " << infile + << ": " << sf_strerror(sndfile) << endl; + return 1; + } + + Chordino *chordino = new Chordino(sfinfo.samplerate); + PluginInputDomainAdapter *ia = new PluginInputDomainAdapter(chordino); + ia->setProcessTimestampMethod(PluginInputDomainAdapter::ShiftData); + PluginBufferingAdapter *adapter = new PluginBufferingAdapter(ia); + + int blocksize = adapter->getPreferredBlockSize(); + + // Plugin requires 1 channel (we will mix down) + if (!adapter->initialise(1, blocksize, blocksize)) { + cerr << myname << ": Failed to initialise Chordino adapter!" << endl; + return 1; + } + + float *filebuf = new float[sfinfo.channels * blocksize]; + float *mixbuf = new float[blocksize]; + + Plugin::FeatureList chordFeatures; + Plugin::FeatureSet fs; + + int chordFeatureNo = -1; + Plugin::OutputList outputs = adapter->getOutputDescriptors(); + for (int i = 0; i < int(outputs.size()); ++i) { + if (outputs[i].identifier == "simplechord") { + chordFeatureNo = i; + } + } + if (chordFeatureNo < 0) { + cerr << myname << ": Failed to identify chords output!" << endl; + return 1; + } + + int frame = 0; + while (frame < sfinfo.frames) { + + int count = -1; + if ((count = sf_readf_float(sndfile, filebuf, blocksize)) <= 0) break; + + // mix down + for (int i = 0; i < blocksize; ++i) { + mixbuf[i] = 0.f; + if (i < count) { + for (int c = 0; c < sfinfo.channels; ++c) { + mixbuf[i] += filebuf[i * sfinfo.channels + c] / sfinfo.channels; + } + } + } + + RealTime timestamp = RealTime::frame2RealTime(frame, sfinfo.samplerate); + + // feed to plugin: can just take address of buffer, as only one channel + fs = adapter->process(&mixbuf, timestamp); + + chordFeatures.insert(chordFeatures.end(), + fs[chordFeatureNo].begin(), + fs[chordFeatureNo].end()); + + frame += count; + } + + sf_close(sndfile); + + // features at end of processing (actually Chordino does all its work here) + fs = adapter->getRemainingFeatures(); + + // chord output is output index 0 + chordFeatures.insert(chordFeatures.end(), + fs[chordFeatureNo].begin(), + fs[chordFeatureNo].end()); + + for (int i = 0; i < (int)chordFeatures.size(); ++i) { + cout << chordFeatures[i].timestamp.toString() << ": " + << chordFeatures[i].label << endl; + } + + delete[] filebuf; + delete[] mixbuf; + + delete adapter; +} +
--- a/chromamethods.cpp Thu Sep 05 17:30:38 2013 +0100 +++ b/chromamethods.cpp Mon Nov 02 11:32:30 2015 +0000 @@ -373,18 +373,19 @@ int ppathsize = static_cast<int>(ppath.size()); for (int i = 0; i < ppathsize; ++i) { chordDictFilename = ppath[i] + "/" + chordDictBase; - cerr << "Looking for chord.dict in " << chordDictFilename << "..." ; +// cerr << "Looking for chord.dict in " << chordDictFilename << "..." ; fstream fin; fin.open(chordDictFilename.c_str(),ios::in); if( fin.is_open() ) { fin.close(); - cerr << " success." << endl; +// cerr << " success." << endl; break; } else { - if (i+1 < ppathsize) cerr << " (not found yet) ..." << endl; - else { - cerr << "* WARNING: failed to find chord dictionary, using default chord dictionary." << endl; + if (i+1 < ppathsize) { +// cerr << " (not found yet) ..." << endl; + } else { +// cerr << "* WARNING: failed to find chord dictionary, using default chord dictionary." << endl; hasExternalDictinoary = false; } }
--- a/nnls-chroma.n3 Thu Sep 05 17:30:38 2013 +0100 +++ b/nnls-chroma.n3 Mon Nov 02 11:32:30 2015 +0000 @@ -6,46 +6,58 @@ @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/nnls-chromannls-chroma> . + foaf:primaryTopic <http://vamp-plugins.org/rdf/plugins/nnls-chroma> . + +:maker + foaf:name "Matthias Mauch" ; + foaf:logo <http://vamp-plugins.org/rdf/plugins/makers/qm.png> ; + foaf:page <http://c4dm.eecs.qmul.ac.uk/> . :nnls-chroma a vamp:PluginLibrary ; - vamp:identifier "nnls-chroma" ; + vamp:identifier "nnls-chroma" ; + dc:title "Chordino and NNLS Chroma" ; + dc:description "Harmony and chord extraction plugins by Matthias Mauch at C4DM" ; vamp:available_plugin plugbase:chordino ; vamp:available_plugin plugbase:nnls-chroma ; - vamp:available_plugin plugbase:tuning ; -# foaf:page <Place more-information HTML page URL here and uncomment> ; + vamp:available_plugin plugbase:tuning ; + foaf:page <http://www.isophonics.net/nnls-chroma> ; + doap:download-page <http://www.isophonics.net/nnls-chroma> ; + foaf:page <http://www.omras2.org/> ; + foaf:page <http://www.matthiasmauch.net/> ; + foaf:maker :maker ; + vamp:has_source true ; + vamp:has_binary "win32" ; + vamp:has_binary "osx" ; . plugbase:chordino a vamp:Plugin ; dc:title "Chordino" ; vamp:name "Chordino" ; - dc:description """Chordino provides a simple chord transcription based on NNLS Chroma (as in the NNLS Chroma plugin). Chord profiles given by the user in the file chord.dict are used to calculate frame-wise chord similarities. A simple (non-state-of-the-art!) algorithm smoothes these to provide a chord transcription using a standard HMM/Viterbi approach.""" ; - foaf:maker [ foaf:name "Matthias Mauch" ] ; # FIXME could give plugin author's URI here + dc:description """Chordino provides a simple chord transcription based on NNLS Chroma (as in the NNLS Chroma plugin). Chord profiles given by the user in the file chord.dict are used to calculate frame-wise chord similarities. Two simple (non-state-of-the-art!) algorithms are available that smooth these to provide a chord transcription: a simple chord change method, and a standard HMM/Viterbi approach.""" ; + foaf:maker :maker ; dc:rights """GPL""" ; # cc:license <Place plugin license URI here and uncomment> ; vamp:identifier "chordino" ; vamp:vamp_API_version vamp:api_version_2 ; - owl:versionInfo "3" ; + owl:versionInfo "1" ; vamp:input_domain vamp:FrequencyDomain ; vamp:parameter plugbase:chordino_param_useNNLS ; + vamp:parameter plugbase:chordino_param_useHMM ; vamp:parameter plugbase:chordino_param_rollon ; vamp:parameter plugbase:chordino_param_tuningmode ; vamp:parameter plugbase:chordino_param_whitening ; - vamp:parameter plugbase:chordino_param_spectralshape ; - vamp:parameter plugbase:chordino_param_boostn ; - vamp:parameter plugbase:chordino_param_usehartesyntax ; + vamp:parameter plugbase:chordino_param_s ; vamp:output plugbase:chordino_output_simplechord ; - vamp:output plugbase:chordino_output_chordnotes ; vamp:output plugbase:chordino_output_harmonicchange ; - vamp:output plugbase:chordino_output_loglikelihood ; . plugbase:chordino_param_useNNLS a vamp:QuantizedParameter ; vamp:identifier "useNNLS" ; @@ -58,10 +70,21 @@ vamp:default_value 1 ; vamp:value_names (); . +plugbase:chordino_param_useHMM a vamp:QuantizedParameter ; + vamp:identifier "useHMM" ; + dc:title "HMM (Viterbi decoding)" ; + dc:format "" ; + vamp:min_value 0 ; + vamp:max_value 1 ; + vamp:unit "" ; + vamp:quantize_step 1 ; + vamp:default_value 1 ; + vamp:value_names (); + . plugbase:chordino_param_rollon a vamp:QuantizedParameter ; vamp:identifier "rollon" ; - dc:title "bass noise threshold" ; - dc:format "%" ; + dc:title "spectral roll-on" ; + dc:format "" ; vamp:min_value 0 ; vamp:max_value 5 ; vamp:unit "%" ; @@ -90,8 +113,8 @@ vamp:default_value 1 ; vamp:value_names (); . -plugbase:chordino_param_spectralshape a vamp:Parameter ; - vamp:identifier "spectralshape" ; +plugbase:chordino_param_s a vamp:Parameter ; + vamp:identifier "s" ; dc:title "spectral shape" ; dc:format "" ; vamp:min_value 0.5 ; @@ -100,57 +123,18 @@ vamp:default_value 0.7 ; vamp:value_names (); . -plugbase:chordino_param_boostn a vamp:Parameter ; - vamp:identifier "boostn" ; - dc:title "boost N" ; - dc:format "" ; - vamp:min_value 0 ; - vamp:max_value 1 ; - vamp:unit "" ; - vamp:default_value 0.1 ; - vamp:value_names (); - . -plugbase:chordino_param_usehartesyntax a vamp:QuantizedParameter ; - vamp:identifier "usehartesyntax" ; - dc:title "use Harte syntax" ; - dc:format "" ; - vamp:min_value 0 ; - vamp:max_value 1 ; - vamp:unit "" ; - vamp:quantize_step 1 ; - vamp:default_value 0 ; - vamp:value_names ( "no" "yes"); - . plugbase:chordino_output_simplechord a vamp:SparseOutput ; vamp:identifier "simplechord" ; dc:title "Chord Estimate" ; - dc:description """Estimated chord times and labels.""" ; + dc:description """Estimated chord times and labels. Two simple (non-state-of-the-art!) algorithms are available that smooth these to provide a chord transcription: a simple chord change method, and a standard HMM/Viterbi approach.""" ; vamp:fixed_bin_count "true" ; - vamp:unit "" ; + vamp:unit "chord" ; + a vamp:QuantizedOutput ; + vamp:quantize_step 1 ; vamp:bin_count 0 ; vamp:sample_type vamp:VariableSampleRate ; vamp:sample_rate 21.5332 ; - vamp:computes_event_type af:ChordSegment ; -# vamp:computes_feature <Place feature attribute URI here and uncomment> ; -# vamp:computes_signal_type <Place signal type URI here and uncomment> ; - . -plugbase:chordino_output_chordnotes a vamp:SparseOutput ; - vamp:identifier "chordnotes" ; - dc:title "Note Representation of Chord Estimate" ; - dc:description """A simple represenation of the estimated chord with bass note (if applicable) and chord notes.""" ; - vamp:fixed_bin_count "true" ; - vamp:unit "MIDI units" ; - a vamp:QuantizedOutput ; - vamp:quantize_step 1 ; - a vamp:KnownExtentsOutput ; - vamp:min_value 0 ; - vamp:max_value 127 ; - vamp:bin_count 1 ; - vamp:sample_type vamp:VariableSampleRate ; - vamp:sample_rate 21.5332 ; - vamp:computes_event_type af:Note ; -# vamp:computes_feature <Place feature attribute URI here and uncomment> ; -# vamp:computes_signal_type <Place signal type URI here and uncomment> ; + vamp:computes_event_type af:ChordSegment ; . plugbase:chordino_output_harmonicchange a vamp:DenseOutput ; vamp:identifier "harmonicchange" ; @@ -158,32 +142,22 @@ dc:description """An indication of the likelihood of harmonic change. Depends on the chord dictionary. Calculation is different depending on whether the Viterbi algorithm is used for chord estimation, or the simple chord estimate.""" ; vamp:fixed_bin_count "true" ; vamp:unit "" ; + a vamp:KnownExtentsOutput ; + vamp:min_value 0 ; + vamp:max_value 0.999 ; 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> ; - . -plugbase:chordino_output_loglikelihood a vamp:DenseOutput ; - vamp:identifier "loglikelihood" ; - dc:title "Log-Likelihood of Chord Estimate" ; - dc:description """Logarithm of the likelihood value of the simple chord estimate.""" ; - 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> ; + vamp:computes_signal_type af:TonalChangeDetectionFunction; . plugbase:nnls-chroma a vamp:Plugin ; dc:title "NNLS Chroma" ; vamp:name "NNLS Chroma" ; dc:description """This plugin provides a number of features derived from a DFT-based log-frequency amplitude spectrum: some variants of the log-frequency spectrum, including a semitone spectrum derived from approximate transcription using the NNLS algorithm; and based on this semitone spectrum, different chroma features.""" ; - foaf:maker [ foaf:name "Matthias Mauch" ] ; # FIXME could give plugin author's URI here + foaf:maker :maker ; dc:rights """GPL""" ; # cc:license <Place plugin license URI here and uncomment> ; vamp:identifier "nnls-chroma" ; vamp:vamp_API_version vamp:api_version_2 ; - owl:versionInfo "3" ; + owl:versionInfo "1" ; vamp:input_domain vamp:FrequencyDomain ; @@ -214,8 +188,8 @@ . plugbase:nnls-chroma_param_rollon a vamp:QuantizedParameter ; vamp:identifier "rollon" ; - dc:title "bass noise threshold" ; - dc:format "%" ; + dc:title "spectral roll-on" ; + dc:format "" ; vamp:min_value 0 ; vamp:max_value 5 ; vamp:unit "%" ; @@ -272,9 +246,7 @@ vamp:fixed_bin_count "true" ; vamp:unit "" ; vamp:bin_count 256 ; -# 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> ; + vamp:computes_signal_type af:Spectrogram ; . plugbase:nnls-chroma_output_tunedlogfreqspec a vamp:DenseOutput ; vamp:identifier "tunedlogfreqspec" ; @@ -283,9 +255,7 @@ vamp:fixed_bin_count "true" ; vamp:unit "" ; vamp:bin_count 256 ; -# 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> ; + vamp:computes_signal_type af:Spectrogram ; . plugbase:nnls-chroma_output_semitonespectrum a vamp:DenseOutput ; vamp:identifier "semitonespectrum" ; @@ -294,9 +264,7 @@ 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> ; + vamp:computes_signal_type af:Spectrogram ; . plugbase:nnls-chroma_output_chroma a vamp:DenseOutput ; vamp:identifier "chroma" ; @@ -306,8 +274,6 @@ vamp:unit "" ; vamp:bin_count 12 ; vamp:bin_names ( "A" "Bb" "B" "C" "C#" "D" "Eb" "E" "F" "F#" "G" "Ab"); -# 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 af:Chromagram ; . plugbase:nnls-chroma_output_basschroma a vamp:DenseOutput ; @@ -318,8 +284,6 @@ vamp:unit "" ; vamp:bin_count 12 ; vamp:bin_names ( "A" "Bb" "B" "C" "C#" "D" "Eb" "E" "F" "F#" "G" "Ab"); -# 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 af:Chromagram ; . plugbase:nnls-chroma_output_bothchroma a vamp:DenseOutput ; @@ -330,20 +294,18 @@ vamp:unit "" ; vamp:bin_count 24 ; vamp:bin_names ( "A (bass)" "Bb (bass)" "B (bass)" "C (bass)" "C# (bass)" "D (bass)" "Eb (bass)" "E (bass)" "F (bass)" "F# (bass)" "G (bass)" "Ab (bass)" "A" "Bb" "B" "C" "C#" "D" "Eb" "E" "F" "F#" "G" "Ab"); -# 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 af:Chromagram ; . plugbase:tuning a vamp:Plugin ; dc:title "Tuning" ; vamp:name "Tuning" ; dc:description """The tuning plugin can estimate the local and global tuning of piece. The same tuning method is used for the NNLS Chroma and Chordino plugins.""" ; - foaf:maker [ foaf:name "Matthias Mauch" ] ; # FIXME could give plugin author's URI here + foaf:maker :maker ; dc:rights """GPL""" ; # cc:license <Place plugin license URI here and uncomment> ; vamp:identifier "tuning" ; vamp:vamp_API_version vamp:api_version_2 ; - owl:versionInfo "3" ; + owl:versionInfo "1" ; vamp:input_domain vamp:FrequencyDomain ; @@ -354,8 +316,8 @@ . plugbase:tuning_param_rollon a vamp:QuantizedParameter ; vamp:identifier "rollon" ; - dc:title "bass noise threshold" ; - dc:format "%" ; + dc:title "spectral roll-on" ; + dc:format "" ; vamp:min_value 0 ; vamp:max_value 5 ; vamp:unit "%" ; @@ -372,12 +334,10 @@ a vamp:KnownExtentsOutput ; vamp:min_value 427.47 ; vamp:max_value 452.89 ; - vamp:bin_count 1 ; + vamp:bin_count 0 ; vamp:sample_type vamp:VariableSampleRate ; - vamp:sample_rate 1.47994e-39 ; -# 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> ; + vamp:sample_rate 2.38221e-44 ; + vamp:computes_event_type af:MusicSegment; . plugbase:tuning_output_localtuning a vamp:DenseOutput ; vamp:identifier "localtuning" ;
--- a/viterbi.cpp Thu Sep 05 17:30:38 2013 +0100 +++ b/viterbi.cpp Mon Nov 02 11:32:30 2015 +0000 @@ -20,11 +20,14 @@ /* initialise first frame */ for (int iState = 0; iState < nState; ++iState) { delta[iState] = init[iState] * obs[0][iState]; +// cerr << "init[" << iState << "] = " << init[iState] << ", obs[0][" << iState << "] = " << obs[0][iState] << endl; deltasum += delta[iState]; } for (int iState = 0; iState < nState; ++iState) delta[iState] /= deltasum; // normalise (scale) scale->push_back(1.0/deltasum); psi.push_back(vector<int>(nState,0)); + +// cerr << "nState = " << nState << ", deltasum = " << deltasum << endl; /* rest of the forward step */ for (int iFrame = 1; iFrame < nFrame; ++iFrame) {