Chris@0
|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 A waveform viewer and audio annotation editor.
|
Chris@2
|
5 Chris Cannam, Queen Mary University of London, 2005-2006
|
Chris@0
|
6
|
Chris@0
|
7 This is experimental software. Not for distribution.
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 #include "BeatDetectionFunctionTransform.h"
|
Chris@0
|
11
|
Chris@0
|
12 #include "model/DenseTimeValueModel.h"
|
Chris@0
|
13 #include "model/SparseTimeValueModel.h"
|
Chris@0
|
14
|
Chris@0
|
15 #include <iostream>
|
Chris@0
|
16 #include "dsp/onsets/DetectionFunction.h"
|
Chris@0
|
17 #include "dsp/tempotracking/TempoTrack.h"
|
Chris@0
|
18
|
Chris@0
|
19
|
Chris@0
|
20 BeatDetectionFunctionTransform::BeatDetectionFunctionTransform(Model *inputModel) :
|
Chris@0
|
21 Transform(inputModel)
|
Chris@0
|
22 {
|
Chris@0
|
23 m_output = new SparseTimeValueModel(inputModel->getSampleRate(), 1,
|
Chris@0
|
24 0.0, 0.0, false);
|
Chris@0
|
25 }
|
Chris@0
|
26
|
Chris@0
|
27 BeatDetectionFunctionTransform::~BeatDetectionFunctionTransform()
|
Chris@0
|
28 {
|
Chris@0
|
29 // parent does it all
|
Chris@0
|
30 }
|
Chris@0
|
31
|
Chris@0
|
32 TransformName
|
Chris@0
|
33 BeatDetectionFunctionTransform::getName()
|
Chris@0
|
34 {
|
Chris@0
|
35 return tr("Beat Detection Function");
|
Chris@0
|
36 }
|
Chris@0
|
37
|
Chris@0
|
38 void
|
Chris@0
|
39 BeatDetectionFunctionTransform::run()
|
Chris@0
|
40 {
|
Chris@0
|
41 SparseTimeValueModel *output = getOutput();
|
Chris@0
|
42 DenseTimeValueModel *input = getInput();
|
Chris@0
|
43 if (!input) {
|
Chris@0
|
44 std::cerr << "BeatDetectionFunctionTransform::run: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
|
Chris@0
|
45 return;
|
Chris@0
|
46 }
|
Chris@0
|
47
|
Chris@0
|
48 DFConfig config;
|
Chris@0
|
49
|
Chris@0
|
50 config.DFType = DF_COMPLEXSD;
|
Chris@0
|
51
|
Chris@0
|
52 // Step resolution for the detection function in seconds
|
Chris@0
|
53 config.stepSecs = 0.01161;
|
Chris@0
|
54
|
Chris@0
|
55 // Step resolution for the detection function in samples
|
Chris@0
|
56 config.stepSize = (unsigned int)floor((double)input->getSampleRate() *
|
Chris@0
|
57 config.stepSecs );
|
Chris@0
|
58
|
Chris@0
|
59 config.frameLength = 2 * config.stepSize;
|
Chris@0
|
60
|
Chris@0
|
61 unsigned int stepSize = config.stepSize;
|
Chris@0
|
62 unsigned int frameLength = config.frameLength;
|
Chris@0
|
63
|
Chris@0
|
64 output->setResolution(stepSize);
|
Chris@0
|
65
|
Chris@0
|
66 //Tempo Tracking Configuration Parameters
|
Chris@0
|
67 TTParams ttparams;
|
Chris@0
|
68
|
Chris@0
|
69 // Low Pass filter coefficients for detection function smoothing
|
Chris@0
|
70 double* aCoeffs = new double[3];
|
Chris@0
|
71 double* bCoeffs = new double[3];
|
Chris@0
|
72
|
Chris@0
|
73 aCoeffs[ 0 ] = 1;
|
Chris@0
|
74 aCoeffs[ 1 ] = -0.5949;
|
Chris@0
|
75 aCoeffs[ 2 ] = 0.2348;
|
Chris@0
|
76 bCoeffs[ 0 ] = 0.1600;
|
Chris@0
|
77 bCoeffs[ 1 ] = 0.3200;
|
Chris@0
|
78 bCoeffs[ 2 ] = 0.1600;
|
Chris@0
|
79
|
Chris@0
|
80 ttparams.winLength = 512;
|
Chris@0
|
81 ttparams.lagLength = 128;
|
Chris@0
|
82 ttparams.LPOrd = 2;
|
Chris@0
|
83 ttparams.LPACoeffs = aCoeffs;
|
Chris@0
|
84 ttparams.LPBCoeffs = bCoeffs;
|
Chris@0
|
85 ttparams.alpha = 9;
|
Chris@0
|
86 ttparams.WinT.post = 8;
|
Chris@0
|
87 ttparams.WinT.pre = 7;
|
Chris@0
|
88
|
Chris@0
|
89 ////////////////////////////////////////////////////////////
|
Chris@0
|
90 // DetectionFunction
|
Chris@0
|
91 ////////////////////////////////////////////////////////////
|
Chris@0
|
92 // Instantiate and configure detection function object
|
Chris@0
|
93
|
Chris@0
|
94 DetectionFunction df(config);
|
Chris@0
|
95
|
Chris@0
|
96 size_t origin = input->getStartFrame();
|
Chris@0
|
97 size_t frameCount = input->getEndFrame() - origin;
|
Chris@0
|
98 size_t blocks = (frameCount / stepSize);
|
Chris@0
|
99 if (blocks * stepSize < frameCount) ++blocks;
|
Chris@0
|
100
|
Chris@0
|
101 double *buffer = new double[frameLength];
|
Chris@0
|
102
|
Chris@0
|
103 // DF output with causal extension
|
Chris@0
|
104 unsigned int clen = blocks + ttparams.winLength;
|
Chris@0
|
105 double *dfOutput = new double[clen];
|
Chris@0
|
106
|
Chris@0
|
107 std::cerr << "Running beat detection function at step size " << stepSize << "..." << std::endl;
|
Chris@0
|
108
|
Chris@0
|
109 for (size_t i = 0; i < clen; ++i) {
|
Chris@0
|
110
|
Chris@0
|
111 // std::cerr << "block " << i << "/" << clen << std::endl;
|
Chris@0
|
112 // std::cerr << ".";
|
Chris@0
|
113
|
Chris@0
|
114 if (i < blocks) {
|
Chris@0
|
115 size_t got = input->getValues(-1, //!!! needs to come from parent layer -- which is not supposed to be in scope at this point
|
Chris@0
|
116 origin + i * stepSize,
|
Chris@0
|
117 origin + i * stepSize + frameLength,
|
Chris@0
|
118 buffer);
|
Chris@0
|
119 while (got < frameLength) buffer[got++] = 0.0;
|
Chris@0
|
120 dfOutput[i] = df.process(buffer);
|
Chris@0
|
121 } else {
|
Chris@0
|
122 dfOutput[i] = 0.0;
|
Chris@0
|
123 }
|
Chris@0
|
124
|
Chris@0
|
125 output->addPoint(SparseTimeValueModel::Point
|
Chris@0
|
126 (i * stepSize, dfOutput[i],
|
Chris@0
|
127 QString("%1").arg(dfOutput[i])));
|
Chris@0
|
128 // m_w->m_bdf->setCompletion(i * 99 / clen);
|
Chris@0
|
129 output->setCompletion(i * 99 / clen);
|
Chris@0
|
130
|
Chris@0
|
131 if (m_deleting) {
|
Chris@0
|
132 delete [] buffer;
|
Chris@0
|
133 delete [] dfOutput;
|
Chris@0
|
134 delete [] aCoeffs;
|
Chris@0
|
135 delete [] bCoeffs;
|
Chris@0
|
136 return;
|
Chris@0
|
137 }
|
Chris@0
|
138 }
|
Chris@0
|
139
|
Chris@0
|
140 output->setCompletion(100);
|
Chris@0
|
141 }
|
Chris@0
|
142
|
Chris@0
|
143 DenseTimeValueModel *
|
Chris@0
|
144 BeatDetectionFunctionTransform::getInput()
|
Chris@0
|
145 {
|
Chris@0
|
146 return dynamic_cast<DenseTimeValueModel *>(getInputModel());
|
Chris@0
|
147 }
|
Chris@0
|
148
|
Chris@0
|
149 SparseTimeValueModel *
|
Chris@0
|
150 BeatDetectionFunctionTransform::getOutput()
|
Chris@0
|
151 {
|
Chris@0
|
152 return static_cast<SparseTimeValueModel *>(getOutputModel());
|
Chris@0
|
153 }
|
Chris@0
|
154
|