Chris@23
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
matthiasm@0
|
2
|
Chris@35
|
3 /*
|
Chris@35
|
4 NNLS-Chroma / Chordino
|
Chris@35
|
5
|
Chris@35
|
6 Audio feature extraction plugins for chromagram and chord
|
Chris@35
|
7 estimation.
|
Chris@35
|
8
|
Chris@35
|
9 Centre for Digital Music, Queen Mary University of London.
|
Chris@35
|
10 This file copyright 2008-2010 Matthias Mauch and QMUL.
|
Chris@35
|
11
|
Chris@35
|
12 This program is free software; you can redistribute it and/or
|
Chris@35
|
13 modify it under the terms of the GNU General Public License as
|
Chris@35
|
14 published by the Free Software Foundation; either version 2 of the
|
Chris@35
|
15 License, or (at your option) any later version. See the file
|
Chris@35
|
16 COPYING included with this distribution for more information.
|
Chris@35
|
17 */
|
Chris@35
|
18
|
Chris@35
|
19 #include "Tuning.h"
|
Chris@27
|
20
|
Chris@27
|
21 #include "chromamethods.h"
|
Chris@27
|
22
|
Chris@27
|
23 #include <cstdlib>
|
Chris@27
|
24 #include <fstream>
|
matthiasm@0
|
25 #include <cmath>
|
matthiasm@9
|
26
|
Chris@27
|
27 #include <algorithm>
|
matthiasm@0
|
28
|
matthiasm@0
|
29 const bool debug_on = false;
|
matthiasm@0
|
30
|
Chris@35
|
31 Tuning::Tuning(float inputSampleRate) :
|
Chris@35
|
32 NNLSBase(inputSampleRate)
|
matthiasm@0
|
33 {
|
Chris@35
|
34 if (debug_on) cerr << "--> Tuning" << endl;
|
matthiasm@0
|
35 }
|
matthiasm@0
|
36
|
Chris@35
|
37 Tuning::~Tuning()
|
matthiasm@0
|
38 {
|
Chris@35
|
39 if (debug_on) cerr << "--> ~Tuning" << endl;
|
matthiasm@0
|
40 }
|
matthiasm@0
|
41
|
matthiasm@52
|
42 size_t
|
matthiasm@52
|
43 Tuning::getPreferredStepSize() const
|
matthiasm@52
|
44 {
|
matthiasm@52
|
45 if (debug_on) cerr << "--> getPreferredStepSize" << endl;
|
matthiasm@52
|
46 return 2048*4;
|
matthiasm@52
|
47 }
|
matthiasm@52
|
48
|
matthiasm@0
|
49 string
|
Chris@35
|
50 Tuning::getIdentifier() const
|
matthiasm@0
|
51 {
|
Chris@23
|
52 if (debug_on) cerr << "--> getIdentifier" << endl;
|
Chris@35
|
53 return "tuning";
|
matthiasm@0
|
54 }
|
matthiasm@0
|
55
|
matthiasm@0
|
56 string
|
Chris@35
|
57 Tuning::getName() const
|
matthiasm@0
|
58 {
|
Chris@23
|
59 if (debug_on) cerr << "--> getName" << endl;
|
Chris@35
|
60 return "Tuning";
|
matthiasm@0
|
61 }
|
matthiasm@0
|
62
|
matthiasm@0
|
63 string
|
Chris@35
|
64 Tuning::getDescription() const
|
matthiasm@0
|
65 {
|
matthiasm@0
|
66 // Return something helpful here!
|
Chris@23
|
67 if (debug_on) cerr << "--> getDescription" << endl;
|
matthiasm@58
|
68 return "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.";
|
matthiasm@0
|
69 }
|
matthiasm@0
|
70
|
matthiasm@52
|
71 Tuning::ParameterList
|
matthiasm@52
|
72 Tuning::getParameterDescriptors() const
|
matthiasm@52
|
73 {
|
matthiasm@52
|
74 if (debug_on) cerr << "--> getParameterDescriptors" << endl;
|
matthiasm@52
|
75 ParameterList list;
|
matthiasm@52
|
76
|
matthiasm@52
|
77 ParameterDescriptor d0;
|
matthiasm@52
|
78 d0.identifier = "rollon";
|
mail@114
|
79 d0.name = "bass noise threshold";
|
mail@114
|
80 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.";
|
matthiasm@59
|
81 d0.unit = "%";
|
matthiasm@52
|
82 d0.minValue = 0;
|
matthiasm@59
|
83 d0.maxValue = 5;
|
matthiasm@52
|
84 d0.defaultValue = 0;
|
matthiasm@52
|
85 d0.isQuantized = true;
|
matthiasm@59
|
86 d0.quantizeStep = 0.5;
|
matthiasm@52
|
87 list.push_back(d0);
|
matthiasm@52
|
88
|
matthiasm@52
|
89
|
matthiasm@52
|
90 return list;
|
matthiasm@52
|
91 }
|
matthiasm@52
|
92
|
Chris@35
|
93 Tuning::OutputList
|
Chris@35
|
94 Tuning::getOutputDescriptors() const
|
matthiasm@0
|
95 {
|
Chris@23
|
96 if (debug_on) cerr << "--> getOutputDescriptors" << endl;
|
matthiasm@0
|
97 OutputList list;
|
matthiasm@0
|
98
|
Chris@35
|
99 int index = 0;
|
matthiasm@0
|
100
|
matthiasm@0
|
101 OutputDescriptor d0;
|
matthiasm@0
|
102 d0.identifier = "tuning";
|
matthiasm@0
|
103 d0.name = "Tuning";
|
matthiasm@58
|
104 d0.description = "Returns a single label (at time 0 seconds) containing an estimate of the concert pitch in Hz.";
|
matthiasm@0
|
105 d0.unit = "Hz";
|
matthiasm@0
|
106 d0.hasFixedBinCount = true;
|
mail@71
|
107 d0.binCount = 1;
|
matthiasm@0
|
108 d0.hasKnownExtents = true;
|
Chris@23
|
109 d0.minValue = 427.47;
|
Chris@23
|
110 d0.maxValue = 452.89;
|
matthiasm@0
|
111 d0.isQuantized = false;
|
matthiasm@0
|
112 d0.sampleType = OutputDescriptor::VariableSampleRate;
|
mail@71
|
113 d0.hasDuration = true;
|
matthiasm@0
|
114 list.push_back(d0);
|
Chris@35
|
115 m_outputTuning = index++;
|
matthiasm@0
|
116
|
Chris@23
|
117 OutputDescriptor d10;
|
Chris@23
|
118 d10.identifier = "localtuning";
|
Chris@37
|
119 d10.name = "Local Tuning";
|
matthiasm@58
|
120 d10.description = "Returns a tuning estimate at every analysis frame, an average of the (recent) previous frame-wise estimates of the concert pitch in Hz.";
|
Chris@23
|
121 d10.unit = "Hz";
|
Chris@23
|
122 d10.hasFixedBinCount = true;
|
Chris@23
|
123 d10.binCount = 1;
|
Chris@23
|
124 d10.hasKnownExtents = true;
|
Chris@23
|
125 d10.minValue = 427.47;
|
Chris@23
|
126 d10.maxValue = 452.89;
|
Chris@23
|
127 d10.isQuantized = false;
|
Chris@23
|
128 d10.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@164
|
129 d10.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
|
Chris@23
|
130 d10.hasDuration = false;
|
Chris@23
|
131 list.push_back(d10);
|
Chris@35
|
132 m_outputLocalTuning = index++;
|
matthiasm@1
|
133
|
matthiasm@0
|
134 return list;
|
matthiasm@0
|
135 }
|
matthiasm@0
|
136
|
matthiasm@0
|
137
|
matthiasm@0
|
138 bool
|
Chris@35
|
139 Tuning::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
matthiasm@0
|
140 {
|
Chris@23
|
141 if (debug_on) {
|
Chris@23
|
142 cerr << "--> initialise";
|
Chris@23
|
143 }
|
matthiasm@1
|
144
|
Chris@35
|
145 if (!NNLSBase::initialise(channels, stepSize, blockSize)) {
|
Chris@35
|
146 return false;
|
Chris@35
|
147 }
|
matthiasm@1
|
148
|
matthiasm@0
|
149 return true;
|
matthiasm@0
|
150 }
|
matthiasm@0
|
151
|
matthiasm@0
|
152 void
|
Chris@35
|
153 Tuning::reset()
|
matthiasm@0
|
154 {
|
Chris@23
|
155 if (debug_on) cerr << "--> reset";
|
Chris@35
|
156 NNLSBase::reset();
|
matthiasm@0
|
157 }
|
matthiasm@0
|
158
|
Chris@35
|
159 Tuning::FeatureSet
|
Chris@35
|
160 Tuning::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
|
matthiasm@0
|
161 {
|
Chris@23
|
162 if (debug_on) cerr << "--> process" << endl;
|
Chris@35
|
163
|
Chris@35
|
164 NNLSBase::baseProcess(inputBuffers, timestamp);
|
matthiasm@0
|
165
|
Chris@23
|
166 Feature f10; // local tuning
|
Chris@23
|
167 f10.hasTimestamp = true;
|
Chris@23
|
168 f10.timestamp = timestamp;
|
Chris@35
|
169 float normalisedtuning = m_localTuning[m_localTuning.size()-1];
|
Chris@23
|
170 float tuning440 = 440 * pow(2,normalisedtuning/12);
|
Chris@23
|
171 f10.values.push_back(tuning440);
|
matthiasm@0
|
172
|
Chris@23
|
173 FeatureSet fs;
|
Chris@35
|
174 fs[m_outputLocalTuning].push_back(f10);
|
Chris@23
|
175 return fs;
|
matthiasm@0
|
176 }
|
matthiasm@0
|
177
|
Chris@35
|
178 Tuning::FeatureSet
|
Chris@35
|
179 Tuning::getRemainingFeatures()
|
matthiasm@0
|
180 {
|
Chris@23
|
181 if (debug_on) cerr << "--> getRemainingFeatures" << endl;
|
Chris@23
|
182 FeatureSet fsOut;
|
Chris@35
|
183 if (m_logSpectrum.size() == 0) return fsOut;
|
Chris@35
|
184
|
Chris@23
|
185 //
|
Chris@23
|
186 /** Calculate Tuning
|
Chris@23
|
187 calculate tuning from (using the angle of the complex number defined by the
|
Chris@23
|
188 cumulative mean real and imag values)
|
Chris@23
|
189 **/
|
mail@80
|
190
|
mail@80
|
191 float meanTuningImag = 0;
|
mail@80
|
192 float meanTuningReal = 0;
|
mail@80
|
193 for (int iBPS = 0; iBPS < nBPS; ++iBPS) {
|
mail@80
|
194 meanTuningReal += m_meanTunings[iBPS] * cosvalues[iBPS];
|
mail@80
|
195 meanTuningImag += m_meanTunings[iBPS] * sinvalues[iBPS];
|
mail@80
|
196 }
|
mail@80
|
197
|
mail@80
|
198
|
Chris@23
|
199 float cumulativetuning = 440 * pow(2,atan2(meanTuningImag, meanTuningReal)/(24*M_PI));
|
matthiasm@1
|
200
|
Chris@23
|
201 char buffer0 [50];
|
matthiasm@1
|
202
|
matthiasm@59
|
203 sprintf(buffer0, "%0.1f Hz", cumulativetuning);
|
matthiasm@1
|
204
|
Chris@23
|
205 // push tuning to FeatureSet fsOut
|
Chris@23
|
206 Feature f0; // tuning
|
Chris@23
|
207 f0.hasTimestamp = true;
|
matthiasm@59
|
208 f0.timestamp = Vamp::RealTime::frame2RealTime(0, lrintf(m_inputSampleRate));
|
matthiasm@59
|
209 f0.values.push_back(cumulativetuning);
|
Chris@23
|
210 f0.label = buffer0;
|
mail@71
|
211 f0.hasDuration = true;
|
mail@71
|
212 f0.duration = m_logSpectrum[m_logSpectrum.size()-1].timestamp;
|
Chris@35
|
213 fsOut[m_outputTuning].push_back(f0);
|
matthiasm@1
|
214
|
Chris@23
|
215 return fsOut;
|
matthiasm@0
|
216
|
matthiasm@0
|
217 }
|
matthiasm@0
|
218
|