view Source/aubioOnsetDetect~.cpp @ 1:a7b9c6885eb8

added in a best slope function, a mix between max increase in the recent df function and the gradient of this increase
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Tue, 18 Oct 2011 14:52:27 +0100
parents 8f67db3c0b01
children b4c899822b4e
line wrap: on
line source
/**
	@file
	aubioOnsetDetect - an MSP object shell
	jeremy bernstein - jeremy@bootsquad.com	

	@ingroup	examples	
*/

#include "ext.h"							// standard Max include, always required (except in Jitter)
#include "ext_obex.h"						// required for new style objects
#include "z_dsp.h"							// required for MSP objects
#include "AubioOnsetDetector.h"
#include "aubio.h"

////////////////////////// object struct
typedef struct _aubioOnsetDetect 
{
	t_pxobject					ob;			// the object itself (t_pxobject in MSP)

	t_float						threshold;
	t_float						threshold2;
	t_int						bufsize;
	t_int						hopsize;
	
	AubioOnsetDetector			*onsetDetector;
	
	void						*bangoutlet;
	void						*medianBangOutlet;
	
	void						*detectionFunctionOutlet;
	void						*rawDetectionFunctionOutlet;	
	void						*medianDetectionFunctionOutlet;	
	
	bool						useMedianOnsetDetection;//(true) 
								//rather than Paul B's peak picking (false)

} t_aubioOnsetDetect;

///////////////////////// function prototypes
//// standard set
void *aubioOnsetDetect_new(t_symbol *s, long argc, t_atom *argv);
void aubioOnsetDetect_free(t_aubioOnsetDetect *x);
void aubioOnsetDetect_assist(t_aubioOnsetDetect *x, void *b, long m, long a, char *s);

void aubioOnsetDetect_float(t_aubioOnsetDetect *x, double f);

void aubioOnsetDetect_energy(t_aubioOnsetDetect *x);
void aubioOnsetDetect_hfc(t_aubioOnsetDetect *x);
void aubioOnsetDetect_complex(t_aubioOnsetDetect *x);
void aubioOnsetDetect_phase(t_aubioOnsetDetect *x);
void aubioOnsetDetect_specdiff(t_aubioOnsetDetect *x);
void aubioOnsetDetect_kl(t_aubioOnsetDetect *x);
void aubioOnsetDetect_mkl(t_aubioOnsetDetect *x);

void aubioOnsetDetect_dsp(t_aubioOnsetDetect *x, t_signal **sp, short *count);
t_int *aubioOnsetDetect_perform(t_int *w);
//////////////////////// global class pointer variable
void *aubioOnsetDetect_class;


int main(void)
{	
	// object initialization, note the use of dsp_free for the freemethod, which is required
	// unless you need to free allocated memory, in which case you should call dsp_free from
	// your custom free function.

	
	// NEW METHOD
	t_class *c;
	
	c = class_new("aubioOnsetDetect~", (method)aubioOnsetDetect_new, (method)dsp_free, (long)sizeof(t_aubioOnsetDetect), 0L, A_GIMME, 0);
	
	class_addmethod(c, (method)aubioOnsetDetect_float,	(char*)"float",	A_FLOAT, 0);
	class_addmethod(c, (method)aubioOnsetDetect_dsp,	(char*)	"dsp",		A_CANT, 0);
	class_addmethod(c, (method)aubioOnsetDetect_assist,	(char*)"assist",	A_CANT, 0);
	
	class_addmethod(c, (method)aubioOnsetDetect_energy, (char*)"energy", 0);
	class_addmethod(c, (method)aubioOnsetDetect_hfc, (char*)"hfc", 0);
	class_addmethod(c, (method)aubioOnsetDetect_phase, (char*)"phase", 0);
	class_addmethod(c, (method)aubioOnsetDetect_complex, (char*)"complex", 0);
	class_addmethod(c, (method)aubioOnsetDetect_specdiff, (char*)"specdiff", 0);
	class_addmethod(c, (method)aubioOnsetDetect_kl, (char*)"kl", 0);
	class_addmethod(c, (method)aubioOnsetDetect_mkl, (char*)"mkl", 0);	
	
			
	class_register(CLASS_BOX, c); // register class as a box class
	
	class_dspinit(c); // new style object version of dsp_initclass();
	
	CLASS_ATTR_FLOAT(c, "threshold", 0, t_aubioOnsetDetect, threshold);//threshold is an attribute and can be set in info page for object
	
	aubioOnsetDetect_class = c;
	
	return 0;
}

