comparison transform/BeatDetectTransform.cpp @ 0:da6937383da8

initial import
author Chris Cannam
date Tue, 10 Jan 2006 16:33:16 +0000
parents
children d86891498eef
comparison
equal deleted inserted replaced
-1:000000000000 0:da6937383da8
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 A waveform viewer and audio annotation editor.
5 Chris Cannam, Queen Mary University of London, 2005
6
7 This is experimental software. Not for distribution.
8 */
9
10 #include "BeatDetectTransform.h"
11
12 #include "model/DenseTimeValueModel.h"
13 #include "model/SparseOneDimensionalModel.h"
14
15 #include <iostream>
16 #include "dsp/onsets/DetectionFunction.h"
17 #include "dsp/tempotracking/TempoTrack.h"
18
19
20 BeatDetectTransform::BeatDetectTransform(Model *inputModel) :
21 Transform(inputModel)
22 {
23 // Step resolution for the detection function in seconds
24 double stepSecs = 0.01161;
25
26 // Step resolution for the detection function in samples
27 size_t stepSize = (size_t)floor((double)inputModel->getSampleRate() *
28 stepSecs);
29
30
31 // m_w->m_bdf->setResolution(stepSize);
32 // output->setResolution(stepSize);
33
34 std::cerr << "BeatDetectTransform::BeatDetectTransform: input sample rate " << inputModel->getSampleRate() << ", stepSecs " << stepSecs << ", stepSize " << stepSize << ", unrounded stepSize " << double(inputModel->getSampleRate()) * stepSecs << ", output sample rate " << inputModel->getSampleRate() / stepSize << ", unrounded output sample rate " << double(inputModel->getSampleRate()) / double(stepSize) << std::endl;
35
36 m_output = new SparseOneDimensionalModel(inputModel->getSampleRate(), 1);
37 }
38
39 BeatDetectTransform::~BeatDetectTransform()
40 {
41 // parent does it all
42 }
43
44 TransformName
45 BeatDetectTransform::getName()
46 {
47 return tr("Beats");
48 }
49
50 void
51 BeatDetectTransform::run()
52 {
53 SparseOneDimensionalModel *output = getOutput();
54 DenseTimeValueModel *input = getInput();
55 if (!input) return;
56
57 DFConfig config;
58
59 config.DFType = DF_COMPLEXSD;
60
61 // Step resolution for the detection function in seconds
62 config.stepSecs = 0.01161;
63
64 // Step resolution for the detection function in samples
65 config.stepSize = (unsigned int)floor((double)input->getSampleRate() *
66 config.stepSecs );
67
68 config.frameLength = 2 * config.stepSize;
69
70 unsigned int stepSize = config.stepSize;
71 unsigned int frameLength = config.frameLength;
72
73 // m_w->m_bdf->setResolution(stepSize);
74 output->setResolution(stepSize);
75
76 //Tempo Tracking Configuration Parameters
77 TTParams ttparams;
78
79 // Low Pass filter coefficients for detection function smoothing
80 double* aCoeffs = new double[3];
81 double* bCoeffs = new double[3];
82
83 aCoeffs[ 0 ] = 1;
84 aCoeffs[ 1 ] = -0.5949;
85 aCoeffs[ 2 ] = 0.2348;
86 bCoeffs[ 0 ] = 0.1600;
87 bCoeffs[ 1 ] = 0.3200;
88 bCoeffs[ 2 ] = 0.1600;
89
90 ttparams.winLength = 512;
91 ttparams.lagLength = 128;
92 ttparams.LPOrd = 2;
93 ttparams.LPACoeffs = aCoeffs;
94 ttparams.LPBCoeffs = bCoeffs;
95 ttparams.alpha = 9;
96 ttparams.WinT.post = 8;
97 ttparams.WinT.pre = 7;
98
99 ////////////////////////////////////////////////////////////
100 // DetectionFunction
101 ////////////////////////////////////////////////////////////
102 // Instantiate and configure detection function object
103
104 DetectionFunction df(config);
105
106 size_t origin = input->getStartFrame();
107 size_t frameCount = input->getEndFrame() - origin;
108 size_t blocks = (frameCount / stepSize);
109 if (blocks * stepSize < frameCount) ++blocks;
110
111 double *buffer = new double[frameLength];
112
113 // DF output with causal extension
114 unsigned int clen = blocks + ttparams.winLength;
115 double *dfOutput = new double[clen];
116
117 std::cerr << "Detecting beats at step size " << stepSize << "..." << std::endl;
118
119 for (size_t i = 0; i < clen; ++i) {
120
121 // std::cerr << "block " << i << "/" << clen << std::endl;
122 // std::cerr << ".";
123
124 if (i < blocks) {
125 size_t got = input->getValues(-1, //!!! needs to come from parent layer -- which is not supposed to be in scope at this point
126 origin + i * stepSize,
127 origin + i * stepSize + frameLength,
128 buffer);
129 while (got < frameLength) buffer[got++] = 0.0;
130 dfOutput[i] = df.process(buffer);
131 } else {
132 dfOutput[i] = 0.0;
133 }
134
135 // m_w->m_bdf->addPoint(SparseTimeValueModel::Point
136 // (i * stepSize, dfOutput[i],
137 // QString("%1").arg(dfOutput[i])));
138 // m_w->m_bdf->setCompletion(i * 99 / clen);
139 output->setCompletion(i * 99 / clen);
140
141 if (m_deleting) {
142 delete [] buffer;
143 delete [] dfOutput;
144 delete [] aCoeffs;
145 delete [] bCoeffs;
146 return;
147 }
148 }
149
150 // m_w->m_bdf->setCompletion(100);
151
152 // Tempo Track Object instantiation and configuration
153 TempoTrack tempoTracker(ttparams);
154
155 // Vector of detected onsets
156 vector<int> beats;
157
158 std::cerr << "Running tempo tracker..." << std::endl;
159
160 beats = tempoTracker.process(dfOutput, blocks);
161
162 delete [] buffer;
163 delete [] dfOutput;
164 delete [] aCoeffs;
165 delete [] bCoeffs;
166
167 for (size_t i = 0; i < beats.size(); ++i) {
168 // std::cerr << "Beat value " << beats[i] << ", multiplying out to " << beats[i] * stepSize << std::endl;
169 float bpm = 0.0;
170 int fdiff = 0;
171 if (i < beats.size() - 1) {
172 fdiff = (beats[i+1] - beats[i]) * stepSize;
173 // one beat is fdiff frames, so there are samplerate/fdiff bps,
174 // so 60*samplerate/fdiff bpm
175 if (fdiff > 0) {
176 bpm = (60.0 * input->getSampleRate()) / fdiff;
177 }
178 }
179 output->addPoint(SparseOneDimensionalModel::Point
180 (origin + beats[i] * stepSize, QString("%1").arg(bpm)));
181 if (m_deleting) return;
182 }
183
184 output->setCompletion(100);
185 }
186
187 DenseTimeValueModel *
188 BeatDetectTransform::getInput()
189 {
190 DenseTimeValueModel *dtvm =
191 dynamic_cast<DenseTimeValueModel *>(getInputModel());
192 if (!dtvm) {
193 std::cerr << "BeatDetectTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
194 }
195 return dtvm;
196 }
197
198 SparseOneDimensionalModel *
199 BeatDetectTransform::getOutput()
200 {
201 return static_cast<SparseOneDimensionalModel *>(getOutputModel());
202 }
203