# HG changeset patch # User Chris Cannam # Date 1446467713 0 # Node ID d22f69c2b0259e22307ffe8613d81c5712218558 # Parent d95c4cdef8afd0a622239bf8d315caaf1249f9c3# Parent 5190d4947ad917bcd8e58556a173040f3d18b64a Merge new tag diff -r 5190d4947ad9 -r d22f69c2b025 .hgtags --- a/.hgtags Mon Nov 02 12:23:00 2015 +0000 +++ b/.hgtags Mon Nov 02 12:35:13 2015 +0000 @@ -1,4 +1,9 @@ 12fd1d3ccd6e0072fc4be295e7a1e383e84912a1 0.1 12fd1d3ccd6e0072fc4be295e7a1e383e84912a1 0.1 dab7e7bfeba17478fa6c5af050c6270026ad635b 0.2 +2cd99c0810f28abe2fcbf2c50a29fee20b910ae4 mirex2013 9d81703dcf6e6ac9f266b50a99dcc45448d381f9 v0.2.1 +9e9267d6d78a8e67f2a4dc1aac4ea1aab135f4f0 v1.0 +0a743c2dac6aa0eaa093d5291c697e51eac1035e v1.1 +0a743c2dac6aa0eaa093d5291c697e51eac1035e v1.1 +ba9310bcc3fcb3c58c99d25837b6f62662666b7d v1.1 diff -r 5190d4947ad9 -r d22f69c2b025 CITATION --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CITATION Mon Nov 02 12:35:13 2015 +0000 @@ -0,0 +1,6 @@ +@inproceedings{matthias2010a, + author = {Matthias Mauch and Simon Dixon}, + title = {Approximate Note Transcription for the Improved Identification of Difficult Chords}, + booktitle = {Proceedings of the 11th International Society for Music Information Retrieval Conference (ISMIR 2010)}, + year = {2010} +} diff -r 5190d4947ad9 -r d22f69c2b025 Chordino.cpp --- a/Chordino.cpp Mon Nov 02 12:23:00 2015 +0000 +++ b/Chordino.cpp Mon Nov 02 12:35:13 2015 +0000 @@ -36,8 +36,6 @@ m_chordnames(0) { if (debug_on) cerr << "--> Chordino" << endl; - // get the *chord* dictionary from file (if the file exists) - } Chordino::~Chordino() @@ -63,7 +61,7 @@ Chordino::getDescription() const { if (debug_on) cerr << "--> getDescription" << endl; - return "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."; + return "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 smooths these to provide a chord transcription using a standard HMM/Viterbi approach."; } Chordino::ParameterList @@ -72,89 +70,91 @@ if (debug_on) cerr << "--> getParameterDescriptors" << endl; ParameterList list; - ParameterDescriptor d; - d.identifier = "useNNLS"; - d.name = "use approximate transcription (NNLS)"; - d.description = "Toggles approximate transcription (NNLS)."; - d.unit = ""; - d.minValue = 0.0; - d.maxValue = 1.0; - d.defaultValue = 1.0; - d.isQuantized = true; - d.quantizeStep = 1.0; - list.push_back(d); + ParameterDescriptor useNNLSParam; + useNNLSParam.identifier = "useNNLS"; + useNNLSParam.name = "use approximate transcription (NNLS)"; + useNNLSParam.description = "Toggles approximate transcription (NNLS)."; + useNNLSParam.unit = ""; + useNNLSParam.minValue = 0.0; + useNNLSParam.maxValue = 1.0; + useNNLSParam.defaultValue = 1.0; + useNNLSParam.isQuantized = true; + useNNLSParam.quantizeStep = 1.0; + list.push_back(useNNLSParam); - ParameterDescriptor d4; - d4.identifier = "useHMM"; - d4.name = "HMM (Viterbi decoding)"; - d4.description = "Turns on Viterbi decoding (when off, the simple chord estimator is used)."; - d4.unit = ""; - d4.minValue = 0.0; - d4.maxValue = 1.0; - d4.defaultValue = 1.0; - d4.isQuantized = true; - d4.quantizeStep = 1.0; - list.push_back(d4); + ParameterDescriptor rollonParam; + rollonParam.identifier = "rollon"; + rollonParam.name = "bass noise threshold"; + rollonParam.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [bass noise threshold] x [total energy] will be set to 0. A threshold value of 0 means that no bins will be changed."; + rollonParam.unit = "%"; + rollonParam.minValue = 0; + rollonParam.maxValue = 5; + rollonParam.defaultValue = 0.0; + rollonParam.isQuantized = true; + rollonParam.quantizeStep = 0.5; + list.push_back(rollonParam); - ParameterDescriptor d0; - d0.identifier = "rollon"; - d0.name = "spectral roll-on"; - d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [spectral roll on] x [total energy] will be set to 0. A value of 0 means that no bins will be changed."; - d0.unit = "%"; - d0.minValue = 0; - d0.maxValue = 5; - d0.defaultValue = 0.0; - d0.isQuantized = true; - d0.quantizeStep = 0.5; - list.push_back(d0); + ParameterDescriptor tuningmodeParam; + tuningmodeParam.identifier = "tuningmode"; + tuningmodeParam.name = "tuning mode"; + tuningmodeParam.description = "Tuning can be performed locally or on the whole extraction segment. Local tuning is only advisable when the tuning is likely to change over the audio, for example in podcasts, or in a cappella singing."; + tuningmodeParam.unit = ""; + tuningmodeParam.minValue = 0; + tuningmodeParam.maxValue = 1; + tuningmodeParam.defaultValue = 0.0; + tuningmodeParam.isQuantized = true; + tuningmodeParam.valueNames.push_back("global tuning"); + tuningmodeParam.valueNames.push_back("local tuning"); + tuningmodeParam.quantizeStep = 1.0; + list.push_back(tuningmodeParam); - ParameterDescriptor d1; - d1.identifier = "tuningmode"; - d1.name = "tuning mode"; - d1.description = "Tuning can be performed locally or on the whole extraction segment. Local tuning is only advisable when the tuning is likely to change over the audio, for example in podcasts, or in a cappella singing."; - d1.unit = ""; - d1.minValue = 0; - d1.maxValue = 1; - d1.defaultValue = 0.0; - d1.isQuantized = true; - d1.valueNames.push_back("global tuning"); - d1.valueNames.push_back("local tuning"); - d1.quantizeStep = 1.0; - list.push_back(d1); + ParameterDescriptor whiteningParam; + whiteningParam.identifier = "whitening"; + whiteningParam.name = "spectral whitening"; + whiteningParam.description = "Spectral whitening: no whitening - 0; whitening - 1."; + whiteningParam.unit = ""; + whiteningParam.isQuantized = true; + whiteningParam.minValue = 0.0; + whiteningParam.maxValue = 1.0; + whiteningParam.defaultValue = 1.0; + whiteningParam.isQuantized = false; + list.push_back(whiteningParam); - ParameterDescriptor d2; - d2.identifier = "whitening"; - d2.name = "spectral whitening"; - d2.description = "Spectral whitening: no whitening - 0; whitening - 1."; - d2.unit = ""; - d2.isQuantized = true; - d2.minValue = 0.0; - d2.maxValue = 1.0; - d2.defaultValue = 1.0; - d2.isQuantized = false; - list.push_back(d2); + ParameterDescriptor spectralShapeParam; + 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 = ""; + spectralShapeParam.minValue = 0.5; + spectralShapeParam.maxValue = 0.9; + spectralShapeParam.defaultValue = 0.7; + spectralShapeParam.isQuantized = false; + list.push_back(spectralShapeParam); - ParameterDescriptor d3; - d3.identifier = "s"; - d3.name = "spectral shape"; - d3.description = "Determines how individual notes in the note dictionary look: higher values mean more dominant higher harmonics."; - d3.unit = ""; - d3.minValue = 0.5; - d3.maxValue = 0.9; - d3.defaultValue = 0.7; - d3.isQuantized = false; - list.push_back(d3); + ParameterDescriptor boostnParam; + boostnParam.identifier = "boostn"; + boostnParam.name = "boost N"; + boostnParam.description = "Boost likelihood of the N (no chord) label."; + boostnParam.unit = ""; + boostnParam.minValue = 0.0; + boostnParam.maxValue = 1.0; + boostnParam.defaultValue = 0.1; + boostnParam.isQuantized = false; + list.push_back(boostnParam); - ParameterDescriptor boostn; - boostn.identifier = "boostn"; - boostn.name = "boost N"; - boostn.description = "Boost likelihood of the N (no chord) label."; - boostn.unit = ""; - boostn.minValue = 0.0; - boostn.maxValue = 1.0; - boostn.defaultValue = 0.1; - boostn.isQuantized = false; - list.push_back(boostn); + ParameterDescriptor usehartesyntaxParam; + usehartesyntaxParam.identifier = "usehartesyntax"; + usehartesyntaxParam.name = "use Harte syntax"; + usehartesyntaxParam.description = "Use the chord syntax proposed by Harte"; + usehartesyntaxParam.unit = ""; + usehartesyntaxParam.minValue = 0.0; + usehartesyntaxParam.maxValue = 1.0; + usehartesyntaxParam.defaultValue = 0.0; + usehartesyntaxParam.isQuantized = true; + usehartesyntaxParam.quantizeStep = 1.0; + usehartesyntaxParam.valueNames.push_back("no"); + usehartesyntaxParam.valueNames.push_back("yes"); + list.push_back(usehartesyntaxParam); return list; } @@ -167,10 +167,13 @@ int index = 0; + float featureRate = + (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; + OutputDescriptor d7; d7.identifier = "simplechord"; d7.name = "Chord Estimate"; - d7.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."; + d7.description = "Estimated chord times and labels."; d7.unit = ""; d7.hasFixedBinCount = true; d7.binCount = 0; @@ -178,14 +181,14 @@ 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++; OutputDescriptor chordnotes; chordnotes.identifier = "chordnotes"; chordnotes.name = "Note Representation of Chord Estimate"; - chordnotes.description = "A simple represenation of the estimated chord with bass note (if applicable) and chord notes."; + chordnotes.description = "A simple representation of the estimated chord with bass note (if applicable) and chord notes."; chordnotes.unit = "MIDI units"; chordnotes.hasFixedBinCount = true; chordnotes.binCount = 1; @@ -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++; @@ -208,15 +211,28 @@ d8.hasFixedBinCount = true; d8.binCount = 1; d8.hasKnownExtents = false; - // d8.minValue = 0.0; - // d8.maxValue = 0.999; d8.isQuantized = false; d8.sampleType = OutputDescriptor::FixedSampleRate; + d8.sampleRate = featureRate; d8.hasDuration = false; - // d8.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; list.push_back(d8); m_outputHarmonicChange = index++; + OutputDescriptor loglikelihood; + loglikelihood.identifier = "loglikelihood"; + loglikelihood.name = "Log-Likelihood of Chord Estimate"; + loglikelihood.description = "Logarithm of the likelihood value of the simple chord estimate."; + loglikelihood.unit = ""; + loglikelihood.hasFixedBinCount = true; + loglikelihood.binCount = 1; + loglikelihood.hasKnownExtents = false; + loglikelihood.isQuantized = false; + loglikelihood.sampleType = OutputDescriptor::FixedSampleRate; + loglikelihood.sampleRate = featureRate; + loglikelihood.hasDuration = false; + list.push_back(loglikelihood); + m_outputLoglikelihood = index++; + return list; } @@ -230,7 +246,7 @@ if (!NNLSBase::initialise(channels, stepSize, blockSize)) { return false; } - m_chordnames = chordDictionary(&m_chorddict, &m_chordnotes, m_boostN); + m_chordnames = chordDictionary(&m_chorddict, &m_chordnotes, m_boostN, m_harte_syntax); return true; } @@ -284,12 +300,8 @@ 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 ... "; - float tempValue = 0; - float dbThreshold = 0; // relative to the background spectrum - float thresh = pow(10,dbThreshold/20); - // cerr << "tune local ? " << m_tuneLocal << endl; int count = 0; FeatureList tunedSpec; @@ -313,7 +325,7 @@ // cerr << intShift << " " << floatShift << endl; for (int k = 2; k < (int)currentLogSpectrum.values.size() - 3; ++k) { // interpolate all inner bins - tempValue = currentLogSpectrum.values[k + intShift] * (1-floatShift) + currentLogSpectrum.values[k+intShift+1] * floatShift; + float tempValue = currentLogSpectrum.values[k + intShift] * (1-floatShift) + currentLogSpectrum.values[k+intShift+1] * floatShift; currentTunedSpec.values.push_back(tempValue); } @@ -339,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 @@ -348,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 ... "; } @@ -361,7 +373,7 @@ FeatureList chromaList; - + bool clipwarned = false; for (FeatureList::iterator it = tunedSpec.begin(); it != tunedSpec.end(); ++it) { Feature currentTunedSpec = *it; // logfreq spectrum @@ -442,7 +454,7 @@ vector origchroma = chroma; chroma.insert(chroma.begin(), basschroma.begin(), basschroma.end()); // just stack the both chromas currentChromas.values = chroma; - + if (m_doNormalizeChroma > 0) { vector chromanorm = vector(3,0); switch (int(m_doNormalizeChroma)) { @@ -482,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) { @@ -504,234 +523,83 @@ count++; } - cerr << "done." << endl; + if (debug_on) cerr << "done." << endl; vector oldnotes; - // bool m_useHMM = true; // this will go into the chordino header file. - if (m_useHMM == 1.0) { - cerr << "[Chordino Plugin] HMM Chord Estimation ... "; - int oldchord = nChord-1; - double selftransprob = 0.99; - - // vector init = vector(nChord,1.0/nChord); - vector init = vector(nChord,0); init[nChord-1] = 1; - - double *delta; - delta = (double *)malloc(sizeof(double)*nFrame*nChord); - - vector > trans; - for (int iChord = 0; iChord < nChord; iChord++) { - vector temp = vector(nChord,(1-selftransprob)/(nChord-1)); - temp[iChord] = selftransprob; - trans.push_back(temp); - } - vector chordpath = ViterbiPath(init, trans, chordogram, delta); - - - Feature chord_feature; // chord estimate - chord_feature.hasTimestamp = true; - chord_feature.timestamp = timestamps[0]; - chord_feature.label = m_chordnames[chordpath[0]]; - fsOut[m_outputChords].push_back(chord_feature); - - 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 - chord_feature.hasTimestamp = true; - chord_feature.timestamp = timestamps[iFrame]; - chord_feature.label = m_chordnames[chordpath[iFrame]]; - fsOut[m_outputChords].push_back(chord_feature); - oldchord = chordpath[iFrame]; - // chord notes - for (int iNote = 0; iNote < (int)oldnotes.size(); ++iNote) { // finish duration of old chord - oldnotes[iNote].duration = oldnotes[iNote].duration + timestamps[iFrame]; - fsOut[m_outputChordnotes].push_back(oldnotes[iNote]); - } - oldnotes.clear(); - for (int iNote = 0; iNote < (int)m_chordnotes[chordpath[iFrame]].size(); ++iNote) { // prepare notes of current chord - Feature chordnote_feature; - chordnote_feature.hasTimestamp = true; - chordnote_feature.timestamp = timestamps[iFrame]; - chordnote_feature.values.push_back(m_chordnotes[chordpath[iFrame]][iNote]); - chordnote_feature.hasDuration = true; - chordnote_feature.duration = -timestamps[iFrame]; // this will be corrected at the next chord - oldnotes.push_back(chordnote_feature); - } + if (debug_on) cerr << "[Chordino Plugin] HMM Chord Estimation ... "; + int oldchord = nChord-1; + double selftransprob = 0.99; + + // vector init = vector(nChord,1.0/nChord); + vector init = vector(nChord,0); init[nChord-1] = 1; + + double *delta; + delta = (double *)malloc(sizeof(double)*nFrame*nChord); + + vector > trans; + for (int iChord = 0; iChord < nChord; iChord++) { + vector temp = vector(nChord,(1-selftransprob)/(nChord-1)); + temp[iChord] = selftransprob; + trans.push_back(temp); + } + vector scale; + vector chordpath = ViterbiPath(init, trans, chordogram, delta, &scale); + + Feature chord_feature; // chord estimate + chord_feature.hasTimestamp = true; + chord_feature.timestamp = timestamps[0]; + chord_feature.label = m_chordnames[chordpath[0]]; + fsOut[m_outputChords].push_back(chord_feature); + + chordchange[0] = 0; + for (int iFrame = 1; iFrame < (int)chordpath.size(); ++iFrame) { + if (chordpath[iFrame] != oldchord ) { + // chord + Feature chord_feature; // chord estimate + chord_feature.hasTimestamp = true; + chord_feature.timestamp = timestamps[iFrame]; + chord_feature.label = m_chordnames[chordpath[iFrame]]; + fsOut[m_outputChords].push_back(chord_feature); + oldchord = chordpath[iFrame]; + // chord notes + for (int iNote = 0; iNote < (int)oldnotes.size(); ++iNote) { // finish duration of old chord + oldnotes[iNote].duration = oldnotes[iNote].duration + timestamps[iFrame]; + fsOut[m_outputChordnotes].push_back(oldnotes[iNote]); } - /* 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]); + oldnotes.clear(); + for (int iNote = 0; iNote < (int)m_chordnotes[chordpath[iFrame]].size(); ++iNote) { // prepare notes of current chord + Feature chordnote_feature; + chordnote_feature.hasTimestamp = true; + chordnote_feature.timestamp = timestamps[iFrame]; + chordnote_feature.values.push_back(m_chordnotes[chordpath[iFrame]][iNote]); + chordnote_feature.hasDuration = true; + chordnote_feature.duration = -timestamps[iFrame]; // this will be corrected at the next chord + oldnotes.push_back(chordnote_feature); } } - - // cerr << chordpath[0] << endl; - } else { - /* Simple chord estimation - I just take the local chord estimates ("currentChordSalience") and average them over time, then - take the maximum. Very simple, don't do this at home... - */ - cerr << "[Chordino Plugin] Simple Chord Estimation ... "; - count = 0; - int halfwindowlength = m_inputSampleRate / m_stepSize; - vector chordSequence; - for (vector::iterator it = timestamps.begin(); it != timestamps.end(); ++it) { // initialise the score chordogram - vector temp = vector(nChord,0); - scoreChordogram.push_back(temp); - } - for (vector::iterator it = timestamps.begin(); it < timestamps.end()-2*halfwindowlength-1; ++it) { - int startIndex = count + 1; - int endIndex = count + 2 * halfwindowlength; - - float chordThreshold = 2.5/nChord;//*(2*halfwindowlength+1); - - vector chordCandidates; - for (int iChord = 0; iChord+1 < nChord; iChord++) { - // float currsum = 0; - // for (int iFrame = startIndex; iFrame < endIndex; ++iFrame) { - // currsum += chordogram[iFrame][iChord]; - // } - // if (currsum > chordThreshold) chordCandidates.push_back(iChord); - for (int iFrame = startIndex; iFrame < endIndex; ++iFrame) { - if (chordogram[iFrame][iChord] > chordThreshold) { - chordCandidates.push_back(iChord); - break; - } - } - } - chordCandidates.push_back(nChord-1); - // cerr << chordCandidates.size() << endl; - - float maxval = 0; // will be the value of the most salient *chord change* in this frame - float maxindex = 0; //... and the index thereof - int bestchordL = nChord-1; // index of the best "left" chord - int bestchordR = nChord-1; // index of the best "right" chord - - for (int iWF = 1; iWF < 2*halfwindowlength; ++iWF) { - // now find the max values on both sides of iWF - // left side: - float maxL = 0; - int maxindL = nChord-1; - for (int kChord = 0; kChord < (int)chordCandidates.size(); kChord++) { - int iChord = chordCandidates[kChord]; - float currsum = 0; - for (int iFrame = 0; iFrame < iWF-1; ++iFrame) { - currsum += chordogram[count+iFrame][iChord]; - } - if (iChord == nChord-1) currsum *= 0.8; - if (currsum > maxL) { - maxL = currsum; - maxindL = iChord; - } - } - // right side: - float maxR = 0; - int maxindR = nChord-1; - for (int kChord = 0; kChord < (int)chordCandidates.size(); kChord++) { - int iChord = chordCandidates[kChord]; - float currsum = 0; - for (int iFrame = iWF-1; iFrame < 2*halfwindowlength; ++iFrame) { - currsum += chordogram[count+iFrame][iChord]; - } - if (iChord == nChord-1) currsum *= 0.8; - if (currsum > maxR) { - maxR = currsum; - maxindR = iChord; - } - } - if (maxL+maxR > maxval) { - maxval = maxL+maxR; - maxindex = iWF; - bestchordL = maxindL; - bestchordR = maxindR; - } - - } - // cerr << "maxindex: " << maxindex << ", bestchordR is " << bestchordR << ", of frame " << count << endl; - // add a score to every chord-frame-point that was part of a maximum - for (int iFrame = 0; iFrame < maxindex-1; ++iFrame) { - scoreChordogram[iFrame+count][bestchordL]++; - } - for (int iFrame = maxindex-1; iFrame < 2*halfwindowlength; ++iFrame) { - scoreChordogram[iFrame+count][bestchordR]++; - } - if (bestchordL != bestchordR) { - chordchange[maxindex+count] += (halfwindowlength - abs(maxindex-halfwindowlength)) * 2.0 / halfwindowlength; - } - count++; - } - // cerr << "******* agent finished *******" << endl; - count = 0; - for (vector::iterator it = timestamps.begin(); it != timestamps.end(); ++it) { - float maxval = 0; // will be the value of the most salient chord in this frame - float maxindex = 0; //... and the index thereof - for (int iChord = 0; iChord < nChord; iChord++) { - if (scoreChordogram[count][iChord] > maxval) { - maxval = scoreChordogram[count][iChord]; - maxindex = iChord; - // cerr << iChord << endl; - } - } - chordSequence.push_back(maxindex); - count++; - } - - - // mode filter on chordSequence - count = 0; - string oldChord = ""; - for (vector::iterator it = timestamps.begin(); it != timestamps.end(); ++it) { - Feature chord_feature; // chord estimate - chord_feature.hasTimestamp = true; - chord_feature.timestamp = *it; - // Feature currentChord; // chord estimate - // currentChord.hasTimestamp = true; - // currentChord.timestamp = currentChromas.timestamp; - - vector chordCount = vector(nChord,0); - int maxChordCount = 0; - int maxChordIndex = nChord-1; - string maxChord; - int startIndex = max(count - halfwindowlength/2,0); - int endIndex = min(int(chordogram.size()), count + halfwindowlength/2); - for (int i = startIndex; i < endIndex; i++) { - chordCount[chordSequence[i]]++; - if (chordCount[chordSequence[i]] > maxChordCount) { - // cerr << "start index " << startIndex << endl; - maxChordCount++; - maxChordIndex = chordSequence[i]; - maxChord = m_chordnames[maxChordIndex]; - } - } - // chordSequence[count] = maxChordIndex; - // cerr << maxChordIndex << endl; - // cerr << chordchange[count] << endl; - if (oldChord != maxChord) { - oldChord = maxChord; - chord_feature.label = m_chordnames[maxChordIndex]; - fsOut[m_outputChords].push_back(chord_feature); - for (int iNote = 0; iNote < (int)oldnotes.size(); ++iNote) { // finish duration of old chord - oldnotes[iNote].duration = oldnotes[iNote].duration + chord_feature.timestamp; - fsOut[m_outputChordnotes].push_back(oldnotes[iNote]); - } - oldnotes.clear(); - for (int iNote = 0; iNote < (int)m_chordnotes[maxChordIndex].size(); ++iNote) { // prepare notes of current chord - Feature chordnote_feature; - chordnote_feature.hasTimestamp = true; - chordnote_feature.timestamp = chord_feature.timestamp; - chordnote_feature.values.push_back(m_chordnotes[maxChordIndex][iNote]); - chordnote_feature.hasDuration = true; - chordnote_feature.duration = -chord_feature.timestamp; // this will be corrected at the next chord - oldnotes.push_back(chordnote_feature); - } - } - count++; + /* calculating simple chord change prob */ + for (int iChord = 0; iChord < 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); } } - Feature chord_feature; // last chord estimate + + float logscale = 0; + for (int iFrame = 0; iFrame < nFrame; ++iFrame) { + logscale -= log(scale[iFrame]); + Feature loglikelihood; + loglikelihood.hasTimestamp = true; + loglikelihood.timestamp = timestamps[iFrame]; + loglikelihood.values.push_back(-log(scale[iFrame])); + // cerr << chordchange[iFrame] << endl; + fsOut[m_outputLoglikelihood].push_back(loglikelihood); + } + logscale /= nFrame; + chord_feature.hasTimestamp = true; chord_feature.timestamp = timestamps[timestamps.size()-1]; chord_feature.label = "N"; @@ -742,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; } diff -r 5190d4947ad9 -r d22f69c2b025 Chordino.h --- a/Chordino.h Mon Nov 02 12:23:00 2015 +0000 +++ b/Chordino.h Mon Nov 02 12:35:13 2015 +0000 @@ -48,6 +48,7 @@ mutable int m_outputChords; mutable int m_outputChordnotes; mutable int m_outputHarmonicChange; + mutable int m_outputLoglikelihood; vector m_chorddict; vector > m_chordnotes; vector m_chordnames; diff -r 5190d4947ad9 -r d22f69c2b025 Makefile.linux --- a/Makefile.linux Mon Nov 02 12:23:00 2015 +0000 +++ b/Makefile.linux Mon Nov 02 12:35:13 2015 +0000 @@ -1,39 +1,34 @@ - -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 - -nnls.o: nnls.h -Chordino.o: Chordino.h NNLSBase.h chromamethods.h nnls.h -chromamethods.o: chromamethods.h nnls.h chorddict.cpp -NNLSBase.o: NNLSBase.h chromamethods.h nnls.h -NNLSChroma.o: NNLSChroma.h NNLSBase.h chromamethods.h nnls.h -plugins.o: NNLSChroma.h NNLSBase.h Chordino.h Tuning.h -Tuning.o: Tuning.h NNLSBase.h chromamethods.h nnls.h -Chordino.o: NNLSBase.h -chromamethods.o: nnls.h -NNLSChroma.o: NNLSBase.h -Tuning.o: NNLSBase.h + +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 +NNLSBase.o: NNLSBase.h chromamethods.h nnls.h +NNLSChroma.o: NNLSChroma.h NNLSBase.h chromamethods.h nnls.h +plugins.o: NNLSChroma.h NNLSBase.h Chordino.h Tuning.h +Tuning.o: Tuning.h NNLSBase.h chromamethods.h nnls.h +viterbi.o: viterbi.h diff -r 5190d4947ad9 -r d22f69c2b025 Makefile.mingw --- a/Makefile.mingw Mon Nov 02 12:23:00 2015 +0000 +++ b/Makefile.mingw Mon Nov 02 12:35:13 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 diff -r 5190d4947ad9 -r d22f69c2b025 Makefile.osx --- a/Makefile.osx Mon Nov 02 12:23:00 2015 +0000 +++ b/Makefile.osx Mon Nov 02 12:35:13 2015 +0000 @@ -8,16 +8,16 @@ # project directory # VAMP_SDK_DIR = ../vamp-plugin-sdk -BOOST_ROOT = ../boost_1_44_0 +BOOST_ROOT = ../boost_1_48_0 ## Uncomment these for an OS/X native build using command-line tools: -ARCHFLAGS = -isysroot /Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 -arch i386 -CFLAGS = $(ARCHFLAGS) -Wall -fPIC -g -CXXFLAGS = $(CFLAGS) -I$(VAMP_SDK_DIR) -I$(BOOST_ROOT) +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) @@ -32,7 +32,7 @@ nnls.o: nnls.h Chordino.o: Chordino.h NNLSBase.h chromamethods.h nnls.h -chromamethods.o: chromamethods.h nnls.h chorddict.cpp +chromamethods.o: chromamethods.h nnls.h NNLSBase.o: NNLSBase.h chromamethods.h nnls.h NNLSChroma.o: NNLSChroma.h NNLSBase.h chromamethods.h nnls.h plugins.o: NNLSChroma.h NNLSBase.h Chordino.h Tuning.h diff -r 5190d4947ad9 -r d22f69c2b025 NNLSBase.cpp --- a/NNLSBase.cpp Mon Nov 02 12:23:00 2015 +0000 +++ b/NNLSBase.cpp Mon Nov 02 12:35:13 2015 +0000 @@ -26,7 +26,7 @@ #include -const bool debug_on = false; +static bool debug_on = false; NNLSBase::NNLSBase(float inputSampleRate) : Plugin(inputSampleRate), @@ -40,7 +40,6 @@ m_whitening(1.0), m_preset(0.0), m_useNNLS(1.0), - m_useHMM(1.0), m_localTuning(0.0), m_kernelValue(0), m_kernelFftIndex(0), @@ -51,13 +50,14 @@ m_rollon(0.0), m_boostN(0.1), m_s(0.7), + m_harte_syntax(0), sinvalues(0), cosvalues(0) { if (debug_on) cerr << "--> NNLSBase" << endl; // make the *note* dictionary matrix m_dict = new float[nNote * 84]; - for (unsigned i = 0; i < nNote * 84; ++i) m_dict[i] = 0.0; + for (int i = 0; i < nNote * 84; ++i) m_dict[i] = 0.0; } @@ -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 @@ -152,8 +152,8 @@ ParameterDescriptor d0; d0.identifier = "rollon"; - d0.name = "spectral roll-on"; - d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [spectral roll on] x [total energy] will be set to 0. A value of 0 means that no bins will be changed."; + d0.name = "bass noise threshold"; + d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [bass noise threshold] x [total energy] will be set to 0. A threshold value of 0 means that no bins will be changed."; d0.unit = "%"; d0.minValue = 0; d0.maxValue = 5; @@ -256,10 +256,10 @@ return m_doNormalizeChroma; } - if (identifier == "useHMM") { - return m_useHMM; - } - + if (identifier == "usehartesyntax") { + return m_harte_syntax; + } + return 0; } @@ -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; @@ -280,10 +282,6 @@ m_s = value; } - if (identifier == "useHMM") { - m_useHMM = value; - } - if (identifier == "boostn") { m_boostN = value; } @@ -318,6 +316,10 @@ if (identifier == "rollon") { m_rollon = value; } + + if (identifier == "usehartesyntax") { + m_harte_syntax = value; + } } NNLSBase::ProgramList @@ -395,7 +397,7 @@ m_kernelNoteIndex.clear(); int countNonzero = 0; for (int iNote = 0; iNote < nNote; ++iNote) { // I don't know if this is wise: manually making a sparse matrix - for (int iFFT = 0; iFFT < blockSize/2; ++iFFT) { + for (int iFFT = 0; iFFT < static_cast(blockSize/2); ++iFFT) { if (tempkernel[iFFT + blockSize/2 * iNote] > 0) { m_kernelValue.push_back(tempkernel[iFFT + blockSize/2 * iNote]); if (tempkernel[iFFT + blockSize/2 * iNote] > 0) { @@ -446,7 +448,7 @@ float energysum = 0; // make magnitude float maxmag = -10000; - for (size_t iBin = 0; iBin < m_blockSize/2; iBin++) { + for (int iBin = 0; iBin < static_cast(m_blockSize/2); iBin++) { magnitude[iBin] = sqrt(fbuf[2 * iBin] * fbuf[2 * iBin] + fbuf[2 * iBin + 1] * fbuf[2 * iBin + 1]); if (magnitude[iBin]>m_blockSize*1.0) magnitude[iBin] = m_blockSize; // a valid audio signal (between -1 and 1) should not be limited here. @@ -458,16 +460,16 @@ float cumenergy = 0; if (m_rollon > 0) { - for (size_t iBin = 2; iBin < m_blockSize/2; iBin++) { + for (int iBin = 2; iBin < static_cast(m_blockSize/2); iBin++) { cumenergy += pow(magnitude[iBin],2); if (cumenergy < energysum * m_rollon / 100) magnitude[iBin-2] = 0; else break; } } - if (maxmag < 2) { + if (maxmag < m_blockSize * 2.0 / 16384.0) { // this is not quite right, I think // cerr << "timestamp " << timestamp << ": very low magnitude, setting magnitude to all zeros" << endl; - for (size_t iBin = 0; iBin < m_blockSize/2; iBin++) { + for (int iBin = 0; iBin < static_cast(m_blockSize/2); iBin++) { magnitude[iBin] = 0; } } diff -r 5190d4947ad9 -r d22f69c2b025 NNLSBase.h --- a/NNLSBase.h Mon Nov 02 12:23:00 2015 +0000 +++ b/NNLSBase.h Mon Nov 02 12:35:13 2015 +0000 @@ -65,7 +65,6 @@ float m_whitening; float m_preset; float m_useNNLS; - float m_useHMM; vector m_localTuning; vector m_kernelValue; vector m_kernelFftIndex; @@ -76,6 +75,7 @@ float m_rollon; float m_boostN; float m_s; + float m_harte_syntax; vector hw; vector sinvalues; vector cosvalues; diff -r 5190d4947ad9 -r d22f69c2b025 NNLSChroma.cpp --- a/NNLSChroma.cpp Mon Nov 02 12:23:00 2015 +0000 +++ b/NNLSChroma.cpp Mon Nov 02 12:35:13 2015 +0000 @@ -67,6 +67,12 @@ OutputList list; // Make chroma names for the binNames property + + const char* notenames[24] = { + "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"}; + + vector chromanames; vector bothchromanames; for (int iNote = 0; iNote < 24; iNote++) { @@ -78,114 +84,101 @@ int index = 0; - OutputDescriptor d1; - d1.identifier = "logfreqspec"; - d1.name = "Log-Frequency Spectrum"; - d1.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping."; - d1.unit = ""; - d1.hasFixedBinCount = true; - d1.binCount = nNote; - d1.hasKnownExtents = false; - d1.isQuantized = false; - d1.sampleType = OutputDescriptor::FixedSampleRate; - d1.hasDuration = false; - d1.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - list.push_back(d1); - m_outputLogSpec = index++; + float featureRate = + (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - OutputDescriptor d2; - d2.identifier = "tunedlogfreqspec"; - d2.name = "Tuned Log-Frequency Spectrum"; - d2.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping, then its tuned using the estimated tuning frequency."; - d2.unit = ""; - d2.hasFixedBinCount = true; - d2.binCount = nNote; - d2.hasKnownExtents = false; - d2.isQuantized = false; - d2.sampleType = OutputDescriptor::FixedSampleRate; - d2.hasDuration = false; - d2.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - list.push_back(d2); - m_outputTunedSpec = index++; + OutputDescriptor logfreqspecOutput; + logfreqspecOutput.identifier = "logfreqspec"; + logfreqspecOutput.name = "Log-Frequency Spectrum"; + logfreqspecOutput.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping."; + logfreqspecOutput.unit = ""; + logfreqspecOutput.hasFixedBinCount = true; + logfreqspecOutput.binCount = nNote; + logfreqspecOutput.hasKnownExtents = false; + logfreqspecOutput.isQuantized = false; + logfreqspecOutput.sampleType = OutputDescriptor::FixedSampleRate; + logfreqspecOutput.hasDuration = false; + logfreqspecOutput.sampleRate = featureRate; + list.push_back(logfreqspecOutput); + m_outputLogfreqspec = index++; + + OutputDescriptor tunedlogfreqspecOutput; + tunedlogfreqspecOutput.identifier = "tunedlogfreqspec"; + tunedlogfreqspecOutput.name = "Tuned Log-Frequency Spectrum"; + tunedlogfreqspecOutput.description = "A Log-Frequency Spectrum (constant Q) that is obtained by cosine filter mapping, then its tuned using the estimated tuning frequency."; + tunedlogfreqspecOutput.unit = ""; + tunedlogfreqspecOutput.hasFixedBinCount = true; + tunedlogfreqspecOutput.binCount = nNote; + tunedlogfreqspecOutput.hasKnownExtents = false; + tunedlogfreqspecOutput.isQuantized = false; + tunedlogfreqspecOutput.sampleType = OutputDescriptor::FixedSampleRate; + tunedlogfreqspecOutput.hasDuration = false; + tunedlogfreqspecOutput.sampleRate = featureRate; + list.push_back(tunedlogfreqspecOutput); + m_outputTunedlogfreqspec = index++; - OutputDescriptor d3; - d3.identifier = "semitonespectrum"; - d3.name = "Semitone Spectrum"; - d3.description = "A semitone-spaced log-frequency spectrum derived from the third-of-a-semitone-spaced tuned log-frequency spectrum."; - d3.unit = ""; - d3.hasFixedBinCount = true; - d3.binCount = 84; - d3.hasKnownExtents = false; - d3.isQuantized = false; - d3.sampleType = OutputDescriptor::FixedSampleRate; - d3.hasDuration = false; - d3.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - list.push_back(d3); - m_outputSemiSpec = index++; + OutputDescriptor semitonespectrumOutput; + semitonespectrumOutput.identifier = "semitonespectrum"; + semitonespectrumOutput.name = "Semitone Spectrum"; + semitonespectrumOutput.description = "A semitone-spaced log-frequency spectrum derived from the third-of-a-semitone-spaced tuned log-frequency spectrum."; + semitonespectrumOutput.unit = ""; + semitonespectrumOutput.hasFixedBinCount = true; + semitonespectrumOutput.binCount = 84; + semitonespectrumOutput.hasKnownExtents = false; + semitonespectrumOutput.isQuantized = false; + semitonespectrumOutput.sampleType = OutputDescriptor::FixedSampleRate; + semitonespectrumOutput.hasDuration = false; + semitonespectrumOutput.sampleRate = featureRate; + list.push_back(semitonespectrumOutput); + m_outputSemitonespectrum = index++; - OutputDescriptor d4; - d4.identifier = "chroma"; - d4.name = "Chromagram"; - d4.description = "Tuning-adjusted chromagram from NNLS approximate transcription, with an emphasis on the medium note range."; - d4.unit = ""; - d4.hasFixedBinCount = true; - d4.binCount = 12; - d4.binNames = chromanames; - d4.hasKnownExtents = false; - d4.isQuantized = false; - d4.sampleType = OutputDescriptor::FixedSampleRate; - d4.hasDuration = false; - d4.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - list.push_back(d4); + OutputDescriptor chromaOutput; + chromaOutput.identifier = "chroma"; + chromaOutput.name = "Chromagram"; + chromaOutput.description = "Tuning-adjusted chromagram from NNLS approximate transcription, with an emphasis on the medium note range."; + chromaOutput.unit = ""; + chromaOutput.hasFixedBinCount = true; + chromaOutput.binCount = 12; + chromaOutput.binNames = chromanames; + chromaOutput.hasKnownExtents = false; + chromaOutput.isQuantized = false; + chromaOutput.sampleType = OutputDescriptor::FixedSampleRate; + chromaOutput.hasDuration = false; + chromaOutput.sampleRate = featureRate; + list.push_back(chromaOutput); m_outputChroma = index++; - OutputDescriptor d5; - d5.identifier = "basschroma"; - d5.name = "Bass Chromagram"; - d5.description = "Tuning-adjusted bass chromagram from NNLS approximate transcription, with an emphasis on the bass note range."; - d5.unit = ""; - d5.hasFixedBinCount = true; - d5.binCount = 12; - d5.binNames = chromanames; - d5.hasKnownExtents = false; - d5.isQuantized = false; - d5.sampleType = OutputDescriptor::FixedSampleRate; - d5.hasDuration = false; - d5.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - list.push_back(d5); - m_outputBassChroma = index++; + OutputDescriptor basschromaOutput; + basschromaOutput.identifier = "basschroma"; + basschromaOutput.name = "Bass Chromagram"; + basschromaOutput.description = "Tuning-adjusted bass chromagram from NNLS approximate transcription, with an emphasis on the bass note range."; + basschromaOutput.unit = ""; + basschromaOutput.hasFixedBinCount = true; + basschromaOutput.binCount = 12; + basschromaOutput.binNames = chromanames; + basschromaOutput.hasKnownExtents = false; + basschromaOutput.isQuantized = false; + basschromaOutput.sampleType = OutputDescriptor::FixedSampleRate; + basschromaOutput.hasDuration = false; + basschromaOutput.sampleRate = featureRate; + list.push_back(basschromaOutput); + m_outputBasschroma = index++; - OutputDescriptor d6; - d6.identifier = "bothchroma"; - d6.name = "Chromagram and Bass Chromagram"; - d6.description = "Tuning-adjusted chromagram and bass chromagram (stacked on top of each other) from NNLS approximate transcription."; - d6.unit = ""; - d6.hasFixedBinCount = true; - d6.binCount = 24; - d6.binNames = bothchromanames; - d6.hasKnownExtents = false; - d6.isQuantized = false; - d6.sampleType = OutputDescriptor::FixedSampleRate; - d6.hasDuration = false; - d6.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - list.push_back(d6); - m_outputBothChroma = index++; - - OutputDescriptor d7; - d7.identifier = "consonance"; - d7.name = "Consonance estimate."; - d7.description = "A simple consonance value based on the convolution of a consonance profile with the semitone spectrum."; - d7.unit = ""; - d7.hasFixedBinCount = true; - d7.binCount = 1; - d7.hasKnownExtents = false; - d7.isQuantized = false; - d7.sampleType = OutputDescriptor::FixedSampleRate; - d7.hasDuration = false; - d7.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize; - list.push_back(d7); - m_outputConsonance = index++; - + OutputDescriptor bothchromaOutput; + bothchromaOutput.identifier = "bothchroma"; + bothchromaOutput.name = "Chromagram and Bass Chromagram"; + bothchromaOutput.description = "Tuning-adjusted chromagram and bass chromagram (stacked on top of each other) from NNLS approximate transcription."; + bothchromaOutput.unit = ""; + bothchromaOutput.hasFixedBinCount = true; + bothchromaOutput.binCount = 24; + bothchromaOutput.binNames = bothchromanames; + bothchromaOutput.hasKnownExtents = false; + bothchromaOutput.isQuantized = false; + bothchromaOutput.sampleType = OutputDescriptor::FixedSampleRate; + bothchromaOutput.hasDuration = false; + bothchromaOutput.sampleRate = featureRate; + list.push_back(bothchromaOutput); + m_outputBothchroma = index++; return list; } @@ -219,29 +212,18 @@ NNLSBase::baseProcess(inputBuffers, timestamp); FeatureSet fs; - fs[m_outputLogSpec].push_back(m_logSpectrum[m_logSpectrum.size()-1]); + fs[m_outputLogfreqspec].push_back(m_logSpectrum[m_logSpectrum.size()-1]); return fs; } NNLSChroma::FeatureSet NNLSChroma::getRemainingFeatures() { - static const int nConsonance = 24; - float consonancepattern[nConsonance] = {0,-1,-1,1,1,1,-1,1,1,1,-1,-1,1,-1,-1,1,1,1,-1,1,1,1,-1,-1}; - float consonancemean = 0; - for (int i = 0; i< nConsonance; ++i) { - consonancemean += consonancepattern[i]/nConsonance; - } - cerr << "consonancemean = " << consonancemean << endl; - - for (int i = 0; i< nConsonance; ++i) { - consonancepattern[i] -= consonancemean; - } - if (debug_on) cerr << "--> getRemainingFeatures" << endl; + if (debug_on) cerr << "--> getRemainingFeatures" << endl; FeatureSet fsOut; if (m_logSpectrum.size() == 0) return fsOut; - // + /** Calculate Tuning calculate tuning from (using the angle of the complex number defined by the cumulative mean real and imag values) @@ -260,19 +242,15 @@ char buffer0 [50]; sprintf(buffer0, "estimated tuning: %0.1f Hz", cumulativetuning); - - // cerr << "normalisedtuning: " << normalisedtuning << '\n'; - + /** Tune Log-Frequency Spectrogram 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; - float dbThreshold = 0; // relative to the background spectrum - float thresh = pow(10,dbThreshold/20); - // cerr << "tune local ? " << m_tuneLocal << endl; + int count = 0; @@ -291,7 +269,7 @@ // cerr << intShift << " " << floatShift << endl; - for (unsigned k = 2; k < f1.values.size() - 3; ++k) { // interpolate all inner bins + for (int k = 2; k < (int)f1.values.size() - 3; ++k) { // interpolate all inner bins tempValue = f1.values[k + intShift] * (1-floatShift) + f1.values[k+intShift+1] * floatShift; f2.values.push_back(tempValue); } @@ -316,10 +294,10 @@ cerr << "ERROR: negative value in logfreq spectrum" << endl; } } - fsOut[m_outputTunedSpec].push_back(f2); + 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 @@ -328,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 ... "; } @@ -338,13 +316,12 @@ vector oldbasschroma = vector(12,0); count = 0; - for (FeatureList::iterator it = fsOut[m_outputTunedSpec].begin(); it != fsOut[m_outputTunedSpec].end(); ++it) { + for (FeatureList::iterator it = fsOut[m_outputTunedlogfreqspec].begin(); it != fsOut[m_outputTunedlogfreqspec].end(); ++it) { Feature f2 = *it; // logfreq spectrum Feature f3; // semitone spectrum Feature f4; // treble chromagram Feature f5; // bass chromagram Feature f6; // treble and bass chromagram - Feature consonance; f3.hasTimestamp = true; f3.timestamp = f2.timestamp; @@ -358,9 +335,6 @@ f6.hasTimestamp = true; f6.timestamp = f2.timestamp; - consonance.hasTimestamp = true; - consonance.timestamp = f2.timestamp; - float b[nNote]; bool some_b_greater_zero = false; @@ -379,11 +353,11 @@ vector chroma = vector(12, 0); vector basschroma = vector(12, 0); float currval; - unsigned iSemitone = 0; + int iSemitone = 0; if (some_b_greater_zero) { if (m_useNNLS == 0) { - for (unsigned iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) { + for (int iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) { currval = 0; for (int iBPS = -nBPS/2; iBPS < nBPS/2+1; ++iBPS) { currval += b[iNote + iBPS] * (1-abs(iBPS*1.0/(nBPS/2+1))); @@ -400,7 +374,7 @@ vector signifIndex; int index=0; sumb /= 84.0; - for (unsigned iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) { + for (int iNote = nBPS/2 + 2; iNote < nNote - nBPS/2; iNote += nBPS) { float currval = 0; for (int iBPS = -nBPS/2; iBPS < nBPS/2+1; ++iBPS) { currval += b[iNote + iBPS]; @@ -435,19 +409,7 @@ for (int i = 0; i < 84; ++i) f3.values.push_back(0); } - float notesum = 0; - - consonance.values.push_back(0); - for (int iSemitone = 0; iSemitone < 84-24; ++iSemitone) { - notesum += f3.values[iSemitone] * f3.values[iSemitone] * treblewindow[iSemitone] * treblewindow[iSemitone]; - float tempconsonance = 0; - for (int jSemitone = 1; jSemitone < 24; ++jSemitone) { - tempconsonance += f3.values[iSemitone+jSemitone] * (consonancepattern[jSemitone]) * treblewindow[iSemitone+jSemitone]; - } - consonance.values[0] += (f3.values[iSemitone] * tempconsonance * treblewindow[iSemitone]); - } - if (notesum > 0) consonance.values[0] /= notesum; - + f4.values = chroma; f5.values = basschroma; chroma.insert(chroma.begin(), basschroma.begin(), basschroma.end()); // just stack the both chromas @@ -490,30 +452,29 @@ break; } if (chromanorm[0] > 0) { - for (size_t i = 0; i < f4.values.size(); i++) { + for (int i = 0; i < (int)f4.values.size(); i++) { f4.values[i] /= chromanorm[0]; } } if (chromanorm[1] > 0) { - for (size_t i = 0; i < f5.values.size(); i++) { + for (int i = 0; i < (int)f5.values.size(); i++) { f5.values[i] /= chromanorm[1]; } } if (chromanorm[2] > 0) { - for (size_t i = 0; i < f6.values.size(); i++) { + for (int i = 0; i < (int)f6.values.size(); i++) { f6.values[i] /= chromanorm[2]; } } } - fsOut[m_outputSemiSpec].push_back(f3); + fsOut[m_outputSemitonespectrum].push_back(f3); fsOut[m_outputChroma].push_back(f4); - fsOut[m_outputBassChroma].push_back(f5); - fsOut[m_outputBothChroma].push_back(f6); - fsOut[m_outputConsonance].push_back(consonance); + fsOut[m_outputBasschroma].push_back(f5); + fsOut[m_outputBothchroma].push_back(f6); count++; } - cerr << "done." << endl; + if (debug_on) cerr << "done." << endl; return fsOut; diff -r 5190d4947ad9 -r d22f69c2b025 NNLSChroma.h --- a/NNLSChroma.h Mon Nov 02 12:23:00 2015 +0000 +++ b/NNLSChroma.h Mon Nov 02 12:35:13 2015 +0000 @@ -44,13 +44,12 @@ void reset(); protected: - mutable int m_outputLogSpec; - mutable int m_outputTunedSpec; - mutable int m_outputSemiSpec; + mutable int m_outputLogfreqspec; + mutable int m_outputTunedlogfreqspec; + mutable int m_outputSemitonespectrum; mutable int m_outputChroma; - mutable int m_outputBassChroma; - mutable int m_outputBothChroma; - mutable int m_outputConsonance; + mutable int m_outputBasschroma; + mutable int m_outputBothchroma; }; diff -r 5190d4947ad9 -r d22f69c2b025 README --- a/README Mon Nov 02 12:23:00 2015 +0000 +++ b/README Mon Nov 02 12:35:13 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 . diff -r 5190d4947ad9 -r d22f69c2b025 Tuning.cpp --- a/Tuning.cpp Mon Nov 02 12:23:00 2015 +0000 +++ b/Tuning.cpp Mon Nov 02 12:35:13 2015 +0000 @@ -76,8 +76,8 @@ ParameterDescriptor d0; d0.identifier = "rollon"; - d0.name = "spectral roll-on"; - d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [spectral roll on] x [total energy] will be set to 0. A value of 0 means that no bins will be changed."; + d0.name = "bass noise threshold"; + d0.description = "Consider the cumulative energy spectrum (from low to high frequencies). All bins below the first bin whose cumulative energy exceeds the quantile [bass noise threshold] x [total energy] will be set to 0. A threshold value of 0 means that no bins will be changed."; d0.unit = "%"; d0.minValue = 0; d0.maxValue = 5; @@ -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++; diff -r 5190d4947ad9 -r d22f69c2b025 chord.dict --- a/chord.dict Mon Nov 02 12:23:00 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -### Comma-Separated Chord Dictionaries -# -# field 1 is chord type name, -# fields 2-25 indicate whether a pitch class is present (1) or not (0) : -# - fields 2-13 correspond to bass pitch classes A through Ab -# - fields 14-25 correspond to chord pitch classes A through Ab - -### Advanced Learners Chord Dictionary -=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 -=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 -m=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 -m=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 -dim7=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0 -dim7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0 -6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0 -7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 -maj7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1 -m7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0 -m6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0 -=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 -=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 -dim=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0 -aug=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 -=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 -=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 -7=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 -# sus4=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0 - -### Rock'n'Roll -# :1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 -# m:1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 diff -r 5190d4947ad9 -r d22f69c2b025 chord.dictold --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chord.dictold Mon Nov 02 12:35:13 2015 +0000 @@ -0,0 +1,31 @@ +### Comma-Separated Chord Dictionaries +# +# field 1 is chord type name, +# fields 2-25 indicate whether a pitch class is present (1) or not (0) : +# - fields 2-13 correspond to bass pitch classes A through Ab +# - fields 14-25 correspond to chord pitch classes A through Ab + +### Advanced Learners Chord Dictionary +=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 +=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 +m=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 +m=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 +dim7=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0 +dim7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0 +6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0 +7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 +maj7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1 +m7=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0 +m6=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0 +=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 +=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 +dim=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0 +aug=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 +=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 +=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 +7=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 +# sus4=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0 + +### Rock'n'Roll +# :1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 +# m:1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 diff -r 5190d4947ad9 -r d22f69c2b025 chorddict.cpp --- a/chorddict.cpp Mon Nov 02 12:23:00 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,297 +0,0 @@ - -// #include -const int nChorddict = 2904; -const char* chordtypes[] = {"", "", "", "", "", "", "", "", "", "", "", "", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/3", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", "/5", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj6", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":maj7", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":min", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":min7", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":dim", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ":aug", ""}; - -const float chorddict[] = - {0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.235702, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.471405, 0.000000, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.208514, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.417029, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.000000, 0.208514, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.417029, 0.000000, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.417029, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.417029, -0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.417029, -0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, -0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, -0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.417029, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, -0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, -0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.417029, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, -0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, -0.208514, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, -0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.208514, 0.000000, 0.417029, 0.000000, 0.000000, -0.417029, 0.000000, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.417029, -0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, 0.000000, 0.208514, 0.000000, 0.000000, -0.208514, 0.000000, 0.417029, 0.000000, 0.000000, 0.417029, 0.000000, 0.000000, 0.000000, 0.417029, -0.000000, 0.000000, 0.417029, 0.000000, 0.417029, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.235702, -0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.235702, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.471405, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.000000, 0.000000, 0.471405, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, -0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, -0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.000000, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.235702, -0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, -0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.000000, -0.235702, 0.000000, 0.000000, 0.000000, 0.235702, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, -0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, 0.471405, 0.000000, 0.000000, 0.000000, -0.471405, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, 0.129099, -0.129099, 0.129099, 0.129099, 0.258199, 0.258199, 0.258199, 0.258199, 0.258199, 0.258199, 0.258199, -0.258199, 0.258199, 0.258199, 0.258199, 0.258199}; \ No newline at end of file diff -r 5190d4947ad9 -r d22f69c2b025 chordextract.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chordextract.cpp Mon Nov 02 12:35:13 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 +#include + +#include "Chordino.h" + +#include + +#include +#include + +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; +} + diff -r 5190d4947ad9 -r d22f69c2b025 chromamethods.cpp --- a/chromamethods.cpp Mon Nov 02 12:23:00 2015 +0000 +++ b/chromamethods.cpp Mon Nov 02 12:35:13 2015 +0000 @@ -31,16 +31,16 @@ #include #include -#include "chorddict.cpp" - using namespace std; using namespace boost; /** Special Convolution - special convolution is as long as the convolvee, i.e. the first argument. in the valid core part of the - convolution it contains the usual convolution values, but the pads at the beginning (ending) have the same values - as the first (last) valid convolution bin. + Special convolution is as long as the convolvee, i.e. the first argument. + In the "valid" core part of the convolution it contains the usual convolution + values, but the parts at the beginning (ending) that would normally be + calculated using zero padding simply have the same values as the first + (last) valid convolution bin. **/ vector SpecialConvolution(vector convolvee, vector kernel) @@ -71,15 +71,6 @@ return Z; } -// vector FftBin2Frequency(vector binnumbers, int fs, int blocksize) -// { -// vector freq(binnumbers.size, 0.0); -// for (unsigned i = 0; i < binnumbers.size; ++i) { -// freq[i] = (binnumbers[i]-1.0) * fs * 1.0 / blocksize; -// } -// return freq; -// } - float cospuls(float x, float centre, float width) { float recipwidth = 1.0/width; @@ -103,7 +94,13 @@ return out; } +/** + * Calculates a matrix that can be used to linearly map from the magnitude spectrum to a pitch-scale spectrum. + * @return this always returns true, which is a bit stupid, really. The main purpose of the function is to change the values in the "matrix" pointed to by *outmatrix + */ bool logFreqMatrix(int fs, int blocksize, float *outmatrix) { + // TODO: rewrite so that everyone understands what is done here. + // TODO: make this more general, such that it works with all minoctave, maxoctave and whatever nBPS (or check if it already does) int binspersemitone = nBPS; int minoctave = 0; // this must be 0 @@ -128,8 +125,6 @@ int maxMIDI = 21 + maxoctave * 12; // this includes one additional semitone! vector cq_f; float oob = 1.0/binspersemitone; // one over binspersemitone - // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI-69))); // 0.083333 is approx 1/12 - // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI+oob-69))); for (int i = minMIDI; i < maxMIDI; ++i) { for (int k = 0; k < binspersemitone; ++k) { cq_f.push_back(440 * pow(2.0,0.083333333333 * (i+oob*k-69))); @@ -146,6 +141,10 @@ fft_activation.push_back(cosp); // cerr << cosp << endl; } + + for (int i = 0; i < nFFT * (int)cq_f.size(); ++i) { + outmatrix[i] = 0.f; + } float cq_activation; for (int iFFT = 1; iFFT < nFFT; ++iFFT) { @@ -153,52 +152,45 @@ int curr_start = oversampling * iFFT - oversampling; int curr_end = oversampling * iFFT + oversampling; // don't know if I should add "+1" here // cerr << oversampled_f[curr_start] << " " << fft_f[iFFT] << " " << oversampled_f[curr_end] << endl; - for (unsigned iCQ = 0; iCQ < cq_f.size(); ++iCQ) { - outmatrix[iFFT + nFFT * iCQ] = 0; + for (int iCQ = 0; iCQ < (int)cq_f.size(); ++iCQ) { if (cq_f[iCQ] * pow(2.0, 0.084) + fft_width > fft_f[iFFT] && cq_f[iCQ] * pow(2.0, -0.084 * 2) - fft_width < fft_f[iFFT]) { // within a generous neighbourhood for (int iOS = curr_start; iOS < curr_end; ++iOS) { cq_activation = pitchCospuls(oversampled_f[iOS],cq_f[iCQ],binspersemitone*12); // cerr << oversampled_f[iOS] << " " << cq_f[iCQ] << " " << cq_activation << endl; outmatrix[iFFT + nFFT * iCQ] += cq_activation * fft_activation[iOS-curr_start]; } - // if (iCQ == 1 || iCQ == 2) { - // cerr << " " << outmatrix[iFFT + nFFT * iCQ] << endl; - // } - } + } } } return true; } void dictionaryMatrix(float* dm, float s_param) { + // TODO: make this more general, such that it works with all minoctave, maxoctave and even more than one note per semitone int binspersemitone = nBPS; int minoctave = 0; // this must be 0 int maxoctave = 7; // this must be 7 - // float s_param = 0.7; // pitch-spaced frequency vector int minMIDI = 21 + minoctave * 12 - 1; // this includes one additional semitone! int maxMIDI = 21 + maxoctave * 12; // this includes one additional semitone! vector cq_f; float oob = 1.0/binspersemitone; // one over binspersemitone - // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI-69))); // 0.083333 is approx 1/12 - // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI+oob-69))); for (int i = minMIDI; i < maxMIDI; ++i) { for (int k = 0; k < binspersemitone; ++k) { cq_f.push_back(440 * pow(2.0,0.083333333333 * (i+oob*k-69))); } } - // cq_f.push_back(440 * pow(2.0,0.083333 * (minMIDI-oob-69))); cq_f.push_back(440 * pow(2.0,0.083333 * (maxMIDI-69))); - float curr_f; +// float curr_f; float floatbin; float curr_amp; // now for every combination calculate the matrix element for (int iOut = 0; iOut < 12 * (maxoctave - minoctave); ++iOut) { // cerr << iOut << endl; for (int iHarm = 1; iHarm <= 20; ++iHarm) { - curr_f = 440 * pow(2,(minMIDI-69+iOut)*1.0/12) * iHarm; +// curr_f = 440 * pow(2,(minMIDI-69+iOut)*1.0/12) * iHarm; // if (curr_f > cq_f[nNote-1]) break; floatbin = ((iOut + 1) * binspersemitone + 1) + binspersemitone * 12 * log2(iHarm); // cerr << floatbin << endl; @@ -212,8 +204,6 @@ } } } - - } static @@ -285,8 +275,8 @@ chordnames.push_back("");// =0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 chordnames.push_back("m");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 chordnames.push_back("m");//=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 - chordnames.push_back("dim7");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0 - chordnames.push_back("dim7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0 + chordnames.push_back("m7b5");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0 + chordnames.push_back("m7b5");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0 chordnames.push_back("6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0 chordnames.push_back("7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 chordnames.push_back("maj7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1 @@ -294,11 +284,30 @@ chordnames.push_back("m6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0 chordnames.push_back("");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 chordnames.push_back("");//=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 - chordnames.push_back("");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0 + chordnames.push_back("dim");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0 chordnames.push_back("aug");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 chordnames.push_back("");//=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 chordnames.push_back("");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 chordnames.push_back("7");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 + // from here: Harte syntax + chordnames.push_back("");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 + chordnames.push_back("");// =0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 + chordnames.push_back(":min");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 + chordnames.push_back(":min");//=0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0 + chordnames.push_back(":hdim7");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,1,0 + chordnames.push_back(":hdim7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0 + chordnames.push_back(":maj6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0 + chordnames.push_back(":7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 + chordnames.push_back(":maj7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1 + chordnames.push_back(":min7");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0 + chordnames.push_back(":min6");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0 + chordnames.push_back("");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 + chordnames.push_back("");//=0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 + chordnames.push_back(":dim");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0 + chordnames.push_back(":aug");//=1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 + chordnames.push_back("");//=0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0 + chordnames.push_back("");//=0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0 + chordnames.push_back(":7");//=0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0 return chordnames; } @@ -330,7 +339,7 @@ return chordvalues; } -vector chordDictionary(vector *mchorddict, vector > *m_chordnotes, float boostN) { +vector chordDictionary(vector *mchorddict, vector > *m_chordnotes, float boostN, float harte_syntax) { typedef tokenizer > Tok; char_separator sep(",; ","="); @@ -340,22 +349,43 @@ vector ppath = getPluginPath(); + const char* notenames[24] = { + "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"}; + + const char* bassnames[13][12] ={ + {"A","","B","C","C#","D","","E","","F#","G","G#"}, + {"Bb","","C","Db","D","Eb","","F","","G","Ab","A"}, + {"B","","C#","D","D#","E","","F#","","G#","A","A#"}, + {"C","","D","Eb","E","F","","G","","A","Bb","B"}, + {"C#","","D#","E","E#","F#","","G#","","A#","B","B#"}, + {"D","","E","F","F#","G","","A","","B","C","C#"}, + {"Eb","","F","Gb","G","Ab","","Bb","","C","Db","D"}, + {"E","","F#","G","G#","A","","B","","C#","D","D#"}, + {"F","","G","Ab","A","Bb","","C","","D","Eb","E"}, + {"F#","","G#","A","A#","B","","C#","","D#","E","E#"}, + {"G","","A","Bb","B","C","","D","","E","F","F#"}, + {"Ab","","Bb","Cb","C","Db","","Eb","","F","Gb","G"}, + {"1","","2","b3","3","4","","5","","6","b7","7"} + }; + bool hasExternalDictinoary = true; - - for (size_t i = 0; i < ppath.size(); ++i) { + int ppathsize = static_cast(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 < ppath.size()) 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; } } @@ -366,12 +396,17 @@ // int iElement = 0; int nChord = 0; + vector tempChordDict = staticChordvalues(); vector tempChordNames = staticChordnames(); - vector tempChordDict = staticChordvalues(); + if (harte_syntax == 1.0) { + tempChordNames.erase(tempChordNames.begin(),tempChordNames.begin()+tempChordNames.size()/2); + } else { + tempChordNames.erase(tempChordNames.begin()+tempChordNames.size()/2,tempChordNames.begin()+tempChordNames.size()); + } + vector loadedChordNames; vector loadedChordDict; if (hasExternalDictinoary && chordDictFile.is_open()) { - cerr << "-----------------> " << tempChordNames.size() << endl; tempChordDict.clear(); tempChordNames.clear(); while (std::getline(chordDictFile, line)) { // loop over lines in chord.dict file @@ -398,6 +433,7 @@ tempChordNames.push_back(chordType); } } + cerr << "-----------------> " << tempChordNames.size() << endl; } @@ -409,7 +445,11 @@ string slashNotation = ""; for (int kSemitone = 1; kSemitone < 12; kSemitone++) { if (tempChordDict[24*iType+(kSemitone) % 12] > 0.99) { - slashNotation = bassnames[iSemitone][kSemitone]; + if (harte_syntax == 0.0) { + slashNotation = bassnames[iSemitone][kSemitone]; + } else { + slashNotation = bassnames[12][kSemitone]; + } } } if (slashNotation=="") tempchordnotes.push_back(MIDI_basenote + (iSemitone+12) % 12); @@ -448,8 +488,8 @@ // N type loadedChordNames.push_back("N"); - for (unsigned kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(0.5); - for (unsigned kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(1.0); + for (int kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(0.5); + for (int kSemitone = 0; kSemitone < 12; kSemitone++) loadedChordDict.push_back(1.0); vector tempchordvector; m_chordnotes->push_back(tempchordvector); float exponent = 2.0; diff -r 5190d4947ad9 -r d22f69c2b025 chromamethods.h --- a/chromamethods.h Mon Nov 02 12:23:00 2015 +0000 +++ b/chromamethods.h Mon Nov 02 12:35:13 2015 +0000 @@ -29,28 +29,9 @@ extern std::vector SpecialConvolution(std::vector convolvee, std::vector kernel); extern void dictionaryMatrix(float* dm, float s_param); -extern std::vector chordDictionary(std::vector *mchorddict, std::vector > *m_chordnotes, float boostN); +extern std::vector chordDictionary(std::vector *mchorddict, std::vector > *m_chordnotes, float boostN, float harte_syntax); extern bool logFreqMatrix(int fs, int blocksize, float *outmatrix); -static const char* notenames[24] = { - "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"}; - -static const char* bassnames[12][12] ={ - {"A","","B","C","C#","D","","E","","F#","G","G#"}, - {"Bb","","C","Db","D","Eb","","F","","G","Ab","A"}, - {"B","","C#","D","D#","E","","F#","","G#","A","A#"}, - {"C","","D","Eb","E","F","","G","","A","Bb","B"}, - {"C#","","D#","E","E#","F#","","G#","","A#","B","B#"}, - {"D","","E","F","F#","G","","A","","B","C","C#"}, - {"Eb","","F","Gb","G","Ab","","Bb","","C","Db","D"}, - {"E","","F#","G","G#","A","","B","","C#","D","D#"}, - {"F","","G","Ab","A","Bb","","C","","D","Eb","E"}, - {"F#","","G#","A","A#","B","","C#","","D#","E","E#"}, - {"G","","A","Bb","B","C","","D","","E","F","F#"}, - {"Ab","","Bb","Cb","C","Db","","Eb","","F","Gb","G"} -}; - static const float basswindow[] = {0.001769, 0.015848, 0.043608, 0.084265, 0.136670, 0.199341, 0.270509, 0.348162, 0.430105, 0.514023, 0.597545, 0.678311, 0.754038, 0.822586, 0.882019, 0.930656, 0.967124, 0.990393, 0.999803, 0.995091, 0.976388, 0.944223, 0.899505, 0.843498, 0.777785, 0.704222, 0.624888, 0.542025, 0.457975, 0.375112, 0.295778, 0.222215, 0.156502, 0.100495, 0.055777, 0.023612, 0.004909, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000}; static const float treblewindow[] = {0.000350, 0.003144, 0.008717, 0.017037, 0.028058, 0.041719, 0.057942, 0.076638, 0.097701, 0.121014, 0.146447, 0.173856, 0.203090, 0.233984, 0.266366, 0.300054, 0.334860, 0.370590, 0.407044, 0.444018, 0.481304, 0.518696, 0.555982, 0.592956, 0.629410, 0.665140, 0.699946, 0.733634, 0.766016, 0.796910, 0.826144, 0.853553, 0.878986, 0.902299, 0.923362, 0.942058, 0.958281, 0.971942, 0.982963, 0.991283, 0.996856, 0.999650, 0.999650, 0.996856, 0.991283, 0.982963, 0.971942, 0.958281, 0.942058, 0.923362, 0.902299, 0.878986, 0.853553, 0.826144, 0.796910, 0.766016, 0.733634, 0.699946, 0.665140, 0.629410, 0.592956, 0.555982, 0.518696, 0.481304, 0.444018, 0.407044, 0.370590, 0.334860, 0.300054, 0.266366, 0.233984, 0.203090, 0.173856, 0.146447, 0.121014, 0.097701, 0.076638, 0.057942, 0.041719, 0.028058, 0.017037, 0.008717, 0.003144, 0.000350}; diff -r 5190d4947ad9 -r d22f69c2b025 nnls-chroma.n3 --- a/nnls-chroma.n3 Mon Nov 02 12:23:00 2015 +0000 +++ b/nnls-chroma.n3 Mon Nov 02 12:35:13 2015 +0000 @@ -6,6 +6,7 @@ @prefix dc: . @prefix af: . @prefix foaf: . +@prefix doap: . @prefix cc: . @prefix : <#> . @@ -13,21 +14,33 @@ foaf:maker ; foaf:primaryTopic . +:maker + foaf:name "Matthias Mauch" ; + foaf:logo ; + foaf:page . + :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 ; + doap:download-page ; foaf:page ; foaf:page ; + 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. 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 [ foaf:name "Matthias Mauch" ] ; # FIXME could give plugin author's URI here + foaf:maker :maker ; dc:rights """GPL""" ; # cc:license ; vamp:identifier "chordino" ; @@ -42,10 +55,8 @@ vamp:parameter plugbase:chordino_param_tuningmode ; vamp:parameter plugbase:chordino_param_whitening ; vamp:parameter plugbase:chordino_param_s ; - vamp:parameter plugbase:chordino_param_boostn ; vamp:output plugbase:chordino_output_simplechord ; - vamp:output plugbase:chordino_output_chordnotes ; vamp:output plugbase:chordino_output_harmonicchange ; . plugbase:chordino_param_useNNLS a vamp:QuantizedParameter ; @@ -111,16 +122,6 @@ vamp:unit "" ; vamp:default_value 0.7 ; vamp:value_names (); - -plugbase:chordino_param_boostn a vamp:Parameter ; - vamp:identifier "boostn" ; - dc:title "Boost likelihood of the N (no chord) label." ; - dc:format "" ; - vamp:min_value 0 ; - vamp:max_value 1 ; - vamp:unit "" ; - vamp:default_value 0.1 ; - vamp:value_names (); . plugbase:chordino_output_simplechord a vamp:SparseOutput ; vamp:identifier "simplechord" ; @@ -134,21 +135,6 @@ vamp:sample_type vamp:VariableSampleRate ; vamp:sample_rate 21.5332 ; vamp:computes_event_type af:ChordSegment ; - -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:computes_event_type af:Note ; . plugbase:chordino_output_harmonicchange a vamp:DenseOutput ; vamp:identifier "harmonicchange" ; @@ -166,7 +152,7 @@ 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 ; vamp:identifier "nnls-chroma" ; @@ -188,7 +174,6 @@ vamp:output plugbase:nnls-chroma_output_chroma ; vamp:output plugbase:nnls-chroma_output_basschroma ; vamp:output plugbase:nnls-chroma_output_bothchroma ; - vamp:output plugbase:nnls-chroma_output_consonance ; . plugbase:nnls-chroma_param_useNNLS a vamp:QuantizedParameter ; vamp:identifier "useNNLS" ; @@ -311,22 +296,11 @@ 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_signal_type af:Chromagram ; . - -plugbase:nnls-chroma_output_consonance a vamp:DenseOutput ; - vamp:identifier "consonance" ; - dc:title "Consonance estimate." ; - dc:description """A simple consonance value based on the convolution of a consonance profile with the semitone spectrum.""" ; - vamp:fixed_bin_count "true" ; - vamp:unit "" ; - vamp:bin_count 1 ; - vamp:computes_signal_type af:TonalChangeDetectionFunction; - . - 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 ; vamp:identifier "tuning" ; @@ -334,6 +308,7 @@ owl:versionInfo "1" ; vamp:input_domain vamp:FrequencyDomain ; + vamp:parameter plugbase:tuning_param_rollon ; vamp:output plugbase:tuning_output_tuning ; @@ -359,10 +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 2.38221e-44 ; - vamp:computes_event_type af:Segment; + vamp:computes_event_type af:MusicSegment; . plugbase:tuning_output_localtuning a vamp:DenseOutput ; vamp:identifier "localtuning" ; diff -r 5190d4947ad9 -r d22f69c2b025 releasenotes-0.3.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/releasenotes-0.3.txt Mon Nov 02 12:35:13 2015 +0000 @@ -0,0 +1,23 @@ +NNLS Chroma 0.3 -- Release Notes + +General Description: + +A Vamp plugin library for harmony and chord extraction with some features aimed at amateur musicians, and some at music information retrieval researchers. +It contains the Chordino, NNLS Chroma and Tuning plugins. +For more information see README or http://isophonics.net/nnls-chroma + +Feature changes: + +in Chordino: +* added Log-Likelihood of Chord Estimate (based on the Viterbi path used for chord estimation), +* added option for Chris Harte's chord syntax, +* removed option for non-HMM chord estimation. + +in NNLS-Chroma: +* removed consonance output. + +Bug fixes: +* renamed dim7 chord to half-diminished (m7b5 and :hdim7, respectively), and added the correct chord label to the diminished chord (was empty before, and hence treated as major chord). + +Other: +* renamed: spectral roll-off parameter to Bass Noise Threshold (in response to Tim Crawfords comment, thanks!) \ No newline at end of file diff -r 5190d4947ad9 -r d22f69c2b025 viterbi.cpp --- a/viterbi.cpp Mon Nov 02 12:23:00 2015 +0000 +++ b/viterbi.cpp Mon Nov 02 12:35:13 2015 +0000 @@ -2,40 +2,38 @@ #include "viterbi.h" #include -std::vector ViterbiPath(std::vector init, std::vector > trans, std::vector > obs, double *delta) { +std::vector ViterbiPath(std::vector init, std::vector > trans, std::vector > obs, double *delta, vector *scale) { int nState = init.size(); int nFrame = obs.size(); - // cerr << nState << " " << nFrame << endl; // check for consistency - if (trans[0].size() != nState || trans.size() != nState || obs[0].size() != nState) { + if ((int)trans[0].size() != nState || (int)trans.size() != nState || (int)obs[0].size() != nState) { cerr << "ERROR: matrix sizes inconsistent." << endl; } - - // vector > delta; // "matrix" of conditional probabilities + vector > psi; // "matrix" of remembered indices of the best transitions vector path = vector(nFrame, nState-1); // the final output path (current assignment arbitrary, makes sense only for Chordino, where nChord-1 is the "no chord" label) - vector scale = vector(nFrame, 0); // remembers by how much the vectors in delta are scaled. double deltasum = 0; /* initialise first frame */ - // delta.push_back(init); 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); + scale->push_back(1.0/deltasum); psi.push_back(vector(nState,0)); + +// cerr << "nState = " << nState << ", deltasum = " << deltasum << endl; /* rest of the forward step */ for (int iFrame = 1; iFrame < nFrame; ++iFrame) { - // delta.push_back(vector(nState,0)); deltasum = 0; psi.push_back(vector(nState,0)); - /* every state wants to know which previous state suits him best */ + /* every state wants to know which previous state suits it best */ for (int jState = 0; jState < nState; ++jState) { int bestState = nState - 1; double bestValue = 0; @@ -48,7 +46,7 @@ } } } - // cerr << bestState <<" ::: " << bestValue << endl ; + delta[iFrame * nState + jState] = bestValue * obs[iFrame][jState]; deltasum += delta[iFrame * nState + jState]; psi[iFrame][jState] = bestState; @@ -57,21 +55,21 @@ for (int iState = 0; iState < nState; ++iState) { delta[iFrame * nState + iState] /= deltasum; // normalise (scale) } - scale.push_back(1.0/deltasum); + scale->push_back(1.0/deltasum); } else { for (int iState = 0; iState < nState; ++iState) { delta[iFrame * nState + iState] = 1.0/nState; } - scale.push_back(1.0); + scale->push_back(1.0); } } /* initialise backward step */ - int bestValue = 0; + double bestValue = 0; for (int iState = 0; iState < nState; ++iState) { double currentValue = delta[(nFrame-1) * nState + iState]; - if (currentValue > path[nFrame-1]) { + if (currentValue > bestValue) { bestValue = currentValue; path[nFrame-1] = iState; } @@ -80,7 +78,6 @@ /* rest of backward step */ for (int iFrame = nFrame-2; iFrame > -1; --iFrame) { path[iFrame] = psi[iFrame+1][path[iFrame+1]]; - // cerr << path[iFrame] << endl; } return path; diff -r 5190d4947ad9 -r d22f69c2b025 viterbi.h --- a/viterbi.h Mon Nov 02 12:23:00 2015 +0000 +++ b/viterbi.h Mon Nov 02 12:35:13 2015 +0000 @@ -23,6 +23,6 @@ #include using namespace std; -extern std::vector ViterbiPath(std::vector init, std::vector > trans, std::vector > obs, double *delta); +extern std::vector ViterbiPath(std::vector init, std::vector > trans, std::vector > obs, double *delta, vector *scale); #endif \ No newline at end of file