diff modules-and-plug-ins/max-external/btrack~.cpp @ 80:d812bf72d928

Tidied up and added maxhelp and beat tracking example patches
author Adam Stark <adamstark.uk@gmail.com>
date Tue, 25 Nov 2014 22:47:09 +0000
parents 9fd4075b8f9e
children
line wrap: on
line diff
--- a/modules-and-plug-ins/max-external/btrack~.cpp	Mon Nov 24 17:17:26 2014 +0000
+++ b/modules-and-plug-ins/max-external/btrack~.cpp	Tue Nov 25 22:47:09 2014 +0000
@@ -42,6 +42,15 @@
     // Indicates whether the beat tracker should output beats
     bool            should_output_beats;
     
+    // the time of the last bang received in milliseconds
+    long            time_of_last_bang_ms;
+    
+    // a count in counter
+    long            count_in;
+    
+    // the recent tempi observed during count ins
+    double           count_in_tempi[3];
+    
     // An outlet for beats
     void            *beat_outlet;
     
@@ -68,6 +77,12 @@
 void btrack_on(t_btrack *x);
 void btrack_off(t_btrack *x);
 
+void btrack_fixtempo(t_btrack *x, double f);
+void btrack_unfixtempo(t_btrack *x);
+
+void btrack_bang(t_btrack *x);
+void btrack_countin(t_btrack *x);
+
 void outlet_beat(t_btrack *x, t_symbol *s, long argc, t_atom *argv);
 
 // global class pointer variable
@@ -79,20 +94,28 @@
 //===========================================================================
 int C74_EXPORT 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.
-
-	t_class *c = class_new("btrack~", (method)btrack_new, (method)dsp_free, (long)sizeof(t_btrack), 0L, A_GIMME, 0);
+    //--------------------------------------------------------------
+	t_class *c = class_new("btrack~", (method)btrack_new, (method)btrack_free, (long)sizeof(t_btrack), 0L, A_GIMME, 0);
 	
+    //--------------------------------------------------------------
 	class_addmethod(c, (method)btrack_float,		"float",	A_FLOAT, 0);
 	class_addmethod(c, (method)btrack_dsp,		"dsp",		A_CANT, 0);		// Old 32-bit MSP dsp chain compilation for Max 5 and earlier
 	class_addmethod(c, (method)btrack_dsp64,		"dsp64",	A_CANT, 0);		// New 64-bit MSP dsp chain compilation for Max 6
 	class_addmethod(c, (method)btrack_assist,	"assist",	A_CANT, 0);
-	
+    
+    //--------------------------------------------------------------
     class_addmethod(c, (method)btrack_on,	"on", 0);
     class_addmethod(c, (method)btrack_off,	"off", 0);
+
+    //--------------------------------------------------------------
+    class_addmethod(c, (method)btrack_fixtempo,		"fixtempo",	A_FLOAT, 0);
+    class_addmethod(c, (method)btrack_unfixtempo,	"unfixtempo", 0);
     
+    //--------------------------------------------------------------
+    class_addmethod(c, (method)btrack_bang,		"bang", 0);
+    class_addmethod(c, (method)btrack_countin,	"countin", 0);
+    
+    //--------------------------------------------------------------
 	class_dspinit(c);
 	class_register(CLASS_BOX, c);
 	btrack_class = c;
@@ -100,10 +123,6 @@
 	return 0;
 }
 
-
-
-
-
 //===========================================================================
 void *btrack_new(t_symbol *s, long argc, t_atom *argv)
 {
@@ -113,39 +132,35 @@
 		dsp_setup((t_pxobject *)x, 1);	// MSP inlets: arg is # of inlets and is REQUIRED! 
 										// use 0 if you don't need inlets
 
-        object_post((t_object *) x,"v1.0     designed by Adam Stark and Matthew Davies at Queen Mary University of London");
-        
         // create detection function and beat tracking objects
         x->b = new BTrack();
         
+        // create outlets for bpm and beats
         x->tempo_outlet = floatout(x);
         x->beat_outlet = bangout(x);
         
-        
+        // initialise variables
         x->should_output_beats = true;
-        
-        /*
-    
-        x->mode = 0;
-        x->lastbang = 0;
-        
-        
-        x->countin = 4;
-        
-        x->counttempi[0] = 120;
-        x->counttempi[1] = 120;
-        x->counttempi[2] = 120;
-         */
+        x->time_of_last_bang_ms = 0;
+        x->count_in = 4;
+        x->count_in_tempi[0] = 120;
+        x->count_in_tempi[1] = 120;
+        x->count_in_tempi[2] = 120;
+
 	}
 	return (x);
 }
 
 
 //===========================================================================
