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@27
|
31 const vector<float> hw(hammingwind, hammingwind+19);
|
matthiasm@0
|
32
|
Chris@35
|
33 Tuning::Tuning(float inputSampleRate) :
|
Chris@35
|
34 NNLSBase(inputSampleRate)
|
matthiasm@0
|
35 {
|
Chris@35
|
36 if (debug_on) cerr << "--> Tuning" << endl;
|
matthiasm@0
|
37 }
|
matthiasm@0
|
38
|
Chris@35
|
39 Tuning::~Tuning()
|
matthiasm@0
|
40 {
|
Chris@35
|
41 if (debug_on) cerr << "--> ~Tuning" << endl;
|
matthiasm@0
|
42 }
|
matthiasm@0
|
43
|
matthiasm@52
|
44 size_t
|
matthiasm@52
|
45 Tuning::getPreferredStepSize() const
|
matthiasm@52
|
46 {
|
matthiasm@52
|
47 if (debug_on) cerr << "--> getPreferredStepSize" << endl;
|
matthiasm@52
|
48 return 2048*4;
|
matthiasm@52
|
49 }
|
matthiasm@52
|
50
|
matthiasm@0
|
51 string
|
Chris@35
|
52 Tuning::getIdentifier() const
|
matthiasm@0
|
53 {
|
Chris@23
|
54 if (debug_on) cerr << "--> getIdentifier" << endl;
|
Chris@35
|
55 return "tuning";
|
matthiasm@0
|
56 }
|
matthiasm@0
|
57
|
matthiasm@0
|
58 string
|
Chris@35
|
59 Tuning::getName() const
|
matthiasm@0
|
60 {
|
Chris@23
|
61 if (debug_on) cerr << "--> getName" << endl;
|
Chris@35
|
62 return "Tuning";
|
matthiasm@0
|
63 }
|
matthiasm@0
|
64
|
matthiasm@0
|
65 string
|
Chris@35
|
66 Tuning::getDescription() const
|
matthiasm@0
|
67 {
|
matthiasm@0
|
68 // Return something helpful here!
|
Chris@23
|
69 if (debug_on) cerr << "--> getDescription" << endl;
|
matthiasm@58
|
70 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
|
71 }
|
matthiasm@0
|
72
|
matthiasm@52
|
73 Tuning::ParameterList
|
matthiasm@52
|
74 Tuning::getParameterDescriptors() const
|
matthiasm@52
|
75 {
|
matthiasm@52
|
76 if (debug_on) cerr << "--> getParameterDescriptors" << endl;
|
matthiasm@52
|
77 ParameterList list;
|
matthiasm@52
|
78
|
matthiasm@52
|
79 ParameterDescriptor d0;
|
matthiasm@52
|
80 d0.identifier = "rollon";
|
matthiasm@52
|
81 d0.name = "spectral roll-on";
|
matthiasm@58
|
82 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.";
|
matthiasm@52
|
83 d0.unit = "";
|
matthiasm@52
|
84 d0.minValue = 0;
|
matthiasm@52
|
85 d0.maxValue = 0.05;
|
matthiasm@52
|
86 d0.defaultValue = 0;
|
matthiasm@52
|
87 d0.isQuantized = true;
|
matthiasm@52
|
88 d0.quantizeStep = 0.005;
|
matthiasm@52
|
89 list.push_back(d0);
|
matthiasm@52
|
90
|
matthiasm@52
|
91
|
matthiasm@52
|
92 return list;
|
matthiasm@52
|
93 }
|
matthiasm@52
|
94
|
Chris@35
|
95 Tuning::OutputList
|
Chris@35
|
96 Tuning::getOutputDescriptors() const
|
matthiasm@0
|
97 {
|
Chris@23
|
98 if (debug_on) cerr << "--> getOutputDescriptors" << endl;
|
matthiasm@0
|
99 OutputList list;
|
matthiasm@0
|
100
|
Chris@35
|
101 int index = 0;
|
matthiasm@0
|
102
|
matthiasm@0
|
103 OutputDescriptor d0;
|
matthiasm@0
|
104 d0.identifier = "tuning";
|
matthiasm@0
|
105 d0.name = "Tuning";
|
matthiasm@58
|
106 d0.description = "Returns a single label (at time 0 seconds) containing an estimate of the concert pitch in Hz.";
|
matthiasm@0
|
107 d0.unit = "Hz";
|
matthiasm@0
|
108 d0.hasFixedBinCount = true;
|
matthiasm@0
|
109 d0.binCount = 0;
|
matthiasm@0
|
110 d0.hasKnownExtents = true;
|
Chris@23
|
111 d0.minValue = 427.47;
|
Chris@23
|
112 d0.maxValue = 452.89;
|
matthiasm@0
|
113 d0.isQuantized = false;
|
matthiasm@0
|
114 d0.sampleType = OutputDescriptor::VariableSampleRate;
|
matthiasm@0
|
115 d0.hasDuration = false;
|
matthiasm@0
|
116 list.push_back(d0);
|
Chris@35
|
117 m_outputTuning = index++;
|
matthiasm@0
|
118
|
Chris@23
|
119 OutputDescriptor d10;
|
Chris@23
|
120 d10.identifier = "localtuning";
|
Chris@37
|
121 d10.name = "Local Tuning";
|
matthiasm@58
|
122 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
|
123 d10.unit = "Hz";
|
Chris@23
|
124 d10.hasFixedBinCount = true;
|
Chris@23
|
125 d10.binCount = 1;
|
Chris@23
|
126 d10.hasKnownExtents = true;
|
Chris@23
|
127 d10.minValue = 427.47;
|
Chris@23
|
128 d10.maxValue = 452.89;
|
Chris@23
|
129 d10.isQuantized = false;
|
Chris@23
|
130 d10.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@23
|
131 d10.hasDuration = false;
|
Chris@23
|
132 // d10.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
|
Chris@23
|
133 list.push_back(d10);
|
Chris@35
|
134 m_outputLocalTuning = index++;
|
matthiasm@1
|
135
|
matthiasm@0
|
136 return list;
|
matthiasm@0
|
137 }
|
matthiasm@0
|
138
|
matthiasm@0
|
139
|
matthiasm@0
|
140 bool
|
Chris@35
|
141 Tuning::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
matthiasm@0
|
142 {
|
Chris@23
|
143 if (debug_on) {
|
Chris@23
|
144 cerr << "--> initialise";
|
Chris@23
|
145 }
|
matthiasm@1
|
146
|
Chris@35
|
147 if (!NNLSBase::initialise(channels, stepSize, blockSize)) {
|
Chris@35
|
148 return false;
|
Chris@35
|
149 }
|
matthiasm@1
|
150
|
matthiasm@0
|
151 return true;
|
matthiasm@0
|
152 }
|
matthiasm@0
|
153
|
matthiasm@0
|
154 void
|
Chris@35
|
155 Tuning::reset()
|
matthiasm@0
|
156 {
|
Chris@23
|
157 if (debug_on) cerr << "--> reset";
|
Chris@35
|
158 NNLSBase::reset();
|
matthiasm@0
|
159 }
|
matthiasm@0
|
160
|
Chris@35
|
161 Tuning::FeatureSet
|
Chris@35
|
162 Tuning::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
|
matthiasm@0
|
163 {
|
Chris@23
|
164 if (debug_on) cerr << "--> process" << endl;
|
Chris@35
|
165
|
Chris@35
|
166 NNLSBase::baseProcess(inputBuffers, timestamp);
|
matthiasm@0
|
167
|
Chris@23
|
168 Feature f10; // local tuning
|
Chris@23
|
169 f10.hasTimestamp = true;
|
Chris@23
|
170 f10.timestamp = timestamp;
|
Chris@35
|
171 float normalisedtuning = m_localTuning[m_localTuning.size()-1];
|
Chris@23
|
172 float tuning440 = 440 * pow(2,normalisedtuning/12);
|
Chris@23
|
173 f10.values.push_back(tuning440);
|
matthiasm@0
|
174
|
Chris@23
|
175 FeatureSet fs;
|
Chris@35
|
176 fs[m_outputLocalTuning].push_back(f10);
|
Chris@23
|
177 return fs;
|
matthiasm@0
|
178 }
|
matthiasm@0
|
179
|
Chris@35
|
180 Tuning::FeatureSet
|
Chris@35
|
181 Tuning::getRemainingFeatures()
|
matthiasm@0
|
182 {
|
Chris@23
|
183 if (debug_on) cerr << "--> getRemainingFeatures" << endl;
|
Chris@23
|
184 FeatureSet fsOut;
|
Chris@35
|
185 if (m_logSpectrum.size() == 0) return fsOut;
|
Chris@35
|
186
|
Chris@23
|
187 //
|
Chris@23
|
188 /** Calculate Tuning
|
Chris@23
|
189 calculate tuning from (using the angle of the complex number defined by the
|
Chris@23
|
190 cumulative mean real and imag values)
|
Chris@23
|
191 **/
|
Chris@23
|
192 float meanTuningImag = sinvalue * m_meanTuning1 - sinvalue * m_meanTuning2;
|
Chris@23
|
193 float meanTuningReal = m_meanTuning0 + cosvalue * m_meanTuning1 + cosvalue * m_meanTuning2;
|
Chris@23
|
194 float cumulativetuning = 440 * pow(2,atan2(meanTuningImag, meanTuningReal)/(24*M_PI));
|
matthiasm@1
|
195
|
Chris@23
|
196 char buffer0 [50];
|
matthiasm@1
|
197
|
Chris@23
|
198 sprintf(buffer0, "estimated tuning: %0.1f Hz", cumulativetuning);
|
matthiasm@1
|
199
|
Chris@23
|
200 // push tuning to FeatureSet fsOut
|
Chris@23
|
201 Feature f0; // tuning
|
Chris@23
|
202 f0.hasTimestamp = true;
|
Chris@23
|
203 f0.timestamp = Vamp::RealTime::frame2RealTime(0, lrintf(m_inputSampleRate));;
|
Chris@23
|
204 f0.label = buffer0;
|
Chris@35
|
205 fsOut[m_outputTuning].push_back(f0);
|
matthiasm@1
|
206
|
Chris@23
|
207 return fsOut;
|
matthiasm@0
|
208
|
matthiasm@0
|
209 }
|
matthiasm@0
|
210
|