Venetian@7
|
1 /*
|
Venetian@7
|
2 * PreciseBassOnsetDetectorOffline.cpp
|
Venetian@7
|
3 * BasslinePrediction
|
Venetian@7
|
4 *
|
Venetian@7
|
5 * Created by Andrew N Robertson on 11/04/2014.
|
Venetian@7
|
6 * Copyright 2014 QMUL. All rights reserved.
|
Venetian@7
|
7 *
|
Venetian@7
|
8 */
|
Venetian@7
|
9
|
Venetian@7
|
10 #include "PreciseBassOnsetDetectorOffline.h"
|
Venetian@7
|
11
|
Venetian@7
|
12 bool printingOn = false;//true;
|
Venetian@7
|
13
|
Venetian@7
|
14 int PreciseBassOnsetDetectorOffline::processAudioFileForBeatTimes(std::string audiofile){
|
Venetian@7
|
15 printf("PBODO: Process Function BASS OFFLINE VERSION\n");
|
Venetian@7
|
16
|
Venetian@7
|
17 //originally from BeatAnnotationViewer project
|
Venetian@7
|
18
|
Venetian@7
|
19 initialise();// - needed but elsewhere
|
Venetian@7
|
20 isBass = true;
|
Venetian@7
|
21
|
Venetian@7
|
22 // static double frame[FRAMESIZE]; // to hold a single frame
|
Venetian@7
|
23 double buffer[frameSize];
|
Venetian@7
|
24 double dfval;
|
Venetian@7
|
25
|
Venetian@7
|
26 for (int i = 0;i < frameSize;i++)
|
Venetian@7
|
27 {
|
Venetian@7
|
28 buffer[i] = 0;
|
Venetian@7
|
29 }
|
Venetian@7
|
30
|
Venetian@7
|
31 //detfun = new df(1,(FRAMESIZE*2),0);
|
Venetian@7
|
32
|
Venetian@7
|
33
|
Venetian@7
|
34
|
Venetian@7
|
35 SNDFILE *infile, *outfile ; // define input and output sound files
|
Venetian@7
|
36
|
Venetian@7
|
37 SF_INFO sfinfo ; // struct to hold info about sound file
|
Venetian@7
|
38 int readcount ; // counts number of samples read from sound file
|
Venetian@7
|
39 const char *infilename = audiofile.c_str();
|
Venetian@7
|
40 //"/Users/andrew/Music/Station To Station 2/3-03 Panic In Detroit (Live Nassau Coliseum '76).wav";//"ledzep.wav" ; // input file name
|
Venetian@7
|
41 // const char *outfilename = "output.wav" ; // output file name
|
Venetian@7
|
42
|
Venetian@7
|
43
|
Venetian@7
|
44 // Open Input File
|
Venetian@7
|
45 if (! (infile = sf_open (infilename, SFM_READ, &sfinfo)))
|
Venetian@7
|
46 { // Open failed
|
Venetian@7
|
47 printf ("Not able to open input file %s.\n", infilename) ;
|
Venetian@7
|
48 // Print the error message from libsndfile.
|
Venetian@7
|
49 puts (sf_strerror (NULL)) ;
|
Venetian@7
|
50 return 1;
|
Venetian@7
|
51 } ;
|
Venetian@7
|
52
|
Venetian@7
|
53 printf("opened '%s'\n", audiofile.c_str());
|
Venetian@7
|
54 loadedFilename = audiofile;
|
Venetian@7
|
55 //STEREO OKAY
|
Venetian@7
|
56
|
Venetian@7
|
57 //HERE IS THE CLASSIC LOADING FILE CODE
|
Venetian@7
|
58 //DEALS WITH MORE THAN MONO
|
Venetian@7
|
59 int channels = sfinfo.channels;
|
Venetian@7
|
60 samples = sfinfo.frames;
|
Venetian@7
|
61 printf("Number of channels %i, samples %i\n", channels, samples);
|
Venetian@7
|
62
|
Venetian@7
|
63
|
Venetian@7
|
64 int blocksize = hopSize;//FRAMESIZE;
|
Venetian@7
|
65 float buf [channels * blocksize] ;
|
Venetian@7
|
66 float frame[blocksize];
|
Venetian@7
|
67
|
Venetian@7
|
68 int k, m;
|
Venetian@7
|
69 readcount = 1;
|
Venetian@7
|
70
|
Venetian@7
|
71
|
Venetian@7
|
72 //DoubleVector d;
|
Venetian@7
|
73 while ((readcount = sf_readf_float (infile, buf, blocksize)) > 0){
|
Venetian@7
|
74 for (k = 0 ; k < readcount ; k++){
|
Venetian@7
|
75 //d.clear();
|
Venetian@7
|
76 frame[k] = 0;
|
Venetian@7
|
77
|
Venetian@7
|
78 for (m = 0 ; m < channels ; m++){
|
Venetian@7
|
79 frame[k] += buf[k*channels + 0];//sum the channels together
|
Venetian@7
|
80 //d.push_back(buf [k * channels + m]);
|
Venetian@7
|
81 }
|
Venetian@7
|
82
|
Venetian@7
|
83 frame[k] /= channels;//average of the channels
|
Venetian@7
|
84 }
|
Venetian@7
|
85
|
Venetian@7
|
86 processAudioFrame(frame, blocksize);
|
Venetian@7
|
87 processYinAudio(frame, blocksize);
|
Venetian@7
|
88 //have now processed framecount samples
|
Venetian@7
|
89 processBassPitches();
|
Venetian@7
|
90
|
Venetian@7
|
91 //add to our buffer for pocessing
|
Venetian@7
|
92 for (int i = 0; i< frameSize-hopSize;i++)
|
Venetian@7
|
93 {
|
Venetian@7
|
94 buffer[i] = buffer[i+hopSize];
|
Venetian@7
|
95 buffer[i+hopSize] = frame[i];
|
Venetian@7
|
96 }
|
Venetian@7
|
97
|
Venetian@7
|
98 //printf("read %i samples\n", readcount);
|
Venetian@7
|
99 //was sf_write_double(outfile, frame, readcount) ;
|
Venetian@7
|
100
|
Venetian@7
|
101 }//end readcount
|
Venetian@7
|
102 //END STEREO OKAY
|
Venetian@7
|
103
|
Venetian@7
|
104 // Close input file
|
Venetian@7
|
105 sf_close (infile);
|
Venetian@7
|
106
|
Venetian@7
|
107 endProcessing();
|
Venetian@7
|
108
|
Venetian@7
|
109 return 0;
|
Venetian@7
|
110
|
Venetian@7
|
111 }
|
Venetian@7
|
112
|
Venetian@7
|
113 void PreciseBassOnsetDetectorOffline::processYinAudio(float* frame, int blocksize){
|
Venetian@7
|
114 //continually update yin
|
Venetian@7
|
115 yule.processBuffer(frame, (int)blocksize);
|
Venetian@7
|
116 }
|
Venetian@7
|
117
|
Venetian@7
|
118 void PreciseBassOnsetDetectorOffline::processBassPitches(){
|
Venetian@7
|
119 int tmpIndex = onsetList.size()-1;
|
Venetian@7
|
120 int hsize = 1024;
|
Venetian@7
|
121 while (tmpIndex >= 0 && onsetList[tmpIndex].positionSamples+8192+hsize>sampleCount){
|
Venetian@7
|
122 // printf("testing onset %i at %i, samplecount now %i diff %i\n", tmpIndex, onsetList[tmpIndex].positionSamples, sampleCount, sampleCount-onsetList[tmpIndex].positionSamples);
|
Venetian@7
|
123 if (onsetList[tmpIndex].positionSamples+8192 <= sampleCount && !onsetList[tmpIndex].pitch){
|
Venetian@7
|
124 //do yin value for this onset
|
Venetian@7
|
125 onsetList[tmpIndex].pitch = yule.yinFrequency;
|
Venetian@7
|
126
|
Venetian@7
|
127 float midiPitch = onsetList[tmpIndex].pitch/27.5;
|
Venetian@7
|
128 if (midiPitch > 0){
|
Venetian@7
|
129 midiPitch = 12.0*log(midiPitch)/log(2);
|
Venetian@7
|
130 midiPitch += 24+9;
|
Venetian@7
|
131 }
|
Venetian@7
|
132
|
Venetian@7
|
133 onsetList[tmpIndex].midiPitch = midiPitch;
|
Venetian@7
|
134 onsetList[tmpIndex].roundedPitch = round(midiPitch);
|
Venetian@7
|
135
|
Venetian@7
|
136 setMidiNoteString(tmpIndex, midiPitch);//sets string eg C#4
|
Venetian@7
|
137
|
Venetian@7
|
138 if (printingOn)
|
Venetian@7
|
139 printf("PBODO: Yin Pitch %i, %f, %f, %s\n", tmpIndex, onsetList[tmpIndex].pitch, midiPitch, onsetList[tmpIndex].midiName.c_str());
|
Venetian@7
|
140 }
|
Venetian@7
|
141
|
Venetian@7
|
142 tmpIndex--;
|
Venetian@7
|
143 }
|
Venetian@7
|
144 }
|
Venetian@7
|
145
|
Venetian@7
|
146 void PreciseBassOnsetDetectorOffline::printOnsetLocations(){
|
Venetian@7
|
147 for (int i = 0; i < (int)onsetList.size(); i++)
|
Venetian@7
|
148 printf("PBODO: Onset[%i]: %.3f, samples %i pitch %f, %i\n", i, onsetList[i].onsetLocation, onsetList[i].positionSamples, onsetList[i].pitch, onsetList[i].roundedPitch);
|
Venetian@7
|
149 }
|
Venetian@7
|
150
|
Venetian@7
|
151 void PreciseBassOnsetDetectorOffline::printPitchInfo(){
|
Venetian@7
|
152 for (int i = 0; i < (int)onsetList.size(); i++)
|
Venetian@7
|
153 printf("PBODO: Beat Position %i,%i: pitch %i\n", onsetList[i].beatPosition, onsetList[i].onsetType, onsetList[i].roundedPitch);
|
Venetian@7
|
154 }
|
Venetian@7
|
155
|
Venetian@7
|
156 void PreciseBassOnsetDetectorOffline::setMidiNoteString(int index, float midiPitch){
|
Venetian@7
|
157 std:string midiName = "";
|
Venetian@7
|
158 if (midiPitch > 0){
|
Venetian@7
|
159 midiPitch = round(midiPitch);
|
Venetian@7
|
160 int midiLetter = (int)midiPitch%12;
|
Venetian@7
|
161 int midiOctave = midiPitch - (int)midiPitch%12;
|
Venetian@7
|
162
|
Venetian@7
|
163 switch (midiLetter) {
|
Venetian@7
|
164 case 0:
|
Venetian@7
|
165 midiName = "C ";
|
Venetian@7
|
166 break;
|
Venetian@7
|
167 case 1:
|
Venetian@7
|
168 midiName = "C#";
|
Venetian@7
|
169 break;
|
Venetian@7
|
170 case 2:
|
Venetian@7
|
171 midiName = "D";
|
Venetian@7
|
172 break;
|
Venetian@7
|
173 case 3:
|
Venetian@7
|
174 midiName = "D#";
|
Venetian@7
|
175 break;
|
Venetian@7
|
176 case 4:
|
Venetian@7
|
177 midiName = "E";
|
Venetian@7
|
178 break;
|
Venetian@7
|
179 case 5:
|
Venetian@7
|
180 midiName = "F ";
|
Venetian@7
|
181 break;
|
Venetian@7
|
182 case 6:
|
Venetian@7
|
183 midiName = "F#";
|
Venetian@7
|
184 break;
|
Venetian@7
|
185 case 7:
|
Venetian@7
|
186 midiName = "G ";
|
Venetian@7
|
187 break;
|
Venetian@7
|
188 case 8:
|
Venetian@7
|
189 midiName = "G#";
|
Venetian@7
|
190 break;
|
Venetian@7
|
191 case 9:
|
Venetian@7
|
192 midiName = "A ";
|
Venetian@7
|
193 break;
|
Venetian@7
|
194 case 10:
|
Venetian@7
|
195 midiName = "A#";
|
Venetian@7
|
196 break;
|
Venetian@7
|
197 case 11:
|
Venetian@7
|
198 midiName = "B ";
|
Venetian@7
|
199 break;
|
Venetian@7
|
200 default:
|
Venetian@7
|
201 break;
|
Venetian@7
|
202 }
|
Venetian@7
|
203
|
Venetian@7
|
204 midiName += ofToString(midiOctave/12);
|
Venetian@7
|
205 }
|
Venetian@7
|
206 if (index < onsetList.size())
|
Venetian@7
|
207 onsetList[index].midiName = midiName;
|
Venetian@7
|
208
|
Venetian@7
|
209 }
|
Venetian@7
|
210
|
Venetian@7
|
211
|
Venetian@7
|
212 /*
|
Venetian@7
|
213 #pragma mark Quantisation
|
Venetian@7
|
214 void PreciseBassOnsetDetectorOffline::categoriseOnsets(std::vector<double> beatTimes){
|
Venetian@7
|
215 double onsetTime;
|
Venetian@7
|
216 for (int i = 0; i < onsetList.size(); i++){
|
Venetian@7
|
217
|
Venetian@7
|
218 onsetTime = onsetList[i].onsetLocation;
|
Venetian@7
|
219
|
Venetian@7
|
220 int beatIndex = 0;
|
Venetian@7
|
221 while(beatIndex < beatTimes.size() && beatTimes[beatIndex] < onsetTime){
|
Venetian@7
|
222 beatIndex++;
|
Venetian@7
|
223 }
|
Venetian@7
|
224 while(beatIndex > 0 && beatTimes[beatIndex] > onsetTime){
|
Venetian@7
|
225 beatIndex--;
|
Venetian@7
|
226 }
|
Venetian@7
|
227 //beatIndex now either side of onset, or onset before first beat
|
Venetian@7
|
228
|
Venetian@7
|
229 printf("beat %.2f, beat+1 %.2f, onset %.2f freq %.2f, ", beatAtIndex(beatTimes, beatIndex),
|
Venetian@7
|
230 beatAtIndex(beatTimes, beatIndex+1), onsetTime, onsetList[i].pitch);
|
Venetian@7
|
231
|
Venetian@7
|
232 double beatTime = beatAtIndex(beatTimes, beatIndex);//vampBeats.vampBeatAtIndex(beatIndex);
|
Venetian@7
|
233
|
Venetian@7
|
234
|
Venetian@7
|
235 double diff = onsetTime - beatTime;
|
Venetian@7
|
236 double nextBeat = beatAtIndex(beatTimes, beatIndex+1);
|
Venetian@7
|
237 double period;
|
Venetian@7
|
238 if (nextBeat){
|
Venetian@7
|
239 period = nextBeat - beatAtIndex(beatTimes, beatIndex);
|
Venetian@7
|
240 } else {
|
Venetian@7
|
241 period = beatAtIndex(beatTimes, beatIndex) - beatAtIndex(beatTimes, beatIndex-1);
|
Venetian@7
|
242 }
|
Venetian@7
|
243 if (period > 0){
|
Venetian@7
|
244 while (diff < 0){
|
Venetian@7
|
245 diff += period;
|
Venetian@7
|
246 //i.e. add the beat period to bring it in range
|
Venetian@7
|
247 }
|
Venetian@7
|
248 //now can look which point it is nearest
|
Venetian@7
|
249 double ratio = diff/period;
|
Venetian@7
|
250 ratio *= 12;
|
Venetian@7
|
251 int beattype = round(ratio);
|
Venetian@7
|
252 if (beattype == 12){
|
Venetian@7
|
253 beattype = 0;
|
Venetian@7
|
254 beatIndex++;//added need to test
|
Venetian@7
|
255 }
|
Venetian@7
|
256
|
Venetian@7
|
257 doCorrection(beattype, beatIndex);
|
Venetian@7
|
258
|
Venetian@7
|
259
|
Venetian@7
|
260
|
Venetian@7
|
261 // Onset newOnset;
|
Venetian@7
|
262 // newOnset.time = onsetTime;
|
Venetian@7
|
263 // newOnset.onsetType = beattype;
|
Venetian@7
|
264 int position = beatIndex%4;
|
Venetian@7
|
265
|
Venetian@7
|
266 // if (onsetTime > beatTime + (period/2.))
|
Venetian@7
|
267 // pos++;
|
Venetian@7
|
268 // newOnset.position = pos%4;
|
Venetian@7
|
269
|
Venetian@7
|
270 onsetList[i].beatPosition = beatIndex;
|
Venetian@7
|
271 onsetList[i].onsetType = beattype;
|
Venetian@7
|
272
|
Venetian@7
|
273 printf("Pitch %i, Position %i,%i\n", onsetList[i].roundedPitch, onsetList[i].beatPosition, beattype);
|
Venetian@7
|
274 }
|
Venetian@7
|
275
|
Venetian@7
|
276 }
|
Venetian@7
|
277 }
|
Venetian@7
|
278 */
|
Venetian@7
|
279
|
Venetian@7
|
280 #pragma mark PredictionProcess
|
Venetian@7
|
281 void PreciseBassOnsetDetectorOffline::predictionProcess(){
|
Venetian@7
|
282
|
Venetian@7
|
283
|
Venetian@7
|
284
|
Venetian@7
|
285 //NOW do do precition
|
Venetian@7
|
286 int optimalLag = getOptimalLag();
|
Venetian@7
|
287 checkPrediction(optimalLag);
|
Venetian@7
|
288
|
Venetian@7
|
289 checkPredictionFirstOrderMarkovCorrect(optimalLag);
|
Venetian@7
|
290
|
Venetian@7
|
291 //checkBars(); - not quite sure what the idea here was
|
Venetian@7
|
292
|
Venetian@7
|
293 /*
|
Venetian@7
|
294 beatInfo.clear();
|
Venetian@7
|
295
|
Venetian@7
|
296 int tmpIndex = 0;
|
Venetian@7
|
297 double nearestOnset = preciseDetector.pod.onsetAtIndex(0);//start with first
|
Venetian@7
|
298 for (int beatIndex = 0; beatIndex < beatTimes.size(); beatIndex++){
|
Venetian@7
|
299 double newBeatTime = beatTimes[beatIndex];
|
Venetian@7
|
300 printf("BEAT %i: %f, ", beatIndex, newBeatTime);
|
Venetian@7
|
301 double diff = pod.onsetAtIndex(tmpIndex) - newBeatTime;
|
Venetian@7
|
302 while (fabs(pod.onsetAtIndex(tmpIndex+1) - newBeatTime) < fabs(diff)){
|
Venetian@7
|
303 tmpIndex++;
|
Venetian@7
|
304 nearestOnset = pod.onsetAtIndex(tmpIndex);
|
Venetian@7
|
305 diff = pod.onsetAtIndex(tmpIndex) - newBeatTime;
|
Venetian@7
|
306 printf("testing %f, ", nearestOnset);
|
Venetian@7
|
307 }
|
Venetian@7
|
308
|
Venetian@7
|
309
|
Venetian@7
|
310 Beat newBeat(false);
|
Venetian@7
|
311 newBeat.onsetFound = false;
|
Venetian@7
|
312 if (fabs(nearestOnset - newBeatTime) < thresholdForBeat){
|
Venetian@7
|
313 newBeat.onsetFound = true;
|
Venetian@7
|
314 newBeat.onsetDifference = nearestOnset - newBeatTime;
|
Venetian@7
|
315 printf("nearest onset %f\n", nearestOnset);
|
Venetian@7
|
316 } else
|
Venetian@7
|
317 printf("no onset %f\n", nearestOnset);
|
Venetian@7
|
318 //within 80 msec we say the onset is attributable to the beat location
|
Venetian@7
|
319 newBeat.onsetTime = nearestOnset;
|
Venetian@7
|
320 newBeat.time = newBeatTime;
|
Venetian@7
|
321 newBeat.errorFound = false;
|
Venetian@7
|
322 newBeat.period = nan(0);
|
Venetian@7
|
323 //find error
|
Venetian@7
|
324 int secondBeat = beatIndex-4;
|
Venetian@7
|
325 if (beatIndex%4 != 0)
|
Venetian@7
|
326 secondBeat = beatIndex - (beatIndex%4);
|
Venetian@7
|
327 int firstBeat = secondBeat - 4;
|
Venetian@7
|
328
|
Venetian@7
|
329 //for the one use previous bar kicks
|
Venetian@7
|
330 //otherwise recent kicks on the one
|
Venetian@7
|
331
|
Venetian@7
|
332 if (firstBeat >= 0 && secondBeat < beatInfo.size()){
|
Venetian@7
|
333 if (beatInfo[firstBeat].onsetFound && beatInfo[secondBeat].onsetFound){
|
Venetian@7
|
334 //can project
|
Venetian@7
|
335 double beatPeriod = beatInfo[secondBeat].onsetTime - beatInfo[firstBeat].onsetTime;
|
Venetian@7
|
336 beatPeriod /= 4.;
|
Venetian@7
|
337 printf("%i beat period %f, ", beatIndex, beatPeriod);
|
Venetian@7
|
338 double error = nearestOnset - (beatInfo[secondBeat].onsetTime + (beatIndex - secondBeat)*beatPeriod);
|
Venetian@7
|
339 printf("error %.1f, beat period %.1f\n", error*1000., beatPeriod*1000.);
|
Venetian@7
|
340 newBeat.errorFound = true;
|
Venetian@7
|
341 newBeat.error = error;
|
Venetian@7
|
342 newBeat.period = beatPeriod;
|
Venetian@7
|
343 }
|
Venetian@7
|
344
|
Venetian@7
|
345 }//end if error
|
Venetian@7
|
346
|
Venetian@7
|
347 beatInfo.push_back(newBeat);
|
Venetian@7
|
348
|
Venetian@7
|
349
|
Venetian@7
|
350 }
|
Venetian@7
|
351 */
|
Venetian@7
|
352
|
Venetian@7
|
353 //dtwProcess();
|
Venetian@7
|
354 }
|
Venetian@7
|
355
|
Venetian@7
|
356 int PreciseBassOnsetDetectorOffline::getOptimalLag(){
|
Venetian@7
|
357 std::vector<double> correlationScores;
|
Venetian@7
|
358 int maxCorr = 35;
|
Venetian@7
|
359
|
Venetian@7
|
360 for (int i = 0; i < maxCorr; i++){
|
Venetian@7
|
361 correlationScores.push_back(quantisedCorrelation(i));
|
Venetian@7
|
362 printf("Lag[%i] %f\n", i, correlationScores[i]);
|
Venetian@7
|
363 }
|
Venetian@7
|
364
|
Venetian@7
|
365 int optimalLag = 8;
|
Venetian@7
|
366
|
Venetian@7
|
367 BeatWriter newWriter;
|
Venetian@7
|
368 newWriter.closeFile();
|
Venetian@7
|
369 newWriter.openFile("/Users/andrewrobertson/corr_scores.txt");
|
Venetian@7
|
370
|
Venetian@7
|
371
|
Venetian@7
|
372 //make rayligh
|
Venetian@7
|
373 std::vector<double> wv;
|
Venetian@7
|
374 float rayparam = 16;
|
Venetian@7
|
375 for (int n = 0; n < maxCorr;n++){
|
Venetian@7
|
376 wv.push_back(((float) n / pow(rayparam,2)) * exp((-1*pow((float)-n,2)) / (2*pow(rayparam,2))));
|
Venetian@7
|
377 //wv.push_back(1.0 - fabs(n - 12.0)/64.0);
|
Venetian@7
|
378
|
Venetian@7
|
379 }
|
Venetian@7
|
380
|
Venetian@7
|
381 double maxScore = 0;
|
Venetian@7
|
382 for (int i = 2; i < maxCorr; i++){
|
Venetian@7
|
383 printf("Lag[%i] %f, rayleigh %f, weighted vec %f\n", i, correlationScores[i], wv[i], correlationScores[i]*wv[i]);
|
Venetian@7
|
384 if (correlationScores[i]*wv[i] > maxScore){
|
Venetian@7
|
385 maxScore = correlationScores[i]*wv[i];
|
Venetian@7
|
386 optimalLag = i;
|
Venetian@7
|
387 }
|
Venetian@7
|
388
|
Venetian@7
|
389 newWriter.outputFile << i << "\t" << correlationScores[i] << std::endl;
|
Venetian@7
|
390 }
|
Venetian@7
|
391
|
Venetian@7
|
392 newWriter.closeFile();
|
Venetian@7
|
393
|
Venetian@7
|
394 printf("Optimal lag %i\n", optimalLag);
|
Venetian@7
|
395
|
Venetian@7
|
396 return optimalLag;
|
Venetian@7
|
397 }
|
Venetian@7
|
398
|
Venetian@7
|
399
|
Venetian@7
|
400 /*
|
Venetian@7
|
401 void PreciseBassOnsetDetectorOffline::doCorrection(int& beattype, int& beatPosition){
|
Venetian@7
|
402 switch (beattype) {
|
Venetian@7
|
403 case 1:
|
Venetian@7
|
404 beattype = 0;//on beat
|
Venetian@7
|
405 break;
|
Venetian@7
|
406 case 2:
|
Venetian@7
|
407 beattype = 3;//16th
|
Venetian@7
|
408 break;
|
Venetian@7
|
409 case 5: case 7:
|
Venetian@7
|
410 beattype = 6;//8th note
|
Venetian@7
|
411 break;
|
Venetian@7
|
412 case 10:
|
Venetian@7
|
413 beattype = 9;
|
Venetian@7
|
414 break;
|
Venetian@7
|
415 case 11:
|
Venetian@7
|
416 beattype = 0;//on the beat
|
Venetian@7
|
417 beatPosition++;
|
Venetian@7
|
418 break;
|
Venetian@7
|
419 default:
|
Venetian@7
|
420 break;
|
Venetian@7
|
421 }
|
Venetian@7
|
422
|
Venetian@7
|
423 }
|
Venetian@7
|
424 */
|
Venetian@7
|
425
|
Venetian@7
|
426
|
Venetian@7
|
427
|
Venetian@7
|
428 double PreciseBassOnsetDetectorOffline::quantisedCorrelation(int lag){
|
Venetian@7
|
429
|
Venetian@7
|
430 double meanCorrelation = 0;
|
Venetian@7
|
431 int count = 0;
|
Venetian@7
|
432
|
Venetian@7
|
433 bool printResult = false;
|
Venetian@7
|
434
|
Venetian@7
|
435 for (int index = 0; index < onsetList.size(); index++){
|
Venetian@7
|
436 int midiPitch = 0;
|
Venetian@7
|
437 if (printResult)
|
Venetian@7
|
438 printf("testing %i,%i (%i): ", onsetList[index].beatPosition, onsetList[index].onsetType, onsetList[index].roundedPitch);
|
Venetian@7
|
439
|
Venetian@7
|
440 getOnsetAtBeat(index, onsetList[index].beatPosition-lag, onsetList[index].onsetType, midiPitch);
|
Venetian@7
|
441
|
Venetian@7
|
442 if (midiPitch){
|
Venetian@7
|
443 count++;
|
Venetian@7
|
444 if (midiPitch == onsetList[index].roundedPitch){
|
Venetian@7
|
445 meanCorrelation++;
|
Venetian@7
|
446 }
|
Venetian@7
|
447 if (printResult){
|
Venetian@7
|
448 printf("MIDI pitch found %i at lag %i\n", midiPitch, lag);
|
Venetian@7
|
449 } else if (printResult){
|
Venetian@7
|
450 printf("none\n");
|
Venetian@7
|
451 }
|
Venetian@7
|
452 }
|
Venetian@7
|
453 }
|
Venetian@7
|
454
|
Venetian@7
|
455 if (count > 0)
|
Venetian@7
|
456 meanCorrelation /= count;
|
Venetian@7
|
457
|
Venetian@7
|
458 return meanCorrelation;
|
Venetian@7
|
459 }
|
Venetian@7
|
460
|
Venetian@7
|
461
|
Venetian@7
|
462 void PreciseBassOnsetDetectorOffline::checkPrediction(int lag){
|
Venetian@7
|
463
|
Venetian@7
|
464 //NAIVE METHOD - JUST LOOKING BACK FOR A BASS NOTE IN SAME POSITION AT SAME LAG
|
Venetian@7
|
465
|
Venetian@7
|
466 int matches = 0;
|
Venetian@7
|
467 int octaveErrors = 0;
|
Venetian@7
|
468 int mismatches = 0;
|
Venetian@7
|
469
|
Venetian@7
|
470 bool printResult = false;//true;
|
Venetian@7
|
471
|
Venetian@7
|
472 for (int index = 0; index < onsetList.size(); index++){
|
Venetian@7
|
473 onsetList[index].midiPrediction = 0;
|
Venetian@7
|
474
|
Venetian@7
|
475 int midiPitch = 0;
|
Venetian@7
|
476 if (printResult)
|
Venetian@7
|
477 printf("prediction %i,%i (%i): ", onsetList[index].beatPosition, onsetList[index].onsetType, onsetList[index].roundedPitch);
|
Venetian@7
|
478
|
Venetian@7
|
479 int k = 1;
|
Venetian@7
|
480 while (onsetList[index].beatPosition - k *lag >= 0){
|
Venetian@7
|
481
|
Venetian@7
|
482 int tmp = getOnsetAtBeat(index, onsetList[index].beatPosition-(k*lag), onsetList[index].onsetType, midiPitch);
|
Venetian@7
|
483
|
Venetian@7
|
484 // if (tmp == 0 && printResult)
|
Venetian@7
|
485 // printf("k %i, pos %i,%i : midi pred %i\n", k, onsetList[index].beatPosition-(k*lag), onsetList[index].onsetType, tmp);
|
Venetian@7
|
486
|
Venetian@7
|
487 if (midiPitch)//i.e. non zero prediction made looking back k*lag beats
|
Venetian@7
|
488 break;
|
Venetian@7
|
489
|
Venetian@7
|
490 k++;//keep looking back
|
Venetian@7
|
491 }
|
Venetian@7
|
492
|
Venetian@7
|
493 if (midiPitch){
|
Venetian@7
|
494 onsetList[index].midiPrediction = midiPitch;
|
Venetian@7
|
495
|
Venetian@7
|
496 if (printResult)
|
Venetian@7
|
497 printf(", pred %i, (lag %i) ", midiPitch, k);
|
Venetian@7
|
498
|
Venetian@7
|
499 if (midiPitch == onsetList[index].roundedPitch){
|
Venetian@7
|
500 onsetList[index].matchIndicator = 1;
|
Venetian@7
|
501 matches++;
|
Venetian@7
|
502 if (printResult)
|
Venetian@7
|
503 printf(", MATCH");
|
Venetian@7
|
504
|
Venetian@7
|
505 }
|
Venetian@7
|
506
|
Venetian@7
|
507 if (midiPitch && onsetList[index].roundedPitch && abs(midiPitch - onsetList[index].roundedPitch) == 12){
|
Venetian@7
|
508 octaveErrors++;
|
Venetian@7
|
509 if (printResult)
|
Venetian@7
|
510 printf(", OCTAVE %i", onsetList[index].roundedPitch-midiPitch);
|
Venetian@7
|
511 }
|
Venetian@7
|
512 else if (midiPitch && onsetList[index].roundedPitch && midiPitch != onsetList[index].roundedPitch){
|
Venetian@7
|
513 mismatches++;
|
Venetian@7
|
514 if (printResult)
|
Venetian@7
|
515 printf(", NOT");
|
Venetian@7
|
516 }
|
Venetian@7
|
517 }
|
Venetian@7
|
518
|
Venetian@7
|
519 if (printResult)
|
Venetian@7
|
520 printf("\n");
|
Venetian@7
|
521
|
Venetian@7
|
522 }
|
Venetian@7
|
523 double sum = matches+octaveErrors+mismatches;
|
Venetian@7
|
524 printf("\nResult: naive method\noptimal lag %i, matches %.3f, octaves %.3f, wrong %.3f\n", lag, matches/sum, octaveErrors/sum, mismatches/sum);
|
Venetian@7
|
525 }
|
Venetian@7
|
526
|
Venetian@7
|
527
|
Venetian@7
|
528 int PreciseBassOnsetDetectorOffline::getOnsetAtBeat(int tmpIndex, int beatPosition, int beatType, int& midiPitch){
|
Venetian@7
|
529 bool onsetFound = false;
|
Venetian@7
|
530 while (tmpIndex >= 0 && onsetList[tmpIndex].beatPosition >= beatPosition){
|
Venetian@7
|
531 if (onsetList[tmpIndex].beatPosition == beatPosition && onsetList[tmpIndex].onsetType == beatType){
|
Venetian@7
|
532 midiPitch = onsetList[tmpIndex].roundedPitch;
|
Venetian@7
|
533 //printf("beat pos %i,%i: pitch %i\n", beatPosition, beatType, midiPitch);
|
Venetian@7
|
534 onsetFound = true;
|
Venetian@7
|
535 break;
|
Venetian@7
|
536 }
|
Venetian@7
|
537 tmpIndex--;
|
Venetian@7
|
538 }
|
Venetian@7
|
539 return onsetFound;
|
Venetian@7
|
540
|
Venetian@7
|
541 }
|
Venetian@7
|
542
|
Venetian@7
|
543
|
Venetian@7
|
544
|
Venetian@7
|
545
|
Venetian@7
|
546 void PreciseBassOnsetDetectorOffline::checkPredictionFirstOrderMarkovCorrect(int lag){
|
Venetian@7
|
547
|
Venetian@7
|
548 //LOOKING BACK, NOW REQUIRE ANOTHER CORRECT BASS NOTE RECENT BEAT POSITION
|
Venetian@7
|
549 //hard to find
|
Venetian@7
|
550 printf("First Order check\n");
|
Venetian@7
|
551
|
Venetian@7
|
552
|
Venetian@7
|
553 int matches = 0;
|
Venetian@7
|
554 int octaveErrors = 0;
|
Venetian@7
|
555 int mismatches = 0;
|
Venetian@7
|
556
|
Venetian@7
|
557 bool printResult = false;//rue;
|
Venetian@7
|
558
|
Venetian@7
|
559 if (printResult)
|
Venetian@7
|
560 printPitchInfo();
|
Venetian@7
|
561
|
Venetian@7
|
562 for (int index = 0; index < onsetList.size(); index++){
|
Venetian@7
|
563 onsetList[index].midiPrediction = 0;
|
Venetian@7
|
564
|
Venetian@7
|
565 int midiPitch = 0;
|
Venetian@7
|
566 int previousMidiPitch = 0;
|
Venetian@7
|
567
|
Venetian@7
|
568 if (printResult)
|
Venetian@7
|
569 printf("\nBeat Position %i,%i:\n", onsetList[index].beatPosition, onsetList[index].onsetType);
|
Venetian@7
|
570
|
Venetian@7
|
571 int k = 1;
|
Venetian@7
|
572
|
Venetian@7
|
573 int previousOffset = 1;//the note before
|
Venetian@7
|
574 while (index - previousOffset >= 0 && (onsetList[index-previousOffset].onsetType != 0 || !onsetList[index-previousOffset].roundedPitch)){
|
Venetian@7
|
575 //printf("rejected: index %i offset %i onset type %i pitch %i\n", index, previousOffset, onsetList[index-previousOffset].onsetType, onsetList[index-previousOffset].roundedPitch);
|
Venetian@7
|
576 previousOffset++;
|
Venetian@7
|
577 }
|
Venetian@7
|
578
|
Venetian@7
|
579
|
Venetian@7
|
580 if (printResult){
|
Venetian@7
|
581 printf("\nBeat Position %i,%i (midi %i, prev %i,%i: %i):\n", onsetList[index].beatPosition, onsetList[index].onsetType, onsetList[index].roundedPitch, onsetList[index-previousOffset].beatPosition, onsetList[index-previousOffset].onsetType, onsetList[index-previousOffset].roundedPitch);
|
Venetian@7
|
582 printf("Previous position is %i,%i offset %i, previous pitch %i\n", onsetList[index-previousOffset].beatPosition, onsetList[index-previousOffset].onsetType, previousOffset, onsetList[index-previousOffset].roundedPitch);
|
Venetian@7
|
583 }
|
Venetian@7
|
584
|
Venetian@7
|
585 bool printit = false;
|
Venetian@7
|
586 //first try our new markov condition
|
Venetian@7
|
587 while (onsetList[index].beatPosition - k *lag >= 0){
|
Venetian@7
|
588
|
Venetian@7
|
589 if(getOnsetAtBeat(index, onsetList[index].beatPosition-(k*lag), onsetList[index].onsetType, midiPitch)
|
Venetian@7
|
590 && getOnsetAtBeat(index - previousOffset, onsetList[index - previousOffset].beatPosition - (k*lag), onsetList[index-previousOffset].onsetType, previousMidiPitch))
|
Venetian@7
|
591 {
|
Venetian@7
|
592 if (printit)
|
Venetian@7
|
593 printf("k %i Predicted pitch %i Lag previous pitch %i \n", k, midiPitch, previousMidiPitch);
|
Venetian@7
|
594 //midi picth is what we would do precition as, but require that the previous note also match our last observed note
|
Venetian@7
|
595
|
Venetian@7
|
596 //onset found at beat pos - k*lag
|
Venetian@7
|
597 //then is the same
|
Venetian@7
|
598
|
Venetian@7
|
599 bool goodPrediction = false;
|
Venetian@7
|
600 if (previousMidiPitch == onsetList[index-previousOffset].roundedPitch){
|
Venetian@7
|
601 goodPrediction = true;
|
Venetian@7
|
602 if (printit)
|
Venetian@7
|
603 printf("Previous Found! Lag %i Lag previous pitch %i\nPrediction %i", k, onsetList[index-previousOffset].roundedPitch, previousMidiPitch, midiPitch);
|
Venetian@7
|
604 }
|
Venetian@7
|
605
|
Venetian@7
|
606
|
Venetian@7
|
607
|
Venetian@7
|
608 if (midiPitch && goodPrediction)//i.e. non zero prediction made looking back k*lag beats
|
Venetian@7
|
609 {
|
Venetian@7
|
610 if (printit)
|
Venetian@7
|
611 printf("MIDI PREDICTION IS %i\n", midiPitch);
|
Venetian@7
|
612 break;
|
Venetian@7
|
613 }
|
Venetian@7
|
614 }
|
Venetian@7
|
615 k++;//keep looking back
|
Venetian@7
|
616 }
|
Venetian@7
|
617
|
Venetian@7
|
618
|
Venetian@7
|
619 if (!midiPitch){
|
Venetian@7
|
620 k = 1;
|
Venetian@7
|
621 while (onsetList[index].beatPosition - k *lag >= 0){
|
Venetian@7
|
622
|
Venetian@7
|
623 int tmp = getOnsetAtBeat(index, onsetList[index].beatPosition-(k*lag), onsetList[index].onsetType, midiPitch);
|
Venetian@7
|
624
|
Venetian@7
|
625 if (midiPitch)//i.e. non zero prediction made looking back k*lag beats
|
Venetian@7
|
626 break;
|
Venetian@7
|
627
|
Venetian@7
|
628 k++;//keep looking back
|
Venetian@7
|
629 }
|
Venetian@7
|
630 }
|
Venetian@7
|
631
|
Venetian@7
|
632 if (midiPitch){//only test non zero
|
Venetian@7
|
633 onsetList[index].midiPrediction = midiPitch;
|
Venetian@7
|
634
|
Venetian@7
|
635 if (printResult)
|
Venetian@7
|
636 printf(", pred %i, (lag %i) ", midiPitch, k);
|
Venetian@7
|
637
|
Venetian@7
|
638 if (midiPitch == onsetList[index].roundedPitch){
|
Venetian@7
|
639 onsetList[index].matchIndicator = 1;
|
Venetian@7
|
640 matches++;
|
Venetian@7
|
641 if (printResult)
|
Venetian@7
|
642 printf(", MATCH");
|
Venetian@7
|
643
|
Venetian@7
|
644 }
|
Venetian@7
|
645
|
Venetian@7
|
646 if (midiPitch && onsetList[index].roundedPitch && abs(midiPitch - onsetList[index].roundedPitch) == 12){
|
Venetian@7
|
647 octaveErrors++;
|
Venetian@7
|
648 if (printResult)
|
Venetian@7
|
649 printf(", OCTAVE %i", onsetList[index].roundedPitch-midiPitch);
|
Venetian@7
|
650 }
|
Venetian@7
|
651 else if (midiPitch && onsetList[index].roundedPitch && midiPitch != onsetList[index].roundedPitch){
|
Venetian@7
|
652 mismatches++;
|
Venetian@7
|
653 if (printResult)
|
Venetian@7
|
654 printf(", NOT");
|
Venetian@7
|
655 }
|
Venetian@7
|
656 }
|
Venetian@7
|
657
|
Venetian@7
|
658 if (printResult)
|
Venetian@7
|
659 printf("\n");
|
Venetian@7
|
660
|
Venetian@7
|
661 }
|
Venetian@7
|
662 double sum = matches+octaveErrors+mismatches;
|
Venetian@7
|
663 printf("Results : First Oreder Markov Correct\nOptimal lag %i, matches %.3f, octaves %.3f, wrong %.3f\n", lag, matches/sum, octaveErrors/sum, mismatches/sum);
|
Venetian@7
|
664 }
|
Venetian@7
|
665
|
Venetian@7
|
666
|
Venetian@7
|
667
|
Venetian@7
|
668 void PreciseBassOnsetDetectorOffline::checkBars(){
|
Venetian@7
|
669 int bar = 0;
|
Venetian@7
|
670 double barScore = 0;
|
Venetian@7
|
671 double barCount;
|
Venetian@7
|
672 std::vector<double> scorePerBar;
|
Venetian@7
|
673 for (int index = 0; index < onsetList.size(); index++){
|
Venetian@7
|
674 while (bar*4 < onsetList[index].beatPosition){
|
Venetian@7
|
675 if (barCount > 0)
|
Venetian@7
|
676 barScore /= barCount;
|
Venetian@7
|
677 scorePerBar.push_back(barScore);
|
Venetian@7
|
678 //now going to next bar so reinitialise
|
Venetian@7
|
679 bar++;
|
Venetian@7
|
680 barScore = 0;
|
Venetian@7
|
681 barCount = 0;
|
Venetian@7
|
682 }
|
Venetian@7
|
683 barScore += onsetList[index].matchIndicator;
|
Venetian@7
|
684 barCount++;
|
Venetian@7
|
685
|
Venetian@7
|
686 }
|
Venetian@7
|
687
|
Venetian@7
|
688 for (int i = 0; i < scorePerBar.size(); i++)
|
Venetian@7
|
689 printf("Score bar [%i] %f\n", i, scorePerBar[i]);
|
Venetian@7
|
690 }
|
Venetian@7
|
691
|
Venetian@7
|
692
|