void aubioOnsetDetect_float(t_aubioOnsetDetect *x, double f)
{
			if (f < 10 || f > 0.1){
			x->threshold = f;
			x->onsetDetector->threshold = f;
			}
	//post("Threshold is %f", x->threshold);
}

void aubioOnsetDetect_energy(t_aubioOnsetDetect *x){
		x->onsetDetector->onsetclass_energy();
		post("Energy based onset detection now used by aubioOnsetDetect~.");
}

void aubioOnsetDetect_hfc(t_aubioOnsetDetect *x){
/** High Frequency Content onset detection function
 
  This method computes the High Frequency Content (HFC) of the input spectral
  frame. The resulting function is efficient at detecting percussive onsets.

  Paul Masri. Computer modeling of Sound for Transformation and Synthesis of
  Musical Signal. PhD dissertation, University of Bristol, UK, 1996.*/
		x->onsetDetector->onsetclass_hfc();
		post("High Frequency Content (Masri '96) detection now used by aubioOnsetDetect~.");
}


void aubioOnsetDetect_complex(t_aubioOnsetDetect *x){
		//Complex Domain Method onset detection function 
		//Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain
		//onset detection for musical signals. In Proceedings of the Digital Audio
		//Effects Conference, DAFx-03, pages 90-93, London, UK, 2003.
		x->onsetDetector->onsetclass_complex();
		post("Complex domain onset detection (Duxbury et al., DaFx '03) now used by aubioOnsetDetect~.");

}

void aubioOnsetDetect_phase(t_aubioOnsetDetect *x){
/** Phase Based Method onset detection function 

  Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note onset
  detection for music signals. In Proceedings of the IEEE International
  Conference on Acoustics Speech and Signal Processing, pages 441­444,
  Hong-Kong, 2003.*/
		x->onsetDetector->onsetclass_phase();
		object_post((t_object *) x, "Phase-based detection (Bello et al., IEEE '03) now used by aubioOnsetDetect~.");
}

void aubioOnsetDetect_specdiff(t_aubioOnsetDetect *x){
		/* Spectral difference method onset detection function 
		Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to
		rhythm analysis. In IEEE International Conference on Multimedia and Expo
		(ICME 2001), pages 881­884, Tokyo, Japan, August 2001.
		*/
		//aubio_onsetdetection_type
		//aubio_onsetdetection_free (x->o);
		x->onsetDetector->onsetclass_specdiff();
		post("Spectral Difference (Foote and Shingo Uchihashi, ICME '01) detection now used by aubioOnsetDetect~.");


}

void aubioOnsetDetect_kl(t_aubioOnsetDetect *x){
		//aubio_onsetdetection_type
		//aubio_onsetdetection_free (x->o);
		/** Kullback-Liebler onset detection function 
  
			Stephen Hainsworth and Malcom Macleod. Onset detection in music audio
			signals. In Proceedings of the International Computer Music Conference
			(ICMC), Singapore, 2003.
		*/

		x->onsetDetector->onsetclass_kl();
		post("Kullback-Liebler (Hainsworth and McLeod, ICMC '03) detection now used by aubioOnsetDetect~.");
}

void aubioOnsetDetect_mkl(t_aubioOnsetDetect *x){
		/** Modified Kullback-Liebler onset detection function 

		Paul Brossier, ``Automatic annotation of musical audio for interactive
		systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for Digital
		music, Queen Mary University of London, London, UK, 2003.*/		
		x->onsetDetector->onsetclass_mkl();
		post("Modified Kullback-Liebler (Brossier, PhD thesis '03) detection now used by aubioOnsetDetect~.");
}



