comparison modules-and-plug-ins/max-external/btrack~.cpp @ 83:3b69082715ea

Merge branch 'release/1.0.2'
author Adam Stark <adamstark.uk@gmail.com>
date Tue, 25 Nov 2014 23:00:13 +0000
parents d812bf72d928
children
comparison
equal deleted inserted replaced
77:73855a26a0e0 83:3b69082715ea
1 //===========================================================================
2 /** @file btrack~.cpp
3 * @brief The btrack~ Max external
4 * @author Adam Stark
5 * @copyright Copyright (C) 2008-2014 Queen Mary University of London
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 //===========================================================================
21
22 //===========================================================================
23 #include "ext.h" // standard Max include, always required (except in Jitter)
24 #include "ext_obex.h" // required for "new" style objects
25 #include "z_dsp.h" // required for MSP objects
26
27 //===========================================================================
28 // BTrack includes
29 #include "../../src/BTrack.h"
30 #include "../../src/OnsetDetectionFunction.h"
31
32 //===========================================================================
33 // struct to represent the object's state
34 typedef struct _btrack {
35
36 // The object itself (t_pxobject in MSP instead of t_object)
37 t_pxobject ob;
38
39 // An instance of the BTrack beat tracker
40 BTrack *b;
41
42 // Indicates whether the beat tracker should output beats
43 bool should_output_beats;
44
45 // the time of the last bang received in milliseconds
46 long time_of_last_bang_ms;
47
48 // a count in counter
49 long count_in;
50
51 // the recent tempi observed during count ins
52 double count_in_tempi[3];
53
54 // An outlet for beats
55 void *beat_outlet;
56
57 // An outlet for tempo estimates
58 void *tempo_outlet;
59
60 } t_btrack;
61
62
63 //===========================================================================
64 // method prototypes
65 void *btrack_new(t_symbol *s, long argc, t_atom *argv);
66 void btrack_free(t_btrack *x);
67 void btrack_assist(t_btrack *x, void *b, long m, long a, char *s);
68 void btrack_float(t_btrack *x, double f);
69 void btrack_dsp(t_btrack *x, t_signal **sp, short *count);
70 void btrack_dsp64(t_btrack *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags);
71 t_int *btrack_perform(t_int *w);
72 void btrack_perform64(t_btrack *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam);
73
74 //===========================================================================
75 void btrack_process(t_btrack *x,double* audioFrame);
76
77 void btrack_on(t_btrack *x);
78 void btrack_off(t_btrack *x);
79
80 void btrack_fixtempo(t_btrack *x, double f);
81 void btrack_unfixtempo(t_btrack *x);
82
83 void btrack_bang(t_btrack *x);
84 void btrack_countin(t_btrack *x);
85
86 void outlet_beat(t_btrack *x, t_symbol *s, long argc, t_atom *argv);
87
88 // global class pointer variable
89 static t_class *btrack_class = NULL;
90
91
92
93
94 //===========================================================================
95 int C74_EXPORT main(void)
96 {
97 //--------------------------------------------------------------
98 t_class *c = class_new("btrack~", (method)btrack_new, (method)btrack_free, (long)sizeof(t_btrack), 0L, A_GIMME, 0);
99
100 //--------------------------------------------------------------
101 class_addmethod(c, (method)btrack_float, "float", A_FLOAT, 0);
102 class_addmethod(c, (method)btrack_dsp, "dsp", A_CANT, 0); // Old 32-bit MSP dsp chain compilation for Max 5 and earlier
103 class_addmethod(c, (method)btrack_dsp64, "dsp64", A_CANT, 0); // New 64-bit MSP dsp chain compilation for Max 6
104 class_addmethod(c, (method)btrack_assist, "assist", A_CANT, 0);
105
106 //--------------------------------------------------------------
107 class_addmethod(c, (method)btrack_on, "on", 0);
108 class_addmethod(c, (method)btrack_off, "off", 0);
109
110 //--------------------------------------------------------------
111 class_addmethod(c, (method)btrack_fixtempo, "fixtempo", A_FLOAT, 0);
112 class_addmethod(c, (method)btrack_unfixtempo, "unfixtempo", 0);
113
114 //--------------------------------------------------------------
115 class_addmethod(c, (method)btrack_bang, "bang", 0);
116 class_addmethod(c, (method)btrack_countin, "countin", 0);
117
118 //--------------------------------------------------------------
119 class_dspinit(c);
120 class_register(CLASS_BOX, c);
121 btrack_class = c;
122
123 return 0;
124 }
125
126 //===========================================================================
127 void *btrack_new(t_symbol *s, long argc, t_atom *argv)
128 {
129 t_btrack *x = (t_btrack *)object_alloc(btrack_class);
130
131 if (x) {
132 dsp_setup((t_pxobject *)x, 1); // MSP inlets: arg is # of inlets and is REQUIRED!
133 // use 0 if you don't need inlets
134
135 // create detection function and beat tracking objects
136 x->b = new BTrack();
137
138 // create outlets for bpm and beats
139 x->tempo_outlet = floatout(x);
140 x->beat_outlet = bangout(x);
141
142 // initialise variables
143 x->should_output_beats = true;
144 x->time_of_last_bang_ms = 0;
145 x->count_in = 4;
146 x->count_in_tempi[0] = 120;
147 x->count_in_tempi[1] = 120;
148 x->count_in_tempi[2] = 120;
149
150 }
151 return (x);
152 }
153
154
155 //===========================================================================
156 void btrack_free(t_btrack *x)
157 {
158 // delete the beat tracker
159 delete x->b;
160 x->b = NULL;
161
162 // call the dsp free function on our object
163 dsp_free((t_pxobject *)x);
164 }
165
166
167 //===========================================================================
168 void btrack_assist(t_btrack *x, void *b, long m, long a, char *s)
169 {
170 if (m == ASSIST_INLET) { //inlet
171 if (a == 0)
172 {
173 sprintf(s, "(signal) Audio In");
174 }
175 }
176 else { // outlet
177 if (a == 0)
178 {
179 sprintf(s, "Beats Out");
180 }
181 if (a == 1)
182 {
183 sprintf(s, "Tempo (bpm)");
184 }
185
186 }
187 }
188
189
190 //===========================================================================
191 void btrack_float(t_btrack *x, double f)
192 {
193
194
195 }
196
197 //===========================================================================
198 // this function is called when the DAC is enabled, and "registers" a function for the signal chain in Max 5 and earlier.
199 // In this case we register the 32-bit, "btrack_perform" method.
200 void btrack_dsp(t_btrack *x, t_signal **sp, short *count)
201 {
202 // get hop size and frame size
203 int hopSize = (int) sp[0]->s_n;
204 int frameSize = hopSize*2;
205
206 // initialise the beat tracker
207 x->b->updateHopAndFrameSize(hopSize, frameSize);
208
209 // set up dsp
210 dsp_add(btrack_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
211 }
212
213
214 //===========================================================================
215 // this is the Max 6 version of the dsp method -- it registers a function for the signal chain in Max 6,
216 // which operates on 64-bit audio signals.
217 void btrack_dsp64(t_btrack *x, t_object *dsp64, short *count, double samplerate, long maxvectorsize, long flags)
218 {
219 // get hop size and frame size
220 int hopSize = (int) maxvectorsize;
221 int frameSize = hopSize*2;
222
223 // initialise the beat tracker
224 x->b->updateHopAndFrameSize(hopSize, frameSize);
225
226 // set up dsp
227 object_method(dsp64, gensym("dsp_add64"), x, btrack_perform64, 0, NULL);
228 }
229
230
231 //===========================================================================
232 // this is the 32-bit perform method for Max 5 and earlier
233 t_int *btrack_perform(t_int *w)
234 {
235 t_btrack *x = (t_btrack *)(w[1]);
236 t_float *inL = (t_float *)(w[2]);
237 int n = (int)w[3];
238
239 double audioFrame[n];
240
241 for (int i = 0;i < n;i++)
242 {
243 audioFrame[i] = (double) inL[i];
244 }
245
246 btrack_process(x,audioFrame);
247
248 // you have to return the NEXT pointer in the array OR MAX WILL CRASH
249 return w + 4;
250 }
251
252 //===========================================================================
253 // this is 64-bit perform method for Max 6
254 void btrack_perform64(t_btrack *x, t_object *dsp64, double **ins, long numins, double **outs, long numouts, long sampleframes, long flags, void *userparam)
255 {
256 t_double *inL = ins[0]; // we get audio for each inlet of the object from the **ins argument
257 int n = sampleframes;
258
259 double audioFrame[n];
260
261 for (int i = 0;i < n;i++)
262 {
263 audioFrame[i] = (double) inL[i];
264 }
265
266 btrack_process(x,audioFrame);
267 }
268
269 //===========================================================================
270 void btrack_process(t_btrack *x,double* audioFrame)
271 {
272 // process the audio frame
273 x->b->processAudioFrame(audioFrame);
274
275
276 // if there is a beat in this frame
277 if (x->b->beatDueInCurrentFrame())
278 {
279 // outlet a beat
280 defer_low((t_object *)x, (method)outlet_beat, NULL, 0, NULL);
281 }
282 }
283
284 //===========================================================================
285 void outlet_beat(t_btrack *x, t_symbol *s, long argc, t_atom *argv)
286 {
287 if (x->should_output_beats)
288 {
289 // send a bang out of the beat outlet
290 outlet_bang(x->beat_outlet);
291
292 // send the tempo out of the tempo outlet
293 outlet_float(x->tempo_outlet, (float) x->b->getCurrentTempoEstimate());
294 }
295 }
296
297
298 //===========================================================================
299 void btrack_on(t_btrack *x)
300 {
301 x->should_output_beats = true;
302 }
303
304 //===========================================================================
305 void btrack_off(t_btrack *x)
306 {
307 x->should_output_beats = false;
308 x->count_in = 4;
309 }
310
311 //===========================================================================
312 void btrack_fixtempo(t_btrack *x, double f)
313 {
314 x->b->fixTempo(f);
315 object_post((t_object *) x,"Tempo fixed to %f BPM",f);
316 }
317
318 //===========================================================================
319 void btrack_unfixtempo(t_btrack *x)
320 {
321 x->b->doNotFixTempo();
322 object_post((t_object *) x,"Tempo no longer fixed");
323 }
324
325 //===========================================================================
326 void btrack_countin(t_btrack *x)
327 {
328 x->count_in = x->count_in-1;
329
330 btrack_bang(x);
331 if (x->count_in == 0)
332 {
333 x->should_output_beats = 1;
334 }
335 }
336
337 //===========================================================================
338 void btrack_bang(t_btrack *x)
339 {
340 double bperiod;
341 double tempo;
342 double mean_tempo;
343
344 // get current time in milliseconds
345 long ms = systime_ms();
346
347 // calculate beat period
348 bperiod = ((double) (ms - x->time_of_last_bang_ms))/1000.0;
349
350 // store time since last bang
351 x->time_of_last_bang_ms = ms;
352
353 // if beat period is between 0 and 1
354 if ((bperiod < 1.0) && (bperiod > 0.0))
355 {
356 // calculate tempo from beat period
357 tempo = (1/bperiod)*60;
358
359 double sum = 0;
360
361 // move back elements in tempo history and sum remaining elements
362 for (int i = 0;i < 2;i++)
363 {
364 x->count_in_tempi[i] = x->count_in_tempi[i+1];
365 sum = sum+x->count_in_tempi[i];
366 }
367
368 // set final element to be the newly calculated tempo
369 x->count_in_tempi[2] = tempo;
370
371 // add the new tempo to the sum
372 sum = sum+x->count_in_tempi[2];
373
374 // calculate the mean tempo by dividing the tempo by 3
375 mean_tempo = sum/3;
376
377 // set the tempo in the beat tracker
378 x->b->setTempo(mean_tempo);
379 }
380 }
381
382
383