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@0
|
44 string
|
Chris@35
|
45 Tuning::getIdentifier() const
|
matthiasm@0
|
46 {
|
Chris@23
|
47 if (debug_on) cerr << "--> getIdentifier" << endl;
|
Chris@35
|
48 return "tuning";
|
matthiasm@0
|
49 }
|
matthiasm@0
|
50
|
matthiasm@0
|
51 string
|
Chris@35
|
52 Tuning::getName() const
|
matthiasm@0
|
53 {
|
Chris@23
|
54 if (debug_on) cerr << "--> getName" << endl;
|
Chris@35
|
55 return "Tuning";
|
matthiasm@0
|
56 }
|
matthiasm@0
|
57
|
matthiasm@0
|
58 string
|
Chris@35
|
59 Tuning::getDescription() const
|
matthiasm@0
|
60 {
|
matthiasm@0
|
61 // Return something helpful here!
|
Chris@23
|
62 if (debug_on) cerr << "--> getDescription" << endl;
|
matthiasm@13
|
63 return "This plugin provides a number of features derived from a log-frequency amplitude spectrum of the DFT: some variants of the log-frequency spectrum, including a semitone spectrum derived from approximate transcription using the NNLS algorithm; based on this semitone spectrum, chroma features and a simple chord estimate.";
|
matthiasm@0
|
64 }
|
matthiasm@0
|
65
|
Chris@35
|
66 Tuning::OutputList
|
Chris@35
|
67 Tuning::getOutputDescriptors() const
|
matthiasm@0
|
68 {
|
Chris@23
|
69 if (debug_on) cerr << "--> getOutputDescriptors" << endl;
|
matthiasm@0
|
70 OutputList list;
|
matthiasm@0
|
71
|
Chris@35
|
72 int index = 0;
|
matthiasm@0
|
73
|
matthiasm@0
|
74 OutputDescriptor d0;
|
matthiasm@0
|
75 d0.identifier = "tuning";
|
matthiasm@0
|
76 d0.name = "Tuning";
|
matthiasm@0
|
77 d0.description = "The concert pitch.";
|
matthiasm@0
|
78 d0.unit = "Hz";
|
matthiasm@0
|
79 d0.hasFixedBinCount = true;
|
matthiasm@0
|
80 d0.binCount = 0;
|
matthiasm@0
|
81 d0.hasKnownExtents = true;
|
Chris@23
|
82 d0.minValue = 427.47;
|
Chris@23
|
83 d0.maxValue = 452.89;
|
matthiasm@0
|
84 d0.isQuantized = false;
|
matthiasm@0
|
85 d0.sampleType = OutputDescriptor::VariableSampleRate;
|
matthiasm@0
|
86 d0.hasDuration = false;
|
matthiasm@0
|
87 list.push_back(d0);
|
Chris@35
|
88 m_outputTuning = index++;
|
matthiasm@0
|
89
|
Chris@23
|
90 OutputDescriptor d10;
|
Chris@23
|
91 d10.identifier = "localtuning";
|
Chris@37
|
92 d10.name = "Local Tuning";
|
Chris@23
|
93 d10.description = "Tuning based on the history up to this timestamp.";
|
Chris@23
|
94 d10.unit = "Hz";
|
Chris@23
|
95 d10.hasFixedBinCount = true;
|
Chris@23
|
96 d10.binCount = 1;
|
Chris@23
|
97 d10.hasKnownExtents = true;
|
Chris@23
|
98 d10.minValue = 427.47;
|
Chris@23
|
99 d10.maxValue = 452.89;
|
Chris@23
|
100 d10.isQuantized = false;
|
Chris@23
|
101 d10.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@23
|
102 d10.hasDuration = false;
|
Chris@23
|
103 // d10.sampleRate = (m_stepSize == 0) ? m_inputSampleRate/2048 : m_inputSampleRate/m_stepSize;
|
Chris@23
|
104 list.push_back(d10);
|
Chris@35
|
105 m_outputLocalTuning = index++;
|
matthiasm@1
|
106
|
matthiasm@0
|
107 return list;
|
matthiasm@0
|
108 }
|
matthiasm@0
|
109
|
matthiasm@0
|
110
|
matthiasm@0
|
111 bool
|
Chris@35
|
112 Tuning::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
matthiasm@0
|
113 {
|
Chris@23
|
114 if (debug_on) {
|
Chris@23
|
115 cerr << "--> initialise";
|
Chris@23
|
116 }
|
matthiasm@1
|
117
|
Chris@35
|
118 if (!NNLSBase::initialise(channels, stepSize, blockSize)) {
|
Chris@35
|
119 return false;
|
Chris@35
|
120 }
|
matthiasm@1
|
121
|
matthiasm@0
|
122 return true;
|
matthiasm@0
|
123 }
|
matthiasm@0
|
124
|
matthiasm@0
|
125 void
|
Chris@35
|
126 Tuning::reset()
|
matthiasm@0
|
127 {
|
Chris@23
|
128 if (debug_on) cerr << "--> reset";
|
Chris@35
|
129 NNLSBase::reset();
|
matthiasm@0
|
130 }
|
matthiasm@0
|
131
|
Chris@35
|
132 Tuning::FeatureSet
|
Chris@35
|
133 Tuning::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
|
matthiasm@0
|
134 {
|
Chris@23
|
135 if (debug_on) cerr << "--> process" << endl;
|
Chris@35
|
136
|
Chris@35
|
137 NNLSBase::baseProcess(inputBuffers, timestamp);
|
matthiasm@0
|
138
|
Chris@23
|
139 Feature f10; // local tuning
|
Chris@23
|
140 f10.hasTimestamp = true;
|
Chris@23
|
141 f10.timestamp = timestamp;
|
Chris@35
|
142 float normalisedtuning = m_localTuning[m_localTuning.size()-1];
|
Chris@23
|
143 float tuning440 = 440 * pow(2,normalisedtuning/12);
|
Chris@23
|
144 f10.values.push_back(tuning440);
|
matthiasm@0
|
145
|
Chris@23
|
146 FeatureSet fs;
|
Chris@35
|
147 fs[m_outputLocalTuning].push_back(f10);
|
Chris@23
|
148 return fs;
|
matthiasm@0
|
149 }
|
matthiasm@0
|
150
|
Chris@35
|
151 Tuning::FeatureSet
|
Chris@35
|
152 Tuning::getRemainingFeatures()
|
matthiasm@0
|
153 {
|
Chris@23
|
154 if (debug_on) cerr << "--> getRemainingFeatures" << endl;
|
Chris@23
|
155 FeatureSet fsOut;
|
Chris@35
|
156 if (m_logSpectrum.size() == 0) return fsOut;
|
Chris@35
|
157
|
Chris@23
|
158 //
|
Chris@23
|
159 /** Calculate Tuning
|
Chris@23
|
160 calculate tuning from (using the angle of the complex number defined by the
|
Chris@23
|
161 cumulative mean real and imag values)
|
Chris@23
|
162 **/
|
Chris@23
|
163 float meanTuningImag = sinvalue * m_meanTuning1 - sinvalue * m_meanTuning2;
|
Chris@23
|
164 float meanTuningReal = m_meanTuning0 + cosvalue * m_meanTuning1 + cosvalue * m_meanTuning2;
|
Chris@23
|
165 float cumulativetuning = 440 * pow(2,atan2(meanTuningImag, meanTuningReal)/(24*M_PI));
|
matthiasm@1
|
166
|
Chris@23
|
167 char buffer0 [50];
|
matthiasm@1
|
168
|
Chris@23
|
169 sprintf(buffer0, "estimated tuning: %0.1f Hz", cumulativetuning);
|
matthiasm@1
|
170
|
Chris@23
|
171 // push tuning to FeatureSet fsOut
|
Chris@23
|
172 Feature f0; // tuning
|
Chris@23
|
173 f0.hasTimestamp = true;
|
Chris@23
|
174 f0.timestamp = Vamp::RealTime::frame2RealTime(0, lrintf(m_inputSampleRate));;
|
Chris@23
|
175 f0.label = buffer0;
|
Chris@35
|
176 fsOut[m_outputTuning].push_back(f0);
|
matthiasm@1
|
177
|
Chris@23
|
178 return fsOut;
|
matthiasm@0
|
179
|
matthiasm@0
|
180 }
|
matthiasm@0
|
181
|