-// NOT CALLED!, we use dsp_free for a generic free function
 void btrack_free(t_btrack *x) 
 {
-	;
+    // delete the beat tracker
+    delete x->b;
+    x->b = NULL;
+    
+    // call the dsp free function on our object
+    dsp_free((t_pxobject *)x);
 }
 
 
@@ -184,11 +199,14 @@
 // In this case we register the 32-bit, "btrack_perform" method.
 void btrack_dsp(t_btrack *x, t_signal **sp, short *count)
 {
+    // get hop size and frame size
     int hopSize = (int) sp[0]->s_n;
     int frameSize = hopSize*2;
     
+    // initialise the beat tracker
     x->b->updateHopAndFrameSize(hopSize, frameSize);
     
+    // set up dsp
 	dsp_add(btrack_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
 }
 
@@ -198,11 +216,14 @@
 // which operates on 64-bit audio signals.
 void btrack_dsp64(t_btrack *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags)
 {
+     // get hop size and frame size
     int hopSize = (int) maxvectorsize;
     int frameSize = hopSize*2;
     
+    // initialise the beat tracker
     x->b->updateHopAndFrameSize(hopSize, frameSize);
 		
+    // set up dsp
 	object_method(dsp64, gensym("dsp_add64"), x, btrack_perform64, 0, NULL);
 }
 
@@ -284,11 +305,79 @@
 void btrack_off(t_btrack *x)
 {
     x->should_output_beats = false;
+    x->count_in = 4;
 }
 
+//===========================================================================
+void btrack_fixtempo(t_btrack *x, double f)
+{
+    x->b->fixTempo(f);
+    object_post((t_object *) x,"Tempo fixed to %f BPM",f);
+}
 
+//===========================================================================
+void btrack_unfixtempo(t_btrack *x)
+{
+    x->b->doNotFixTempo();
+    object_post((t_object *) x,"Tempo no longer fixed");
+}
 
+//===========================================================================
+void btrack_countin(t_btrack *x)
+{
+    x->count_in = x->count_in-1;
+    
+    btrack_bang(x);
+    if (x->count_in == 0)
+    {
+        x->should_output_beats = 1;
+    }
+}
 
+//===========================================================================
+void btrack_bang(t_btrack *x)
+{
+    double bperiod;
+    double tempo;
+    double mean_tempo;
+    
+    // get current time in milliseconds
+    long ms = systime_ms();
+    
+    // calculate beat period
+    bperiod = ((double) (ms - x->time_of_last_bang_ms))/1000.0;
+    
+    // store time since last bang
+    x->time_of_last_bang_ms = ms;
+    
+    // if beat period is between 0 and 1
+    if ((bperiod < 1.0) && (bperiod > 0.0))
+    {
+        // calculate tempo from beat period
+        tempo = (1/bperiod)*60;
+        
+        double sum = 0;
+        
+        // move back elements in tempo history and sum remaining elements
+        for (int i = 0;i < 2;i++)
+        {
+            x->count_in_tempi[i] = x->count_in_tempi[i+1];
+            sum = sum+x->count_in_tempi[i];
+        }
+        
+        // set final element to be the newly calculated tempo
+        x->count_in_tempi[2] = tempo;
+        
+        // add the new tempo to the sum
+        sum = sum+x->count_in_tempi[2];
+        
+        // calculate the mean tempo by dividing the tempo by 3
+        mean_tempo = sum/3;
+        
+        // set the tempo in the beat tracker
+        x->b->setTempo(mean_tempo);
+    }
+}