annotate Source/aubioOnsetDetect~.cpp @ 6:6a95d8b80393 tip

unknown changes
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 26 Nov 2012 23:17:34 +0000
parents eba88b84b5ca
children
rev   line source
andrew@0 1 /**
andrew@0 2 @file
andrew@0 3 aubioOnsetDetect - an MSP object shell
andrew@0 4 jeremy bernstein - jeremy@bootsquad.com
andrew@0 5
andrew@0 6 @ingroup examples
andrew@0 7 */
andrew@0 8
andrew@0 9 #include "ext.h" // standard Max include, always required (except in Jitter)
andrew@0 10 #include "ext_obex.h" // required for new style objects
andrew@0 11 #include "z_dsp.h" // required for MSP objects
andrew@0 12 #include "AubioOnsetDetector.h"
andrew@0 13 #include "aubio.h"
andrew@0 14
andrew@0 15 ////////////////////////// object struct
andrew@0 16 typedef struct _aubioOnsetDetect
andrew@0 17 {
andrew@0 18 t_pxobject ob; // the object itself (t_pxobject in MSP)
andrew@0 19
andrew@0 20 t_float threshold;
andrew@0 21 t_float threshold2;
andrew@0 22 t_int bufsize;
andrew@0 23 t_int hopsize;
andrew@0 24
andrew@0 25 AubioOnsetDetector *onsetDetector;
andrew@0 26
andrew@3 27
andrew@0 28 void *bangoutlet;
andrew@0 29 void *medianBangOutlet;
andrew@0 30
andrew@0 31 void *detectionFunctionOutlet;
andrew@0 32 void *rawDetectionFunctionOutlet;
andrew@0 33 void *medianDetectionFunctionOutlet;
andrew@0 34
andrew@6 35 // bool useMedianOnsetDetection;//(true)
andrew@0 36 //rather than Paul B's peak picking (false)
andrew@0 37
andrew@0 38 } t_aubioOnsetDetect;
andrew@0 39
andrew@0 40 ///////////////////////// function prototypes
andrew@0 41 //// standard set
andrew@0 42 void *aubioOnsetDetect_new(t_symbol *s, long argc, t_atom *argv);
andrew@0 43 void aubioOnsetDetect_free(t_aubioOnsetDetect *x);
andrew@0 44 void aubioOnsetDetect_assist(t_aubioOnsetDetect *x, void *b, long m, long a, char *s);
andrew@0 45
andrew@0 46 void aubioOnsetDetect_float(t_aubioOnsetDetect *x, double f);
andrew@4 47 void aubioOnsetDetect_setBuffersize(t_aubioOnsetDetect *x, int i);
andrew@4 48 void aubioOnsetDetect_setHopsize(t_aubioOnsetDetect *x, int i);
andrew@0 49 void aubioOnsetDetect_energy(t_aubioOnsetDetect *x);
andrew@0 50 void aubioOnsetDetect_hfc(t_aubioOnsetDetect *x);
andrew@0 51 void aubioOnsetDetect_complex(t_aubioOnsetDetect *x);
andrew@0 52 void aubioOnsetDetect_phase(t_aubioOnsetDetect *x);
andrew@0 53 void aubioOnsetDetect_specdiff(t_aubioOnsetDetect *x);
andrew@0 54 void aubioOnsetDetect_kl(t_aubioOnsetDetect *x);
andrew@0 55 void aubioOnsetDetect_mkl(t_aubioOnsetDetect *x);
andrew@0 56
andrew@0 57 void aubioOnsetDetect_dsp(t_aubioOnsetDetect *x, t_signal **sp, short *count);
andrew@0 58 t_int *aubioOnsetDetect_perform(t_int *w);
andrew@0 59 //////////////////////// global class pointer variable
andrew@0 60 void *aubioOnsetDetect_class;
andrew@0 61
andrew@0 62
andrew@0 63 int main(void)
andrew@0 64 {
andrew@0 65 // object initialization, note the use of dsp_free for the freemethod, which is required
andrew@0 66 // unless you need to free allocated memory, in which case you should call dsp_free from
andrew@0 67 // your custom free function.
andrew@0 68
andrew@0 69
andrew@0 70 // NEW METHOD
andrew@0 71 t_class *c;
andrew@0 72
andrew@0 73 c = class_new("aubioOnsetDetect~", (method)aubioOnsetDetect_new, (method)dsp_free, (long)sizeof(t_aubioOnsetDetect), 0L, A_GIMME, 0);
andrew@4 74 class_addmethod(c, (method)aubioOnsetDetect_setBuffersize, (char*)"setBuffersize", A_LONG, 0);
andrew@4 75 class_addmethod(c, (method)aubioOnsetDetect_setHopsize, (char*)"setHopsize", A_LONG, 0);
andrew@4 76
andrew@0 77 class_addmethod(c, (method)aubioOnsetDetect_float, (char*)"float", A_FLOAT, 0);
andrew@0 78 class_addmethod(c, (method)aubioOnsetDetect_dsp, (char*) "dsp", A_CANT, 0);
andrew@0 79 class_addmethod(c, (method)aubioOnsetDetect_assist, (char*)"assist", A_CANT, 0);
andrew@0 80
andrew@0 81 class_addmethod(c, (method)aubioOnsetDetect_energy, (char*)"energy", 0);
andrew@0 82 class_addmethod(c, (method)aubioOnsetDetect_hfc, (char*)"hfc", 0);
andrew@0 83 class_addmethod(c, (method)aubioOnsetDetect_phase, (char*)"phase", 0);
andrew@0 84 class_addmethod(c, (method)aubioOnsetDetect_complex, (char*)"complex", 0);
andrew@0 85 class_addmethod(c, (method)aubioOnsetDetect_specdiff, (char*)"specdiff", 0);
andrew@0 86 class_addmethod(c, (method)aubioOnsetDetect_kl, (char*)"kl", 0);
andrew@0 87 class_addmethod(c, (method)aubioOnsetDetect_mkl, (char*)"mkl", 0);
andrew@0 88
andrew@0 89
andrew@0 90 class_register(CLASS_BOX, c); // register class as a box class
andrew@0 91
andrew@0 92 class_dspinit(c); // new style object version of dsp_initclass();
andrew@0 93
andrew@0 94 CLASS_ATTR_FLOAT(c, "threshold", 0, t_aubioOnsetDetect, threshold);//threshold is an attribute and can be set in info page for object
andrew@0 95
andrew@0 96 aubioOnsetDetect_class = c;
andrew@0 97
andrew@0 98 return 0;
andrew@0 99 }
andrew@0 100
andrew@4 101
andrew@4 102 void aubioOnsetDetect_setBuffersize(t_aubioOnsetDetect *x, int i){
andrew@4 103 x->bufsize = i;//using fixed buffer size here.
andrew@4 104 x->hopsize = x->bufsize / 2;
andrew@4 105 object_post((t_object*)x, "Buffersize in aubioonset set to %i and hopsize to %i", x->bufsize, x->hopsize);
andrew@4 106
andrew@4 107 //set this up in AubioOnsetDetector class instead
andrew@4 108 //x->onsetDetector = new AubioOnsetDetector();
andrew@6 109
andrew@4 110 x->onsetDetector->buffersize = x->bufsize;
andrew@4 111 x->onsetDetector->hopsize = x->hopsize;
andrew@5 112 // x->onsetDetector->threshold = x->threshold;
andrew@5 113 // x->onsetDetector->threshold2 = x->threshold2;
andrew@4 114 x->onsetDetector->initialise();
andrew@4 115 }
andrew@4 116
andrew@4 117 void aubioOnsetDetect_setHopsize(t_aubioOnsetDetect *x, int i){
andrew@4 118 if (i < x->bufsize && x->hopsize > 0){
andrew@4 119 x->hopsize = i;
andrew@4 120 object_post((t_object*)x, "Hopsize now set to %i and Buffersize set to %i", x->hopsize, x->bufsize);
andrew@4 121
andrew@4 122 //set this up in AubioOnsetDetector class instead
andrew@4 123 // x->onsetDetector = new AubioOnsetDetector();
andrew@4 124 x->onsetDetector->buffersize = x->bufsize;
andrew@4 125 x->onsetDetector->hopsize = x->hopsize;
andrew@5 126 // x->onsetDetector->threshold = x->threshold;
andrew@5 127 // x->onsetDetector->threshold2 = x->threshold2;
andrew@4 128 x->onsetDetector->initialise();
andrew@4 129 }
andrew@4 130 }
andrew@4 131
andrew@4 132
andrew@0 133 void aubioOnsetDetect_float(t_aubioOnsetDetect *x, double f)
andrew@0 134 {
andrew@0 135 if (f < 10 || f > 0.1){
andrew@0 136 x->threshold = f;
andrew@0 137 x->onsetDetector->threshold = f;
andrew@0 138 }
andrew@0 139 //post("Threshold is %f", x->threshold);
andrew@0 140 }
andrew@0 141
andrew@0 142 void aubioOnsetDetect_energy(t_aubioOnsetDetect *x){
andrew@0 143 x->onsetDetector->onsetclass_energy();
andrew@0 144 post("Energy based onset detection now used by aubioOnsetDetect~.");
andrew@0 145 }
andrew@0 146
andrew@0 147 void aubioOnsetDetect_hfc(t_aubioOnsetDetect *x){
andrew@0 148 /** High Frequency Content onset detection function
andrew@0 149
andrew@0 150 This method computes the High Frequency Content (HFC) of the input spectral
andrew@0 151 frame. The resulting function is efficient at detecting percussive onsets.
andrew@0 152
andrew@0 153 Paul Masri. Computer modeling of Sound for Transformation and Synthesis of
andrew@0 154 Musical Signal. PhD dissertation, University of Bristol, UK, 1996.*/
andrew@0 155 x->onsetDetector->onsetclass_hfc();
andrew@0 156 post("High Frequency Content (Masri '96) detection now used by aubioOnsetDetect~.");
andrew@0 157 }
andrew@0 158
andrew@0 159
andrew@0 160 void aubioOnsetDetect_complex(t_aubioOnsetDetect *x){
andrew@0 161 //Complex Domain Method onset detection function
andrew@0 162 //Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain
andrew@0 163 //onset detection for musical signals. In Proceedings of the Digital Audio
andrew@0 164 //Effects Conference, DAFx-03, pages 90-93, London, UK, 2003.
andrew@0 165 x->onsetDetector->onsetclass_complex();
andrew@0 166 post("Complex domain onset detection (Duxbury et al., DaFx '03) now used by aubioOnsetDetect~.");
andrew@0 167
andrew@0 168 }
andrew@0 169
andrew@0 170 void aubioOnsetDetect_phase(t_aubioOnsetDetect *x){
andrew@0 171 /** Phase Based Method onset detection function
andrew@0 172
andrew@0 173 Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note onset
andrew@0 174 detection for music signals. In Proceedings of the IEEE International
andrew@0 175 Conference on Acoustics Speech and Signal Processing, pages 441­444,
andrew@0 176 Hong-Kong, 2003.*/
andrew@0 177 x->onsetDetector->onsetclass_phase();
andrew@0 178 object_post((t_object *) x, "Phase-based detection (Bello et al., IEEE '03) now used by aubioOnsetDetect~.");
andrew@0 179 }
andrew@0 180
andrew@0 181 void aubioOnsetDetect_specdiff(t_aubioOnsetDetect *x){
andrew@0 182 /* Spectral difference method onset detection function
andrew@0 183 Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to
andrew@0 184 rhythm analysis. In IEEE International Conference on Multimedia and Expo
andrew@0 185 (ICME 2001), pages 881­884, Tokyo, Japan, August 2001.
andrew@0 186 */
andrew@0 187 //aubio_onsetdetection_type
andrew@0 188 //aubio_onsetdetection_free (x->o);
andrew@0 189 x->onsetDetector->onsetclass_specdiff();
andrew@0 190 post("Spectral Difference (Foote and Shingo Uchihashi, ICME '01) detection now used by aubioOnsetDetect~.");
andrew@0 191
andrew@0 192
andrew@0 193 }
andrew@0 194
andrew@0 195 void aubioOnsetDetect_kl(t_aubioOnsetDetect *x){
andrew@0 196 //aubio_onsetdetection_type
andrew@0 197 //aubio_onsetdetection_free (x->o);
andrew@0 198 /** Kullback-Liebler onset detection function
andrew@0 199
andrew@0 200 Stephen Hainsworth and Malcom Macleod. Onset detection in music audio
andrew@0 201 signals. In Proceedings of the International Computer Music Conference
andrew@0 202 (ICMC), Singapore, 2003.
andrew@0 203 */
andrew@0 204
andrew@0 205 x->onsetDetector->onsetclass_kl();
andrew@0 206 post("Kullback-Liebler (Hainsworth and McLeod, ICMC '03) detection now used by aubioOnsetDetect~.");
andrew@0 207 }
andrew@0 208
andrew@0 209 void aubioOnsetDetect_mkl(t_aubioOnsetDetect *x){
andrew@0 210 /** Modified Kullback-Liebler onset detection function
andrew@0 211
andrew@0 212 Paul Brossier, ``Automatic annotation of musical audio for interactive
andrew@0 213 systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for Digital
andrew@0 214 music, Queen Mary University of London, London, UK, 2003.*/
andrew@0 215 x->onsetDetector->onsetclass_mkl();
andrew@0 216 post("Modified Kullback-Liebler (Brossier, PhD thesis '03) detection now used by aubioOnsetDetect~.");
andrew@0 217 }
andrew@0 218
andrew@0 219
andrew@0 220
andrew@0 221 // this function is called when the DAC is enabled, and "registers" a function
andrew@0 222 // for the signal chain. in this case, "aubioOnsetDetect_perform"
andrew@0 223 void aubioOnsetDetect_dsp(t_aubioOnsetDetect *x, t_signal **sp, short *count)
andrew@0 224 {
andrew@0 225 // dsp_add
andrew@0 226 // 1: (t_perfroutine p) perform method
andrew@0 227 // 2: (long argc) number of args to your perform method
andrew@0 228 // 3...: argc additional arguments, all must be sizeof(pointer) or long
andrew@0 229 // these can be whatever, so you might want to include your object pointer in there
andrew@0 230 // so that you have access to the info, if you need it.
andrew@0 231 dsp_add(aubioOnsetDetect_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
andrew@0 232 }
andrew@0 233
andrew@0 234 t_int *aubioOnsetDetect_perform(t_int *w)
andrew@0 235 {
andrew@0 236 // DO NOT CALL post IN HERE, but you can call defer_low (not defer)
andrew@0 237
andrew@0 238 // args are in a vector, sized as specified in aubioOnsetDetect_dsp method
andrew@0 239 // w[0] contains &aubioOnsetDetect_perform, so we start at w[1]
andrew@0 240 t_aubioOnsetDetect *x = (t_aubioOnsetDetect *)(w[1]);
andrew@0 241 t_float *inL = (t_float *)(w[2]);
andrew@0 242 t_float *outL = (t_float *)(w[3]);
andrew@0 243 int n = (int)w[4];
andrew@0 244
andrew@0 245 float frame[n];
andrew@0 246 int j;
andrew@0 247 for (j=0;j<n;j++) {
andrew@0 248 frame[j] = (float) inL[j];//must cast to float or is type t_float
andrew@0 249 }
andrew@0 250 // aubio onset detector then processes current frame - returns bool true when new detection is output
andrew@0 251 if (x->onsetDetector->processframe(frame, n)){
andrew@0 252 //if buffer full and new result is processed (buffer is 1024 with hopsize 512 - can be set to other values)
andrew@6 253
andrew@6 254 outlet_float(x->medianDetectionFunctionOutlet, x->onsetDetector->bestSlopeMedian);
andrew@6 255 /*
andrew@6 256 //idea for getting processed value out
andrew@6 257 if (x->onsetDetector->rawDetectionValue > x->onsetDetector->medianDetectionValue)
andrew@6 258 outlet_float(x->medianDetectionFunctionOutlet, x->onsetDetector->rawDetectionValue - x->onsetDetector->medianDetectionValue);
andrew@6 259 else
andrew@6 260 outlet_float(x->medianDetectionFunctionOutlet, 0.0);
andrew@6 261 */
andrew@6 262
andrew@0 263 outlet_float(x->rawDetectionFunctionOutlet, x->onsetDetector->rawDetectionValue);
andrew@1 264 // outlet_float(x->detectionFunctionOutlet, x->onsetDetector->peakPickedDetectionValue);
andrew@1 265 outlet_float(x->detectionFunctionOutlet, x->onsetDetector->bestSlopeValue);
andrew@0 266
andrew@0 267
andrew@1 268 if (x->onsetDetector->anrMedianProcessedOnsetFound)
andrew@1 269 outlet_bang(x->medianBangOutlet);
andrew@0 270
andrew@2 271 if (x->onsetDetector->anrBestSlopeOnset)
andrew@0 272 outlet_bang(x->bangoutlet);
andrew@0 273
andrew@0 274
andrew@0 275 }//end if new aubio onset detection result
andrew@0 276
andrew@0 277 outL[j] = inL[j];//have added this so signal is "see through": outputting the input signal
andrew@0 278
andrew@0 279 // you have to return the NEXT pointer in the array OR MAX WILL CRASH
andrew@0 280 return w + 5;
andrew@0 281 }
andrew@0 282
andrew@0 283 void aubioOnsetDetect_assist(t_aubioOnsetDetect *x, void *b, long m, long a, char *s)
andrew@0 284 {
andrew@0 285 if (m == ASSIST_INLET) { //inlet
andrew@0 286 sprintf(s, "Inlet %ld", a);
andrew@0 287 switch (a){
andrew@0 288 case 0:
andrew@0 289 sprintf(s, "Input signal and float (between 0.1 and 10) for aubio detection threshold.");
andrew@0 290 break;
andrew@0 291 case 1:
andrew@0 292 sprintf(s, "no inlet 1");
andrew@0 293 break;
andrew@0 294 }
andrew@0 295 }
andrew@0 296 else { // outlet
andrew@0 297
andrew@0 298 switch (a){
andrew@0 299 case 0:
andrew@4 300 sprintf(s, "Bang out when onset is detected according to best slope.");
andrew@0 301 break;
andrew@0 302 case 1:
andrew@4 303 sprintf(s, "best slope detection function.");
andrew@0 304 break;
andrew@0 305 case 2:
andrew@4 306 sprintf(s, "Raw aubio detection function result.");
andrew@0 307 break;
andrew@0 308 case 3:
andrew@4 309 sprintf(s, "Bang outlet according to median threshold.");
andrew@4 310 break;
andrew@4 311 case 4:
andrew@4 312 sprintf(s, "Median function");
andrew@4 313 break;
andrew@4 314
andrew@0 315 }
andrew@0 316 }
andrew@0 317 }
andrew@0 318
andrew@0 319 // NOT CALLED!, we use dsp_free for a generic free function
andrew@0 320 void aubioOnsetDetect_free(t_aubioOnsetDetect *x)
andrew@0 321 {
andrew@0 322 ;
andrew@0 323 }
andrew@0 324
andrew@0 325 void *aubioOnsetDetect_new(t_symbol *s, long argc, t_atom *argv)
andrew@0 326 {
andrew@0 327 t_aubioOnsetDetect *x = NULL;
andrew@0 328
andrew@0 329
andrew@0 330 // NEW VERSION
andrew@4 331
andrew@4 332 //note for C++ programmers:
andrew@4 333 //adding (t_class *) in the line below lets you use .cpp files instead
andrew@4 334 //then just change your external code to .cpp instead of c
andrew@5 335
andrew@0 336 if (x = (t_aubioOnsetDetect *)object_alloc((t_class *) aubioOnsetDetect_class)) {
andrew@0 337 dsp_setup((t_pxobject *)x, 1); // MSP inlets: arg is # of inlets and is REQUIRED!
andrew@0 338 // use 0 if you don't need inlets
andrew@6 339
andrew@6 340
andrew@6 341 object_post((t_object*)x, (char*) "Aubio Onset Detect Revamp found, created by Andrew Robertson from work by Paul Brossier, Queen Mary University");
andrew@6 342
andrew@6 343
andrew@5 344 //set outlets, from right to left
andrew@0 345 x->medianDetectionFunctionOutlet = floatout(x);
andrew@1 346 x->medianBangOutlet = bangout(x);
andrew@0 347 x->rawDetectionFunctionOutlet = floatout(x);
andrew@0 348 x->detectionFunctionOutlet = floatout(x);
andrew@0 349 x->bangoutlet = bangout(x);
andrew@0 350
andrew@6 351 // outlet_new(x, "signal"); - no longer
andrew@6 352
andrew@5 353 //aubio params
andrew@0 354 x->threshold = 1;
andrew@0 355 x->threshold2 = -70.;
andrew@0 356
andrew@6 357 //set this up in AubioOnsetDetector class instead
andrew@6 358 x->onsetDetector = new AubioOnsetDetector();
andrew@6 359 // x->onsetDetector->buffersize = x->bufsize;
andrew@6 360 // x->onsetDetector->hopsize = x->hopsize;
andrew@6 361 x->onsetDetector->threshold = x->threshold;
andrew@6 362 x->onsetDetector->threshold2 = x->threshold2;
andrew@4 363
andrew@6 364
andrew@0 365
andrew@6 366 if (argc > 0 && argv->a_type == A_FLOAT){//i.e. there is an argument on creation like [aubioOnsetDetect~ 0.3]
andrew@4 367 t_atom my_atom = argv[0];
andrew@6 368 object_post((t_object*)x, (char*) "Threshold argument: set to %f ", atom_getfloat(&my_atom));
andrew@4 369 x->threshold = atom_getfloat(&my_atom);
andrew@0 370
andrew@0 371 if (x->threshold > 10)
andrew@0 372 x->threshold = 10;
andrew@0 373
andrew@0 374 if (x->threshold < 0.1)
andrew@0 375 x->threshold = 0.1;
andrew@0 376
andrew@0 377 x->onsetDetector->threshold = x->threshold;
andrew@0 378 }
andrew@0 379
andrew@6 380 if (argc > 1 && (argv+1)->a_type == A_LONG){
andrew@6 381 t_atom my_atom = argv[1];
andrew@6 382 aubioOnsetDetect_setBuffersize(x, atom_getlong(&my_atom));
andrew@6 383 object_post((t_object*)x, (char*) "Buffersize argument: set to %ld ", atom_getlong(&my_atom));
andrew@6 384 } else {
andrew@6 385 x->bufsize = 1024;//using fixed buffer size here.
andrew@6 386 x->hopsize = x->bufsize / 2;
andrew@6 387 }
andrew@6 388
andrew@6 389 x->onsetDetector->initialise();
andrew@6 390
andrew@6 391 // x->useMedianOnsetDetection = true;
andrew@0 392 }
andrew@0 393 return (x);
andrew@0 394 }