// this function is called when the DAC is enabled, and "registers" a function
// for the signal chain. in this case, "aubioOnsetDetect_perform"
void aubioOnsetDetect_dsp(t_aubioOnsetDetect *x, t_signal **sp, short *count)
{
	// dsp_add
	// 1: (t_perfroutine p) perform method
	// 2: (long argc) number of args to your perform method
	// 3...: argc additional arguments, all must be sizeof(pointer) or long
	// these can be whatever, so you might want to include your object pointer in there
	// so that you have access to the info, if you need it.
	dsp_add(aubioOnsetDetect_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
}

t_int *aubioOnsetDetect_perform(t_int *w)
{
	// DO NOT CALL post IN HERE, but you can call defer_low (not defer)
	
	// args are in a vector, sized as specified in aubioOnsetDetect_dsp method
	// w[0] contains &aubioOnsetDetect_perform, so we start at w[1]
	t_aubioOnsetDetect *x = (t_aubioOnsetDetect *)(w[1]);
	t_float *inL = (t_float *)(w[2]);
	t_float *outL = (t_float *)(w[3]);
	int n = (int)w[4];
	
	float frame[n];
	int j;
	for (j=0;j<n;j++) {
	frame[j] = (float) inL[j];//must cast to float or is type t_float
	}
	// aubio onset detector then processes current frame - returns bool true when new detection is output
	if (x->onsetDetector->processframe(frame, n)){
	//if buffer full and new result is processed (buffer is 1024 with hopsize 512 - can be set to other values)
		outlet_float(x->medianDetectionFunctionOutlet, x->onsetDetector->medianDetectionValue);
		outlet_float(x->rawDetectionFunctionOutlet, x->onsetDetector->rawDetectionValue);
	//	outlet_float(x->detectionFunctionOutlet, x->onsetDetector->peakPickedDetectionValue);
		outlet_float(x->detectionFunctionOutlet, x->onsetDetector->bestSlopeValue);
		
		
		if (x->onsetDetector->anrMedianProcessedOnsetFound)
				outlet_bang(x->medianBangOutlet);
		
		if (x->onsetDetector->aubioOnsetFound)
			outlet_bang(x->bangoutlet);
			
		
	}//end if new aubio onset detection result
	
	outL[j] = inL[j];//have added this so signal is "see through": outputting the input signal
	
	// you have to return the NEXT pointer in the array OR MAX WILL CRASH
	return w + 5;
}

void aubioOnsetDetect_assist(t_aubioOnsetDetect *x, void *b, long m, long a, char *s)
{
	if (m == ASSIST_INLET) { //inlet
		sprintf(s, "Inlet %ld", a);
		switch (a){
		case 0:
		sprintf(s, "Input signal and float (between 0.1 and 10) for aubio detection threshold.");
		break;
		case 1:
		sprintf(s, "no inlet 1");
		break;
		}
	} 
	else {	// outlet
				
		switch (a){
			case 0:
				sprintf(s, "Outlet %ld is the original signal.", a); 	
				break;
			case 1:
				sprintf(s, "Bang out when onset is detected.");
				break;
			case 2:
				sprintf(s, "Peak Picked detection function.");
				break;
			case 3:
				sprintf(s, "Raw aubio detection function result.");
				break;
			}
	}
}

// NOT CALLED!, we use dsp_free for a generic free function
void aubioOnsetDetect_free(t_aubioOnsetDetect *x) 
{
	;
}

void *aubioOnsetDetect_new(t_symbol *s, long argc, t_atom *argv)
{
	t_aubioOnsetDetect *x = NULL;

	
	// NEW VERSION
	if (x = (t_aubioOnsetDetect *)object_alloc((t_class *) aubioOnsetDetect_class)) {
		dsp_setup((t_pxobject *)x, 1);	// MSP inlets: arg is # of inlets and is REQUIRED! 
										// use 0 if you don't need inlets

		x->medianDetectionFunctionOutlet = floatout(x);
		x->medianBangOutlet  = bangout(x);
		x->rawDetectionFunctionOutlet = floatout(x);		
		x->detectionFunctionOutlet = floatout(x);
		x->bangoutlet  = bangout(x);

		outlet_new(x, "signal"); // signal outlet (note "signal" rather than NULL)

		x->threshold = 1;
		x->threshold2 = -70.;
		x->bufsize   = 1024;//using fixed buffer size here.
		x->hopsize   = x->bufsize / 2;
		
		//set this up in AubioOnsetDetector class instead
		x->onsetDetector = new AubioOnsetDetector();
		x->onsetDetector->buffersize = x->bufsize;
		x->onsetDetector->hopsize = x->hopsize;
		x->onsetDetector->threshold = x->threshold;
		x->onsetDetector->threshold2 = x->threshold2;
		x->onsetDetector->initialise();
		//
						
		if (argc == 1){//i.e. there is an argument on creation like [aubioOnsetDetect~ 0.3]
		t_atom my_atom = argv[0];
		
			object_post((t_object*)x, (char*) "Aubio Onset Detect found, created by Andrew Robertson from work by Paul Brossier, Queen Mary University");
		object_post((t_object*)x, (char*) "Threshold set to %f ", atom_getfloat(&my_atom));
		x->threshold = atom_getfloat(&my_atom);
		
			if (x->threshold > 10)
			x->threshold = 10;
			
			if (x->threshold < 0.1)
			x->threshold = 0.1;
			
			x->onsetDetector->threshold = x->threshold;
		}
		
		x->useMedianOnsetDetection = true;
	}
	return (x);
}