aboutsummaryrefslogtreecommitdiff
path: root/pd/extra/bonk~/bonk~.c
diff options
context:
space:
mode:
Diffstat (limited to 'pd/extra/bonk~/bonk~.c')
-rw-r--r--pd/extra/bonk~/bonk~.c1475
1 files changed, 919 insertions, 556 deletions
diff --git a/pd/extra/bonk~/bonk~.c b/pd/extra/bonk~/bonk~.c
index 3c5fc176..48e6837e 100644
--- a/pd/extra/bonk~/bonk~.c
+++ b/pd/extra/bonk~/bonk~.c
@@ -1,26 +1,69 @@
-/* Copyright 1997-1999 Miller Puckette (msp@ucsd.edu) and Ted Apel
-(tapel@ucsd.edu). Permission is granted to use this software for any
-noncommercial purpose. For commercial licensing please contact the UCSD
-Technology Transfer Office.
-
-THE AUTHORS AND THEIR EMPLOYERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
-IN CONNECTION WITH THIS SOFTWARE!
+/*
+ ###########################################################################
+ # bonk~ - a Max/MSP external
+ # by miller puckette and ted appel
+ # http://crca.ucsd.edu/~msp/
+ # Max/MSP port by barry threw
+ # http://www.barrythrew.com
+ # me@barrythrew.com
+ # San Francisco, CA
+ # (c) 2008
+ # for Kesumo - http://www.kesumo.com
+ ###########################################################################
+ // bonk~ detects attacks in an audio signal
+ ###########################################################################
+ This software is copyrighted by Miller Puckette and others. The following
+ terms (the "Standard Improved BSD License") apply to all files associated with
+ the software unless explicitly disclaimed in individual files:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ 3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+dolist:
+decay and other times in msec
*/
#include <math.h>
#include <stdio.h>
+#include <string.h>
#ifdef NT
-#pragma warning (disable: 4305 4244 4996)
+#pragma warning (disable: 4305 4244)
#endif
-
+
#ifdef MSP
-
#include "ext.h"
#include "z_dsp.h"
#include "math.h"
#include "ext_support.h"
#include "ext_proto.h"
+#include "ext_obex.h"
typedef double t_floatarg; /* from m_pd.h */
#define flog log
@@ -28,18 +71,6 @@ typedef double t_floatarg; /* from m_pd.h */
#define fsqrt sqrt
#define t_resizebytes(a, b, c) t_resizebytes((char *)(a), (b), (c))
-#define flog log
-#define fexp exp
-#define fsqrt sqrt
-
-#define FILE_DIALOG 1 /* use dialogs to get file name */
-#define FILE_NAMED 2 /* symbol specifies file name */
-
-#define DUMTAB1SIZE 256
-#define DUMTAB2SIZE 1024
-
-static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
-
void *bonk_class;
#define getbytes t_getbytes
#define freebytes t_freebytes
@@ -50,28 +81,52 @@ void *bonk_class;
static t_class *bonk_class;
#endif
+#ifndef _MSC_VER
+#include <alloca.h>
+#endif
+
/* ------------------------ bonk~ ----------------------------- */
-#define NPOINTS 256
+#define DEFNPOINTS 256
#define MAXCHANNELS 8
+#define MINPOINTS 64
#define DEFPERIOD 128
-#define DEFHITHRESH 60
-#define DEFLOTHRESH 50
+#define DEFNFILTERS 11
+#define DEFHALFTONES 6
+#define DEFOVERLAP 1
+#define DEFFIRSTBIN 1
+#define DEFHITHRESH 5
+#define DEFLOTHRESH 2.5
#define DEFMASKTIME 4
#define DEFMASKDECAY 0.7
#define DEFDEBOUNCEDECAY 0
#define DEFMINVEL 7
-
-
+#define DEFATTACKBINS 1
+#define MAXATTACKWAIT 4
typedef struct _filterkernel
{
- int k_npoints;
- float k_freq;
- float k_normalize;
+ int k_filterpoints;
+ int k_hoppoints;
+ int k_skippoints;
+ int k_nhops;
+ float k_centerfreq; /* center frequency, bins */
+ float k_bandwidth; /* bandwidth, bins */
float *k_stuff;
} t_filterkernel;
+typedef struct _filterbank
+{
+ int b_nfilters; /* number of filters in bank */
+ int b_npoints; /* input vector size */
+ float b_halftones; /* filter bandwidth in halftones */
+ float b_overlap; /* overlap; default 1 for 1/2-power pts */
+ float b_firstbin; /* freq of first filter in bins, default 1 */
+ t_filterkernel *b_vec; /* filter kernels */
+ int b_refcount; /* number of bonk~ objects using this */
+ struct _filterbank *b_next; /* next in linked list */
+} t_filterbank;
+
#if 0 /* this is the design for 1.0: */
static t_filterkernel bonk_filterkernels[] =
{{256, 2, .01562}, {256, 4, .01562}, {256, 6, .01562}, {180, 6, .02222},
@@ -79,6 +134,7 @@ static t_filterkernel bonk_filterkernels[] =
{32, 6, .03227}, {22, 6, .03932}, {16, 6, .04489}};
#endif
+#if 0
/* here's the 1.1 rev: */
static t_filterkernel bonk_filterkernels[] =
{{256, 1, .01562, 0}, {256, 3, .01562, 0}, {256, 5, .01562, 0},
@@ -86,27 +142,40 @@ static t_filterkernel bonk_filterkernels[] =
{76, 6, .0236, 0}, {54, 6, .02634, 0}, {38, 6, .03047, 0},
{26, 6, .03667, 0}, {18, 6, .04458, 0}};
-#define NFILTERS ((int)(sizeof(bonk_filterkernels)/ \
- sizeof(bonk_filterkernels[0])))
+#define NFILTERS \
+ ((int)(sizeof(bonk_filterkernels) / sizeof(bonk_filterkernels[0])))
+
+#endif
+
+#if 0
+ /* and 1.2 */
+#define NFILTERS 11
+static t_filterkernel bonk_filterkernels[NFILTERS];
+#endif
+
+ /* and 1.3 */
+#define MAXNFILTERS 50
+#define MASKHIST 8
-static float bonk_hanningwindow[NPOINTS];
+static t_filterbank *bonk_filterbanklist;
typedef struct _hist
{
float h_power;
- float h_mask;
float h_before;
+ float h_outpower;
int h_countup;
+ float h_mask[MASKHIST];
} t_hist;
typedef struct template
{
- float t_amp[NFILTERS];
+ float t_amp[MAXNFILTERS];
} t_template;
typedef struct _insig
{
- t_hist g_hist[NFILTERS]; /* history for each filter */
+ t_hist g_hist[MAXNFILTERS]; /* history for each filter */
#ifdef PD
t_outlet *g_outlet; /* outlet for raw data */
#endif
@@ -126,85 +195,230 @@ typedef struct _bonk
#endif /* PD */
#ifdef MSP
t_pxobject x_obj;
+ void *obex;
void *x_cookedout;
void *x_clock;
- short x_vol;
#endif /* MSP */
+ /* parameters */
+ int x_npoints; /* number of points in input buffer */
+ int x_period; /* number of input samples between analyses */
+ int x_nfilters; /* number of filters requested */
+ float x_halftones; /* nominal halftones between filters */
+ float x_overlap;
+ float x_firstbin;
+
+ float x_hithresh; /* threshold for total growth to trigger */
+ float x_lothresh; /* threshold for total growth to re-arm */
+ float x_minvel; /* minimum velocity we output */
+ float x_maskdecay;
+ int x_masktime;
+ int x_useloudness; /* use loudness spectra instead of power */
+ float x_debouncedecay;
+ float x_debouncevel;
+ double x_learndebounce; /* debounce time (in "learn" mode only) */
+ int x_attackbins; /* number of bins to wait for attack */
- t_hist x_hist[NFILTERS];
+ t_filterbank *x_filterbank;
+ t_hist x_hist[MAXNFILTERS];
t_template *x_template;
t_insig *x_insig;
int x_ninsig;
int x_ntemplate;
int x_infill;
int x_countdown;
- int x_period;
int x_willattack;
+ int x_attacked;
int x_debug;
- float x_hithresh;
- float x_lothresh;
- int x_masktime;
- float x_maskdecay;
int x_learn;
- double x_learndebounce; /* debounce time for "learn" mode */
int x_learncount; /* countup for "learn" mode */
- float x_debouncedecay;
- float x_minvel; /* minimum velocity we output */
- float x_debouncevel;
+ int x_spew; /* if true, always generate output! */
+ int x_maskphase; /* phase, 0 to MASKHIST-1, for mask history */
+ float x_sr; /* current sample rate in Hz. */
+ int x_hit; /* next "tick" called because of a hit, not a poll */
} t_bonk;
#ifdef MSP
-static void *bonk_new(int period, int bonk2);
-void bonk_tick(t_bonk *x);
-void bonk_doit(t_bonk *x);
+static void *bonk_new(t_symbol *s, long ac, t_atom *av);
+static void bonk_tick(t_bonk *x);
+static void bonk_doit(t_bonk *x);
static t_int *bonk_perform(t_int *w);
-void bonk_dsp(t_bonk *x, t_signal **sp);
+static void bonk_dsp(t_bonk *x, t_signal **sp);
void bonk_assist(t_bonk *x, void *b, long m, long a, char *s);
-void bonk_thresh(t_bonk *x, t_floatarg f1, t_floatarg f2);
-void bonk_mask(t_bonk *x, t_floatarg f1, t_floatarg f2);
-void bonk_debounce(t_bonk *x, t_floatarg f1);
-static void bonk_print(t_bonk *x, t_floatarg f);
-static void bonk_learn(t_bonk *x, t_floatarg f);
-void bonk_bang(t_bonk *x);
-void bonk_setupkernels(void);
-void bonk_free(t_bonk *x);
+static void bonk_free(t_bonk *x);
void bonk_setup(void);
-void main();
-float qrsqrt(float f);
+int main();
+
+static void bonk_thresh(t_bonk *x, t_floatarg f1, t_floatarg f2);
+static void bonk_print(t_bonk *x, t_floatarg f);
+static void bonk_bang(t_bonk *x);
+
static void bonk_write(t_bonk *x, t_symbol *s);
static void bonk_read(t_bonk *x, t_symbol *s);
+void bonk_minvel_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_lothresh_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_hithresh_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_masktime_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_maskdecay_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_debouncedecay_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_debug_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_spew_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_useloudness_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_attackbins_set(t_bonk *x, void *attr, long ac, t_atom *av);
+void bonk_learn_set(t_bonk *x, void *attr, long ac, t_atom *av);
+
+float qrsqrt(float f);
double clock_getsystime();
double clock_gettimesince(double prevsystime);
-static char *strcpy(char *s1, const char *s2);
-static int ilog2(int n);
+char *strcpy(char *s1, const char *s2);
#endif
static void bonk_tick(t_bonk *x);
-static void bonk_donew(t_bonk *x, int period, int nsig)
+#define HALFWIDTH 0.75 /* half peak bandwidth at half power point in bins */
+
+static t_filterbank *bonk_newfilterbank(int npoints, int nfilters,
+ float halftones, float overlap, float firstbin)
+{
+ int i, j;
+ float cf, bw, h, relspace;
+ t_filterbank *b = (t_filterbank *)getbytes(sizeof(*b));
+ b->b_npoints = npoints;
+ b->b_nfilters = nfilters;
+ b->b_halftones = halftones;
+ b->b_overlap = overlap;
+ b->b_firstbin = firstbin;
+ b->b_refcount = 0;
+ b->b_next = bonk_filterbanklist;
+ bonk_filterbanklist = b;
+ b->b_vec = (t_filterkernel *)getbytes(nfilters * sizeof(*b->b_vec));
+
+ h = exp((log(2.)/12.)*halftones); /* specced interval between filters */
+ relspace = (h - 1)/(h + 1); /* nominal spacing-per-f for fbank */
+
+ cf = firstbin;
+ bw = cf * relspace * overlap;
+ if (bw < HALFWIDTH)
+ bw = HALFWIDTH;
+ for (i = 0; i < nfilters; i++)
+ {
+ float *fp, newcf, newbw;
+ float normalizer = 0;
+ int filterpoints, skippoints, hoppoints, nhops;
+
+ filterpoints = 0.5 + npoints * HALFWIDTH/bw;
+ if (cf > npoints/2)
+ {
+ post("bonk~: only using %d filters (ran past Nyquist)", i+1);
+ break;
+ }
+ if (filterpoints < 4)
+ {
+ post("bonk~: only using %d filters (kernels got too short)", i+1);
+ break;
+ }
+ else if (filterpoints > npoints)
+ filterpoints = npoints;
+
+ hoppoints = 0.5 + 0.5 * npoints * HALFWIDTH/bw;
+
+ nhops = 1. + (npoints-filterpoints)/(float)hoppoints;
+ skippoints = 0.5 * (npoints-filterpoints - (nhops-1) * hoppoints);
+
+ b->b_vec[i].k_stuff =
+ (float *)getbytes(2 * sizeof(float) * filterpoints);
+ b->b_vec[i].k_filterpoints = filterpoints;
+ b->b_vec[i].k_nhops = nhops;
+ b->b_vec[i].k_hoppoints = hoppoints;
+ b->b_vec[i].k_skippoints = skippoints;
+ b->b_vec[i].k_centerfreq = cf;
+ b->b_vec[i].k_bandwidth = bw;
+
+ for (fp = b->b_vec[i].k_stuff, j = 0; j < filterpoints; j++, fp+= 2)
+ {
+ float phase = j * cf * (2*3.14159/ npoints);
+ float wphase = j * (2*3.14159 / filterpoints);
+ float window = sin(0.5*wphase);
+ fp[0] = window * cos(phase);
+ fp[1] = window * sin(phase);
+ normalizer += window;
+ }
+ normalizer = 1/(normalizer * nhops);
+ for (fp = b->b_vec[i].k_stuff, j = 0;
+ j < filterpoints; j++, fp+= 2)
+ fp[0] *= normalizer, fp[1] *= normalizer;
+#if 0
+ post("i %d cf %.2f bw %.2f nhops %d, hop %d, skip %d, npoints %d",
+ i, cf, bw, nhops, hoppoints, skippoints, filterpoints);
+#endif
+ newcf = (cf + bw/overlap)/(1 - relspace);
+ newbw = newcf * overlap * relspace;
+ if (newbw < HALFWIDTH)
+ {
+ newbw = HALFWIDTH;
+ newcf = cf + 2 * HALFWIDTH / overlap;
+ }
+ cf = newcf;
+ bw = newbw;
+ }
+ for (; i < nfilters; i++)
+ b->b_vec[i].k_stuff = 0, b->b_vec[i].k_filterpoints = 0;
+ return (b);
+}
+
+static void bonk_freefilterbank(t_filterbank *b)
+{
+ t_filterbank *b2, *b3;
+ int i;
+ if (bonk_filterbanklist == b)
+ bonk_filterbanklist = b->b_next;
+ else for (b2 = bonk_filterbanklist; b3 = b2->b_next; b2 = b3)
+ if (b3 == b)
+ {
+ b2->b_next = b3->b_next;
+ break;
+ }
+ for (i = 0; i < b->b_nfilters; i++)
+ if (b->b_vec[i].k_stuff)
+ freebytes(b->b_vec[i].k_stuff,
+ b->b_vec[i].k_filterpoints * sizeof(float));
+ freebytes(b, sizeof(*b));
+}
+
+static void bonk_donew(t_bonk *x, int npoints, int period, int nsig,
+ int nfilters, float halftones, float overlap, float firstbin,
+ float samplerate)
{
int i, j;
t_hist *h;
float *fp;
t_insig *g;
-
+ t_filterbank *fb;
for (j = 0, g = x->x_insig; j < nsig; j++, g++)
{
for (i = 0, h = g->g_hist; i--; h++)
- h->h_power = h->h_mask = h->h_before = 0, h->h_countup = 0;
- /* we ought to check for failure to allocate memory here */
- g->g_inbuf = (float *)getbytes(NPOINTS * sizeof(float));
- for (i = NPOINTS, fp = g->g_inbuf; i--; fp++) *fp = 0;
+ {
+ h->h_power = h->h_before = 0, h->h_countup = 0;
+ for (j = 0; j < MASKHIST; j++)
+ h->h_mask[j] = 0;
+ }
+ /* we ought to check for failure to allocate memory here */
+ g->g_inbuf = (float *)getbytes(npoints * sizeof(float));
+ for (i = npoints, fp = g->g_inbuf; i--; fp++) *fp = 0;
}
+ if (!period) period = npoints/2;
+ x->x_npoints = npoints;
+ x->x_period = period;
x->x_ninsig = nsig;
+ x->x_nfilters = nfilters;
+ x->x_halftones = halftones;
x->x_template = (t_template *)getbytes(0);
x->x_ntemplate = 0;
x->x_infill = 0;
x->x_countdown = 0;
- if (!period) period = NPOINTS/2;
- x->x_period = 1 << ilog2(period);
x->x_willattack = 0;
+ x->x_attacked = 0;
+ x->x_maskphase = 0;
x->x_debug = 0;
x->x_hithresh = DEFHITHRESH;
x->x_lothresh = DEFLOTHRESH;
@@ -215,33 +429,51 @@ static void bonk_donew(t_bonk *x, int period, int nsig)
x->x_learncount = 0;
x->x_debouncedecay = DEFDEBOUNCEDECAY;
x->x_minvel = DEFMINVEL;
+ x->x_useloudness = 0;
x->x_debouncevel = 0;
+ x->x_attackbins = DEFATTACKBINS;
+ x->x_sr = samplerate;
+ x->x_filterbank = 0;
+ x->x_hit = 0;
+ for (fb = bonk_filterbanklist; fb; fb = fb->b_next)
+ if (fb->b_nfilters == x->x_nfilters &&
+ fb->b_halftones == x->x_halftones &&
+ fb->b_firstbin == firstbin &&
+ fb->b_overlap == overlap &&
+ fb->b_npoints == x->x_npoints)
+ {
+ fb->b_refcount++;
+ x->x_filterbank = fb;
+ break;
+ }
+ if (!x->x_filterbank)
+ x->x_filterbank = bonk_newfilterbank(npoints, nfilters,
+ halftones, overlap, firstbin),
+ x->x_filterbank->b_refcount++;
}
-
-static void bonk_print(t_bonk *x, t_floatarg f);
-
-static void bonk_dotick(t_bonk *x, int hit)
+static void bonk_tick(t_bonk *x)
{
- t_atom at[NFILTERS], *ap, at2[3];
+ t_atom at[MAXNFILTERS], *ap, at2[3];
int i, j, k, n;
t_hist *h;
- float powerout[NFILTERS*MAXCHANNELS], *pp, vel = 0, temperature = 0;
+ float *pp, vel = 0, temperature = 0;
float *fp;
t_template *tp;
- int nfit, ninsig = x->x_ninsig, ntemplate = x->x_ntemplate;
+ int nfit, ninsig = x->x_ninsig, ntemplate = x->x_ntemplate, nfilters = x->x_nfilters;
t_insig *gp;
- int totalbins = NFILTERS * ninsig;
+#ifdef _MSC_VER
+ float powerout[MAXNFILTERS*MAXCHANNELS];
+#else
+ float *powerout = alloca(x->x_nfilters * x->x_ninsig * sizeof(*powerout));
+#endif
- x->x_willattack = 0;
-
for (i = ninsig, pp = powerout, gp = x->x_insig; i--; gp++)
{
- for (j = 0, h = gp->g_hist; j < NFILTERS; j++, h++, pp++)
+ for (j = 0, h = gp->g_hist; j < nfilters; j++, h++, pp++)
{
- float power = (hit ? h->h_mask - h->h_before : h->h_power);
- float intensity = *pp =
- (power > 0 ? 100. * qrsqrt(qrsqrt(power)) : 0);
+ float power = h->h_outpower;
+ float intensity = *pp = (power > 0 ? 100. * qrsqrt(qrsqrt(power)) : 0);
vel += intensity;
temperature += intensity * (float)j;
}
@@ -249,23 +481,23 @@ static void bonk_dotick(t_bonk *x, int hit)
if (vel > 0) temperature /= vel;
else temperature = 0;
vel *= 0.5 / ninsig; /* fudge factor */
- if (hit)
+ if (x->x_hit)
{
- /* if hit nonzero it's a clock callback. if in "learn" mode update the
- template list; in any event match the hit to known templates. */
-
+ /* if hit nonzero it's a clock callback. if in "learn" mode update the
+ template list; in any event match the hit to known templates. */
+
if (vel < x->x_debouncevel)
{
if (x->x_debug)
post("bounce cancelled: vel %f debounce %f",
- vel, x->x_debouncevel);
+ vel, x->x_debouncevel);
return;
}
if (vel < x->x_minvel)
{
if (x->x_debug)
post("low velocity cancelled: vel %f, minvel %f",
- vel, x->x_minvel);
+ vel, x->x_minvel);
return;
}
x->x_debouncevel = vel;
@@ -276,23 +508,23 @@ static void bonk_dotick(t_bonk *x, int hit)
if ((!ntemplate) || (msec > 200))
{
int countup = x->x_learncount;
- /* normalize to 100 */
+ /* normalize to 100 */
float norm;
- for (i = NFILTERS * ninsig, norm = 0, pp = powerout; i--; pp++)
+ for (i = nfilters * ninsig, norm = 0, pp = powerout; i--; pp++)
norm += *pp * *pp;
if (norm < 1.0e-15) norm = 1.0e-15;
norm = 100.f * qrsqrt(norm);
- /* check if this is the first strike for a new template */
+ /* check if this is the first strike for a new template */
if (!countup)
{
int oldn = ntemplate;
x->x_ntemplate = ntemplate = oldn + ninsig;
x->x_template = (t_template *)t_resizebytes(x->x_template,
oldn * sizeof(x->x_template[0]),
- ntemplate * sizeof(x->x_template[0]));
+ ntemplate * sizeof(x->x_template[0]));
for (i = ninsig, pp = powerout; i--; oldn++)
- for (j = NFILTERS, fp = x->x_template[oldn].t_amp; j--;
- pp++, fp++)
+ for (j = nfilters, fp = x->x_template[oldn].t_amp; j--;
+ pp++, fp++)
*fp = *pp * norm;
}
else
@@ -301,10 +533,10 @@ static void bonk_dotick(t_bonk *x, int hit)
if (oldn < 0) post("bonk_tick bug");
for (i = ninsig, pp = powerout; i--; oldn++)
{
- for (j = NFILTERS, fp = x->x_template[oldn].t_amp; j--;
- pp++, fp++)
- *fp = (countup * *fp + *pp * norm)
- /(countup + 1.0f);
+ for (j = nfilters, fp = x->x_template[oldn].t_amp; j--;
+ pp++, fp++)
+ *fp = (countup * *fp + *pp * norm)
+ /(countup + 1.0f);
}
}
countup++;
@@ -320,18 +552,18 @@ static void bonk_dotick(t_bonk *x, int hit)
int templatecount;
nfit = -1;
for (i = 0, templatecount = 0, tp = x->x_template;
- templatecount < ntemplate; i++)
+ templatecount < ntemplate; i++)
{
float dotprod = 0;
for (k = 0, pp = powerout;
- k < ninsig && templatecount < ntemplate;
- k++, tp++, templatecount++)
+ k < ninsig && templatecount < ntemplate;
+ k++, tp++, templatecount++)
{
- for (j = NFILTERS, fp = tp->t_amp;
- j--; fp++, pp++)
+ for (j = nfilters, fp = tp->t_amp;
+ j--; fp++, pp++)
{
if (*fp < 0 || *pp < 0) post("bonk_tick bug 2");
- dotprod += *fp * *pp;
+ dotprod += *fp * *pp;
}
}
if (dotprod > bestfit)
@@ -345,69 +577,78 @@ static void bonk_dotick(t_bonk *x, int hit)
else nfit = 0;
}
else nfit = -1; /* hit is zero; this is the "bang" method. */
-
+
+ x->x_attacked = 1;
if (x->x_debug)
post("bonk out: number %d, vel %f, temperature %f",
nfit, vel, temperature);
+
SETFLOAT(at2, nfit);
SETFLOAT(at2+1, vel);
SETFLOAT(at2+2, temperature);
outlet_list(x->x_cookedout, 0, 3, at2);
-
+
for (n = 0, gp = x->x_insig + (ninsig-1),
- pp = powerout + NFILTERS * (ninsig-1);
- n < ninsig; n++, gp--, pp -= NFILTERS)
+ pp = powerout + nfilters * (ninsig-1); n < ninsig;
+ n++, gp--, pp -= nfilters)
{
float *pp2;
- for (i = 0, ap = at, pp2 = pp; i < NFILTERS;
+ for (i = 0, ap = at, pp2 = pp; i < nfilters;
i++, ap++, pp2++)
{
ap->a_type = A_FLOAT;
ap->a_w.w_float = *pp2;
}
- outlet_list(gp->g_outlet, 0, NFILTERS, at);
+ outlet_list(gp->g_outlet, 0, nfilters, at);
}
}
-static void bonk_tick(t_bonk *x)
-{
- bonk_dotick(x, 1);
-}
-
static void bonk_doit(t_bonk *x)
{
- int i, j, n;
+ int i, j, ch, n;
t_filterkernel *k;
t_hist *h;
- float growth = 0, *fp1, *fp2, *fp3, *fp4;
- float windowbuf[NPOINTS];
- static int poodle;
- int ninsig = x->x_ninsig;
+ float growth = 0, *fp1, *fp3, *fp4, hithresh, lothresh;
+ int ninsig = x->x_ninsig, nfilters = x->x_nfilters,
+ maskphase = x->x_maskphase, nextphase, oldmaskphase;
t_insig *gp;
-
- for (n = 0, gp = x->x_insig; n < ninsig; n++, gp++)
- {
- for (i = NPOINTS, fp1 = gp->g_inbuf, fp2 = bonk_hanningwindow,
- fp3 = windowbuf; i--; fp1++, fp2++, fp3++)
- *fp3 = *fp1 * *fp2;
-
- for (i = 0, k = bonk_filterkernels, h = gp->g_hist;
- i < NFILTERS; i++, k++, h++)
+ nextphase = maskphase + 1;
+ if (nextphase >= MASKHIST)
+ nextphase = 0;
+ x->x_maskphase = nextphase;
+ oldmaskphase = nextphase - x->x_attackbins;
+ if (oldmaskphase < 0)
+ oldmaskphase += MASKHIST;
+ if (x->x_useloudness)
+ hithresh = qrsqrt(qrsqrt(x->x_hithresh)),
+ lothresh = qrsqrt(qrsqrt(x->x_lothresh));
+ else hithresh = x->x_hithresh, lothresh = x->x_lothresh;
+ for (ch = 0, gp = x->x_insig; ch < ninsig; ch++, gp++)
+ {
+ for (i = 0, k = x->x_filterbank->b_vec, h = gp->g_hist;
+ i < nfilters; i++, k++, h++)
{
- float power = 0, maskpow = h->h_mask;
+ float power = 0, maskpow = h->h_mask[maskphase];
+ float *inbuf= gp->g_inbuf + k->k_skippoints;
int countup = h->h_countup;
- int npoints = k->k_npoints;
- /* special case: the fourth filter is centered */
- float *inbuf = gp->g_inbuf +
- (i == 3 ? ((NPOINTS - npoints) / 2) : 0);
-
- /* run the filter repeatedly, sliding it forward by half its
- length, stopping when it runs past the end of the buffer */
- for (fp1 = inbuf, fp2 = fp1 + NPOINTS - k->k_npoints;
- fp1 <= fp2; fp1 += npoints/2)
+ int filterpoints = k->k_filterpoints;
+ /* if the user asked for more filters that fit under the
+ Nyquist frequency, some filters won't actually be filled in
+ so we skip running them. */
+ if (!filterpoints)
+ {
+ h->h_countup = 0;
+ h->h_mask[nextphase] = 0;
+ h->h_power = 0;
+ continue;
+ }
+ /* run the filter repeatedly, sliding it forward by hoppoints,
+ for nhop times */
+ for (fp1 = inbuf, n = 0;
+ n < k->k_nhops; fp1 += k->k_hoppoints, n++)
{
float rsum = 0, isum = 0;
- for (fp3 = fp1, fp4 = k->k_stuff, j = npoints; j--;)
+ for (fp3 = fp1, fp4 = k->k_stuff, j = filterpoints; j--;)
{
float g = *fp3++;
rsum += g * *fp4++;
@@ -415,14 +656,19 @@ static void bonk_doit(t_bonk *x)
}
power += rsum * rsum + isum * isum;
}
-
- if (!x->x_willattack) h->h_before = maskpow;
-
- if (power > maskpow)
- growth += power/(maskpow + 1.0e-15) - 1.f;
+ if (!x->x_willattack)
+ h->h_before = maskpow;
+
+ if (power > h->h_mask[oldmaskphase])
+ {
+ if (x->x_useloudness)
+ growth += qrsqrt(qrsqrt(
+ power/(h->h_mask[oldmaskphase] + 1.0e-15))) - 1.f;
+ else growth += power/(h->h_mask[oldmaskphase] + 1.0e-15) - 1.f;
+ }
if (!x->x_willattack && countup >= x->x_masktime)
maskpow *= x->x_maskdecay;
-
+
if (power > maskpow)
{
maskpow = power;
@@ -430,95 +676,130 @@ static void bonk_doit(t_bonk *x)
}
countup++;
h->h_countup = countup;
- h->h_mask = maskpow;
+ h->h_mask[nextphase] = maskpow;
h->h_power = power;
}
}
- if (x->x_willattack > 4)
- {
- /* if it takes more than 4 analyses for the energy to stop growing,
- forget it; we would rather miss the note than report it late. */
- if (x->x_debug) post("soft attack cancelled");
- x->x_willattack = 0;
- }
- else if (x->x_willattack)
+ if (x->x_willattack)
{
+ if (x->x_willattack > MAXATTACKWAIT || growth < x->x_lothresh)
+ {
+ /* if haven't yet, and if not in spew mode, report a hit */
+ if (!x->x_spew && !x->x_attacked)
+ {
+ for (ch = 0, gp = x->x_insig; ch < ninsig; ch++, gp++)
+ for (i = nfilters, h = gp->g_hist; i--; h++)
+ h->h_outpower = h->h_mask[nextphase];
+ x->x_hit = 1;
+ clock_delay(x->x_clock, 0);
+ }
+ }
if (growth < x->x_lothresh)
- clock_delay(x->x_clock, 0);
+ x->x_willattack = 0;
else x->x_willattack++;
}
else if (growth > x->x_hithresh)
{
- if (x->x_debug) post("attack; growth = %f", growth);
+ if (x->x_debug) post("attack: growth = %f", growth);
x->x_willattack = 1;
- for (n = 0, gp = x->x_insig; n < ninsig; n++, gp++)
- for (i = NFILTERS, h = gp->g_hist; i--; h++)
- h->h_mask = h->h_power, h->h_countup = 0;
+ x->x_attacked = 0;
+ for (ch = 0, gp = x->x_insig; ch < ninsig; ch++, gp++)
+ for (i = nfilters, h = gp->g_hist; i--; h++)
+ h->h_mask[nextphase] = h->h_power, h->h_countup = 0;
}
- x->x_debouncevel *= x->x_debouncedecay;
-
- /* shift the input buffer and update counters */
- if (x->x_period > NPOINTS) x->x_countdown = x->x_period - NPOINTS;
- else x->x_countdown = 0;
- if (x->x_period < NPOINTS)
+ /* if in "spew" mode just always output */
+ if (x->x_spew)
{
- int overlap = NPOINTS - x->x_period;
-
- for (n = 0, gp = x->x_insig; n < ninsig; n++, gp++)
- for (i = overlap, fp1 = gp->g_inbuf, fp2 = fp1 + x->x_period; i--;)
- *fp1++ = *fp2++;
- x->x_infill = overlap;
+ for (ch = 0, gp = x->x_insig; ch < ninsig; ch++, gp++)
+ for (i = nfilters, h = gp->g_hist; i--; h++)
+ h->h_outpower = h->h_power;
+ x->x_hit = 0;
+ clock_delay(x->x_clock, 0);
}
- else x->x_infill = 0;
- poodle = 1;
+ x->x_debouncevel *= x->x_debouncedecay;
}
static t_int *bonk_perform(t_int *w)
{
t_bonk *x = (t_bonk *)(w[1]);
int n = (int)(w[2]);
- int onset = (int)(w[3]);
- if (x->x_countdown > 0) x->x_countdown -= n;
+ int onset = 0;
+ if (x->x_countdown >= n)
+ x->x_countdown -= n;
else
{
- int i, j, infill = x->x_infill, ninsig = x->x_ninsig;
+ int i, j, ninsig = x->x_ninsig;
t_insig *gp;
- for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++)
+ if (x->x_countdown > 0)
+ {
+ n -= x->x_countdown;
+ onset += x->x_countdown;
+ x->x_countdown = 0;
+ }
+ while (n > 0)
{
- float *fp = gp->g_inbuf + infill;
- t_float *in1 = gp->g_invec + onset;
- for (j = 0; j < n; j++)
- *fp++ = *in1++;
+ int infill = x->x_infill;
+ int m = (n < (x->x_npoints - infill) ?
+ n : (x->x_npoints - infill));
+ for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++)
+ {
+ float *fp = gp->g_inbuf + infill;
+ t_float *in1 = gp->g_invec + onset;
+ for (j = 0; j < m; j++)
+ *fp++ = *in1++;
+ }
+ infill += m;
+ x->x_infill = infill;
+ if (infill == x->x_npoints)
+ {
+ bonk_doit(x);
+
+ /* shift or clear the input buffer and update counters */
+ if (x->x_period > x->x_npoints)
+ x->x_countdown = x->x_period - x->x_npoints;
+ else x->x_countdown = 0;
+ if (x->x_period < x->x_npoints)
+ {
+ int overlap = x->x_npoints - x->x_period;
+ float *fp1, *fp2;
+ for (n = 0, gp = x->x_insig; n < ninsig; n++, gp++)
+ for (i = overlap, fp1 = gp->g_inbuf,
+ fp2 = fp1 + x->x_period; i--;)
+ *fp1++ = *fp2++;
+ x->x_infill = overlap;
+ }
+ else x->x_infill = 0;
+ }
+ n -= m;
+ onset += m;
}
- infill += n;
- x->x_infill = infill;
- if (infill == NPOINTS) bonk_doit(x);
}
- return (w+4);
+ return (w+3);
}
static void bonk_dsp(t_bonk *x, t_signal **sp)
{
- int i, n = sp[0]->s_n, vsize = x->x_period, ninsig = x->x_ninsig;
+ int i, n = sp[0]->s_n, ninsig = x->x_ninsig;
t_insig *gp;
- if (vsize > n) vsize = n;
+
+ x->x_sr = sp[0]->s_sr;
for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++)
gp->g_invec = (*(sp++))->s_vec;
-
- for (i = 0; i < n; i += vsize)
- dsp_add(bonk_perform, 3, x, vsize, i);
+
+ dsp_add(bonk_perform, 2, x, n);
}
static void bonk_thresh(t_bonk *x, t_floatarg f1, t_floatarg f2)
{
if (f1 > f2)
post("bonk: warning: low threshold greater than hi threshold");
- x->x_lothresh = f1;
- x->x_hithresh = f2;
+ x->x_lothresh = (f1 <= 0 ? 0.0001 : f1);
+ x->x_hithresh = (f2 <= 0 ? 0.0001 : f2);
}
+#ifdef PD
static void bonk_mask(t_bonk *x, t_floatarg f1, t_floatarg f2)
{
int ticks = f1;
@@ -542,32 +823,79 @@ static void bonk_minvel(t_bonk *x, t_floatarg f)
x->x_minvel = f;
}
+static void bonk_debug(t_bonk *x, t_floatarg f)
+{
+ x->x_debug = (f != 0);
+}
+
+static void bonk_spew(t_bonk *x, t_floatarg f)
+{
+ x->x_spew = (f != 0);
+}
+
+static void bonk_useloudness(t_bonk *x, t_floatarg f)
+{
+ x->x_useloudness = (f != 0);
+}
+
+static void bonk_attackbins(t_bonk *x, t_floatarg f)
+{
+ if (f < 1)
+ f = 1;
+ else if (f > MASKHIST)
+ f = MASKHIST;
+ x->x_attackbins = f;
+}
+
+static void bonk_learn(t_bonk *x, t_floatarg f)
+{
+ int n = f;
+ if (n < 0) n = 0;
+ if (n)
+ {
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ x->x_ntemplate * sizeof(x->x_template[0]), 0);
+ x->x_ntemplate = 0;
+ }
+ x->x_learn = n;
+ x->x_learncount = 0;
+}
+#endif
+
static void bonk_print(t_bonk *x, t_floatarg f)
{
int i;
post("thresh %f %f", x->x_lothresh, x->x_hithresh);
post("mask %d %f", x->x_masktime, x->x_maskdecay);
+ post("attack-bins %d", x->x_attackbins);
post("debounce %f", x->x_debouncedecay);
post("minvel %f", x->x_minvel);
+ post("spew %d", x->x_spew);
+ post("useloudness %d", x->x_useloudness);
+
+#if 0 /* LATER rewrite without hard-coded 11 filters */
if (x->x_ntemplate)
{
post("templates:");
for (i = 0; i < x->x_ntemplate; i++)
- post("%2d \
-%5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f", i,
- x->x_template[i].t_amp[0],
- x->x_template[i].t_amp[1],
- x->x_template[i].t_amp[2],
- x->x_template[i].t_amp[3],
- x->x_template[i].t_amp[4],
- x->x_template[i].t_amp[5],
- x->x_template[i].t_amp[6],
- x->x_template[i].t_amp[7],
- x->x_template[i].t_amp[8],
- x->x_template[i].t_amp[9],
- x->x_template[i].t_amp[10]);
+ post(
+"%2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f",
+ i,
+ x->x_template[i].t_amp[0],
+ x->x_template[i].t_amp[1],
+ x->x_template[i].t_amp[2],
+ x->x_template[i].t_amp[3],
+ x->x_template[i].t_amp[4],
+ x->x_template[i].t_amp[5],
+ x->x_template[i].t_amp[6],
+ x->x_template[i].t_amp[7],
+ x->x_template[i].t_amp[8],
+ x->x_template[i].t_amp[9],
+ x->x_template[i].t_amp[10]);
}
else post("no templates");
+#endif
+ post("number of templates %d", x->x_ntemplate);
if (x->x_learn) post("learn mode");
if (f != 0)
{
@@ -577,101 +905,55 @@ static void bonk_print(t_bonk *x, t_floatarg f)
{
t_hist *h;
if (ninsig > 1) post("input %d:", j+1);
- for (i = NFILTERS, h = gp->g_hist; i--; h++)
+ for (i = x->x_nfilters, h = gp->g_hist; i--; h++)
post("pow %f mask %f before %f count %d",
- h->h_power, h->h_mask, h->h_before, h->h_countup);
+ h->h_power, h->h_mask[x->x_maskphase],
+ h->h_before, h->h_countup);
}
+ post("filter details (frequencies are in units of %.2f-Hz. bins):",
+ x->x_sr);
+ for (j = 0; j < x->x_nfilters; j++)
+ post("%2d cf %.2f bw %.2f nhops %d hop %d skip %d npoints %d",
+ j,
+ x->x_filterbank->b_vec[j].k_centerfreq,
+ x->x_filterbank->b_vec[j].k_bandwidth,
+ x->x_filterbank->b_vec[j].k_nhops,
+ x->x_filterbank->b_vec[j].k_hoppoints,
+ x->x_filterbank->b_vec[j].k_skippoints,
+ x->x_filterbank->b_vec[j].k_filterpoints);
}
if (x->x_debug) post("debug mode");
}
-static void bonk_debug(t_bonk *x, t_floatarg f)
-{
- x->x_debug = (f != 0);
-}
-
-static void bonk_learn(t_bonk *x, t_floatarg f)
-{
- int n = f;
- if (n < 0) n = 0;
- if (n)
- {
- x->x_template = (t_template *)t_resizebytes(x->x_template,
- x->x_ntemplate * sizeof(x->x_template[0]), 0);
- x->x_ntemplate = 0;
- }
- x->x_learn = n;
- x->x_learncount = 0;
-}
-
static void bonk_forget(t_bonk *x)
{
int ntemplate = x->x_ntemplate, newn = ntemplate - x->x_ninsig;
if (newn < 0) newn = 0;
x->x_template = (t_template *)t_resizebytes(x->x_template,
x->x_ntemplate * sizeof(x->x_template[0]),
- newn * sizeof(x->x_template[0]));
+ newn * sizeof(x->x_template[0]));
x->x_ntemplate = newn;
x->x_learncount = 0;
}
-#if 0
static void bonk_bang(t_bonk *x)
{
- t_atom at[NFILTERS];
- int i, j, ninsig = x->x_ninsig;
+ int i, ch;
t_insig *gp;
-
- SETFLOAT(at2, nfit);
- SETFLOAT(at2+1, vel);
- SETFLOAT(at2+2, temperature);
- outlet_list(x->x_cookedout, 0L, 3, at2);
- for (i = 0, gp = x->x_insig + (ninsig-1); i < ninsig; i++, gp--)
- {
- for (j = 0; j < NFILTERS; j++)
- {
- at[j].a_type = A_FLOAT;
- at[j].a_w.w_float = 100 * qrsqrt(qrsqrt(gp->g_hist[j].h_power));
- }
- outlet_list(gp->g_outlet, 0L, NFILTERS, at);
- }
-}
-#endif
-
-static void bonk_bang(t_bonk *x)
-{
- bonk_dotick(x, 0);
-}
-
-static void bonk_setupkernels(void)
-{
- int i, j;
- float *fp;
- for (i = 0; i < NFILTERS; i++)
+ x->x_hit = 0;
+ for (ch = 0, gp = x->x_insig; ch < x->x_ninsig; ch++, gp++)
{
- int npoints = bonk_filterkernels[i].k_npoints;
- float freq = bonk_filterkernels[i].k_freq;
- float normalize = bonk_filterkernels[i].k_normalize;
- float phaseinc = (2.f * 3.14159f) / npoints;
- bonk_filterkernels[i].k_stuff =
- (float *)getbytes(2 * sizeof(float) * npoints);
- for (fp = bonk_filterkernels[i].k_stuff, j = npoints; j--;)
- {
- float phase = j * phaseinc;
- float window = normalize * (0.5f - 0.5f * cos(phase));
- *fp++ = window * cos(freq * phase);
- *fp++ = window * sin(freq * phase);
- }
+ t_hist *h;
+ for (i = 0, h = gp->g_hist; i < x->x_nfilters; i++, h++)
+ h->h_outpower = h->h_power;
}
- for (i = 0; i < NPOINTS; i++)
- bonk_hanningwindow[i] = (0.5f - 0.5f * cos(i * (2*3.14159)/NPOINTS));
+ bonk_tick(x);
}
-#ifdef PD
static void bonk_read(t_bonk *x, t_symbol *s)
{
FILE *fd = fopen(s->s_name, "r");
- float vec[NFILTERS];
+ float vec[MAXNFILTERS];
int i, ntemplate = 0, remaining;
float *fp, *fp2;
if (!fd)
@@ -683,14 +965,14 @@ static void bonk_read(t_bonk *x, t_symbol *s)
x->x_ntemplate * sizeof(t_template), 0);
while (1)
{
- for (i = NFILTERS, fp = vec; i--; fp++)
+ for (i = x->x_nfilters, fp = vec; i--; fp++)
if (fscanf(fd, "%f", fp) < 1) goto nomore;
x->x_template = (t_template *)t_resizebytes(x->x_template,
ntemplate * sizeof(t_template),
- (ntemplate + 1) * sizeof(t_template));
- for (i = NFILTERS, fp = vec,
- fp2 = x->x_template[ntemplate].t_amp; i--;)
- *fp2++ = *fp++;
+ (ntemplate + 1) * sizeof(t_template));
+ for (i = x->x_nfilters, fp = vec,
+ fp2 = x->x_template[ntemplate].t_amp; i--;)
+ *fp2++ = *fp++;
ntemplate++;
}
nomore:
@@ -706,141 +988,7 @@ nomore:
x->x_ntemplate = ntemplate;
fclose(fd);
}
-#endif /* PD */
-
-#ifdef MSP
-static void bonk_read(t_bonk *x, t_symbol *s)
-{
- SFTypeList types;
- short vol = 0;
- OSType type;
- char name[256];
- char **buf;
- int eaten;
- long size = 100;
- int i, ntemplate = 0;
- float vec[NFILTERS];
- float *fp, *fp2;
- if (s->s_name[0])
- {
- vol = defvolume();
- strcpy (name, s->s_name);
-
- if (readtohandle (name, vol, &buf, &size) != 0)
-
- {
- post("bonk~: problem with reading file.");
- return;
-
- }
- else
- {
- post("bonk~: template read successfully.");
- }
- for (eaten = 0; ;)
- {
- for (i = NFILTERS, fp = vec; i--; fp++)
- {
- while (eaten < size && (
- (*buf)[eaten] == ' ' ||
- (*buf)[eaten] == '\t' ||
- (*buf)[eaten] == '\n' ||
- (*buf)[eaten] == ';' ||
- (*buf)[eaten] == '\r'))
- eaten++;
- if (eaten >= size) goto nomore;
- if (sscanf(&(*buf)[eaten], "%f", fp) < 1) goto nomore;
-
- while (eaten < size && !(
- (*buf)[eaten] == ' ' ||
- (*buf)[eaten] == '\t' ||
- (*buf)[eaten] == '\n' ||
- (*buf)[eaten] == ';' ||
- (*buf)[eaten] == '\r'))
- eaten++;
- }
- x->x_template = (t_template *)t_resizebytes(x->x_template,
-
- ntemplate * sizeof(t_template),
- (ntemplate + 1) * sizeof(t_template));
-
- for (i = NFILTERS, fp = vec,
- fp2 = x->x_template[ntemplate].t_amp; i--;)
- *fp2++ = *fp++;
- ntemplate++;
- post("bonk~: fp = %f", fp);
- }
- }
- else
- {
- name[0] = 0;
- types[0]='TEXT';
- types[1]='maxb';
-
- open_promptset("Select template for reading.");
-
- if (open_dialog(name, &vol, &type, types, 2))
- {
- post("bonk~: open canceled");
- return;
- }
- x->x_template = (t_template *)t_resizebytes(x->x_template,
-
- x->x_ntemplate * sizeof(t_template), 0);
-
-
- if (readtohandle (name, vol, &buf, &size) != 0)
-
- {
- post("bonk~: problem with reading file.");
- return;
-
- }
- else
- {
- post("bonk~: template read successfully.");
- }
- for (eaten = 0; ;)
- {
- for (i = NFILTERS, fp = vec; i--; fp++)
- {
- while (eaten < size && (
- (*buf)[eaten] == ' ' ||
- (*buf)[eaten] == '\t' ||
- (*buf)[eaten] == '\n' ||
- (*buf)[eaten] == ';' ||
- (*buf)[eaten] == '\r'))
- eaten++;
- if (eaten >= size) goto nomore;
- if (sscanf(&(*buf)[eaten], "%f", fp) < 1) goto nomore;
-
- while (eaten < size && !(
- (*buf)[eaten] == ' ' ||
- (*buf)[eaten] == '\t' ||
- (*buf)[eaten] == '\n' ||
- (*buf)[eaten] == ';' ||
- (*buf)[eaten] == '\r'))
- eaten++;
- }
- x->x_template = (t_template *)t_resizebytes(x->x_template,
-
- ntemplate * sizeof(t_template),
- (ntemplate + 1) * sizeof(t_template));
-
- for (i = NFILTERS, fp = vec,
- fp2 = x->x_template[ntemplate].t_amp; i--;)
- *fp2++ = *fp++;
- ntemplate++;
- }
- nomore:
- post("bonk~: read %d templates", ntemplate);
-
- x->x_ntemplate = ntemplate;
- }
-}
-#endif /* MSP */
-#ifdef PD
static void bonk_write(t_bonk *x, t_symbol *s)
{
FILE *fd = fopen(s->s_name, "w");
@@ -854,87 +1002,117 @@ static void bonk_write(t_bonk *x, t_symbol *s)
}
for (; ntemplate--; tp++)
{
- for (i = NFILTERS, fp = tp->t_amp; i--; fp++)
- fprintf(fd, "%6.2f ", *fp);
+ for (i = x->x_nfilters, fp = tp->t_amp; i--; fp++)
+ fprintf(fd, "%6.2f ", *fp);
fprintf(fd, "\n");
}
post("bonk: wrote %d templates\n", x->x_ntemplate);
fclose(fd);
}
-#endif /* PD */
-
-#ifdef MSP
-static void bonk_write(t_bonk *x, t_symbol *s)
-{
-
- char fn[236];
- short vol;
- short bin = 0;
- void* b;
- int i, ntemplate = x->x_ntemplate;
- t_template *tp = x->x_template;
- if (s->s_name[0])
- {
- strcpy (fn, s->s_name);
- vol = defvolume();
- b = binbuf_new();
- for (; ntemplate--; tp++)
- {
- int i;
- Atom at[11];
- for (i = 0; i < 11; i++)
- at[i].a_type = A_FLOAT, at[i].a_w.w_float = tp->t_amp[i];
- binbuf_insert(b, 0L, 11, at);
- }
- binbuf_write(b, fn, vol, bin);
- freeobject(b);
- post("bonk~: wrote file %s", fn);
- }
-
- else
- {
- saveas_promptset("Save Template file as");
- strcpy(fn, "");
- if (!saveas_dialog(fn, &vol, 0L))
- {
- b = binbuf_new();
- for (; ntemplate--; tp++)
- {
- int i;
- Atom at[11];
- for (i = 0; i < 11; i++)
- at[i].a_type = A_FLOAT, at[i].a_w.w_float =
- tp->t_amp[i];
- binbuf_insert(b, 0L, 11, at);
- }
- binbuf_write(b, fn, vol, bin);
- freeobject(b);
- post("bonk~: wrote file %s", fn);
- }
- }
-}
-#endif /* MSP */
static void bonk_free(t_bonk *x)
{
+
int i, ninsig = x->x_ninsig;
t_insig *gp = x->x_insig;
+#ifdef MSP
+ dsp_free((t_pxobject *)x);
+#endif
for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++)
- freebytes(gp->g_inbuf, NPOINTS * sizeof(float));
+ freebytes(gp->g_inbuf, x->x_npoints * sizeof(float));
clock_free(x->x_clock);
+ if (!--(x->x_filterbank->b_refcount))
+ bonk_freefilterbank(x->x_filterbank);
+
}
/* -------------------------- Pd glue ------------------------- */
#ifdef PD
-static void *bonk_new(t_floatarg fperiod, t_floatarg fnsig)
+static void *bonk_new(t_symbol *s, int argc, t_atom *argv)
{
t_bonk *x = (t_bonk *)pd_new(bonk_class);
- int nsig = fnsig, j;
+ int nsig = 1, period = DEFPERIOD, npts = DEFNPOINTS,
+ nfilters = DEFNFILTERS, j;
+ float halftones = DEFHALFTONES, overlap = DEFOVERLAP,
+ firstbin = DEFFIRSTBIN;
t_insig *g;
- if (nsig < 1) nsig = 1;
- if (nsig > MAXCHANNELS) nsig = MAXCHANNELS;
-
+
+ if (argc > 0 && argv[0].a_type == A_FLOAT)
+ {
+ /* old style args for compatibility */
+ period = atom_getfloatarg(0, argc, argv);
+ nsig = atom_getfloatarg(1, argc, argv);
+ }
+ else while (argc > 0)
+ {
+ t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+ if (!strcmp(firstarg->s_name, "-npts") && argc > 1)
+ {
+ npts = atom_getfloatarg(1, argc, argv);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-hop") && argc > 1)
+ {
+ period = atom_getfloatarg(1, argc, argv);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-nsigs") && argc > 1)
+ {
+ nsig = atom_getfloatarg(1, argc, argv);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-nfilters") && argc > 1)
+ {
+ nfilters = atom_getfloatarg(1, argc, argv);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-halftones") && argc > 1)
+ {
+ halftones = atom_getfloatarg(1, argc, argv);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-overlap") && argc > 1)
+ {
+ overlap = atom_getfloatarg(1, argc, argv);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-firstbin") && argc > 1)
+ {
+ firstbin = atom_getfloatarg(1, argc, argv);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-spew") && argc > 1)
+ {
+ x->x_spew = (atom_getfloatarg(1, argc, argv) != 0);
+ argc -= 2; argv += 2;
+ }
+ else
+ {
+ pd_error(x,
+"usage is: bonk [-npts #] [-hop #] [-nsigs #] [-nfilters #] [-halftones #]");
+ post(
+"... [-overlap #] [-firstbin #] [-spew #]");
+ argc = 0;
+ }
+ }
+
+ x->x_npoints = (npts >= MINPOINTS ? npts : DEFNPOINTS);
+ x->x_period = (period >= 1 ? period : npts/2);
+ x->x_nfilters = (nfilters >= 1 ? nfilters : DEFNFILTERS);
+ if (halftones < 0.01)
+ halftones = DEFHALFTONES;
+ else if (halftones > 12)
+ halftones = 12;
+ if (nsig < 1)
+ nsig = 1;
+ else if (nsig > MAXCHANNELS)
+ nsig = MAXCHANNELS;
+ if (firstbin < 0.5)
+ firstbin = 0.5;
+ if (overlap < 1)
+ overlap = 1;
+
x->x_clock = clock_new(x, (t_method)bonk_tick);
x->x_insig = (t_insig *)getbytes(nsig * sizeof(*x->x_insig));
for (j = 0, g = x->x_insig; j < nsig; j++, g++)
@@ -944,121 +1122,308 @@ static void *bonk_new(t_floatarg fperiod, t_floatarg fnsig)
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
}
x->x_cookedout = outlet_new(&x->x_obj, gensym("list"));
- bonk_donew(x, fperiod, nsig);
+ bonk_donew(x, npts, period, nsig, nfilters, halftones, overlap,
+ firstbin, sys_getsr());
return (x);
}
void bonk_tilde_setup(void)
{
- bonk_class = class_new(gensym("bonk~"), (t_newmethod)bonk_new,
- (t_method)bonk_free, sizeof(t_bonk), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ bonk_class = class_new(gensym("bonk~"), (t_newmethod)bonk_new, (t_method)bonk_free, sizeof(t_bonk), 0, A_GIMME, 0);
class_addmethod(bonk_class, nullfn, gensym("signal"), 0);
class_addmethod(bonk_class, (t_method)bonk_dsp, gensym("dsp"), 0);
class_addbang(bonk_class, bonk_bang);
- class_addmethod(bonk_class, (t_method)bonk_learn, gensym("learn"),
- A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_learn, gensym("learn"), A_FLOAT, 0);
class_addmethod(bonk_class, (t_method)bonk_forget, gensym("forget"), 0);
- class_addmethod(bonk_class, (t_method)bonk_thresh, gensym("thresh"),
- A_FLOAT, A_FLOAT, 0);
- class_addmethod(bonk_class, (t_method)bonk_mask, gensym("mask"),
- A_FLOAT, A_FLOAT, 0);
- class_addmethod(bonk_class, (t_method)bonk_debounce, gensym("debounce"),
- A_FLOAT, 0);
- class_addmethod(bonk_class, (t_method)bonk_minvel, gensym("minvel"),
- A_FLOAT, 0);
- class_addmethod(bonk_class, (t_method)bonk_print, gensym("print"),
- A_DEFFLOAT, 0);
- class_addmethod(bonk_class, (t_method)bonk_debug, gensym("debug"),
- A_DEFFLOAT, 0);
- class_addmethod(bonk_class, (t_method)bonk_read, gensym("read"),
- A_SYMBOL, 0);
- class_addmethod(bonk_class, (t_method)bonk_write, gensym("write"),
- A_SYMBOL, 0);
- bonk_setupkernels();
- post("bonk version 1.1 TEST 3");
+ class_addmethod(bonk_class, (t_method)bonk_thresh, gensym("thresh"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_mask, gensym("mask"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_debounce, gensym("debounce"), A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_minvel, gensym("minvel"), A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_print, gensym("print"), A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_debug, gensym("debug"), A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_spew, gensym("spew"), A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_useloudness, gensym("useloudness"), A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_attackbins, gensym("attack-bins"), A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_read, gensym("read"), A_SYMBOL, 0);
+ class_addmethod(bonk_class, (t_method)bonk_write, gensym("write"), A_SYMBOL, 0);
+ post("bonk version 1.3");
}
#endif
/* -------------------------- MSP glue ------------------------- */
#ifdef MSP
-static int ilog2(int n)
+int main()
+{
+ t_class *c;
+ t_object *attr;
+ long attrflags = 0;
+ t_symbol *sym_long = gensym("long"), *sym_float32 = gensym("float32");
+
+ c = class_new("bonk~", (method)bonk_new, (method)bonk_free, sizeof(t_bonk), (method)0L, A_GIMME, 0);
+
+ class_obexoffset_set(c, calcoffset(t_bonk, obex));
+
+ attr = attr_offset_new("npoints", sym_long, attrflags, (method)0L, (method)0L, calcoffset(t_bonk, x_npoints));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("hop", sym_long, attrflags, (method)0L, (method)0L, calcoffset(t_bonk, x_period));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("nfilters", sym_long, attrflags, (method)0L, (method)0L, calcoffset(t_bonk, x_nfilters));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("halftones", sym_float32, attrflags, (method)0L, (method)0L, calcoffset(t_bonk, x_halftones));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("overlap", sym_float32, attrflags, (method)0L, (method)0L, calcoffset(t_bonk, x_overlap));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("firstbin", sym_float32, attrflags, (method)0L, (method)0L, calcoffset(t_bonk, x_firstbin));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("minvel", sym_float32, attrflags, (method)0L, (method)bonk_minvel_set, calcoffset(t_bonk, x_minvel));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("lothresh", sym_float32, attrflags, (method)0L, (method)bonk_lothresh_set, calcoffset(t_bonk, x_lothresh));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("hithresh", sym_float32, attrflags, (method)0L, (method)bonk_hithresh_set, calcoffset(t_bonk, x_hithresh));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("masktime", sym_long, attrflags, (method)0L, (method)bonk_masktime_set, calcoffset(t_bonk, x_masktime));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("maskdecay", sym_float32, attrflags, (method)0L, (method)bonk_maskdecay_set, calcoffset(t_bonk, x_maskdecay));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("debouncedecay", sym_float32, attrflags, (method)0L, (method)bonk_debouncedecay_set, calcoffset(t_bonk, x_debouncedecay));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("debug", sym_long, attrflags, (method)0L, (method)bonk_debug_set, calcoffset(t_bonk, x_debug));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("spew", sym_long, attrflags, (method)0L, (method)bonk_spew_set, calcoffset(t_bonk, x_spew));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("useloudness", sym_long, attrflags, (method)0L, (method)bonk_useloudness_set, calcoffset(t_bonk, x_useloudness));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("attackbins", sym_long, attrflags, (method)0L, (method)bonk_attackbins_set, calcoffset(t_bonk, x_attackbins));
+ class_addattr(c, attr);
+
+ attr = attr_offset_new("learn", sym_long, attrflags, (method)0L, (method)bonk_learn_set, calcoffset(t_bonk, x_learn));
+ class_addattr(c, attr);
+
+ class_addmethod(c, (method)bonk_dsp, "dsp", A_CANT, 0);
+ class_addmethod(c, (method)bonk_bang, "bang", A_CANT, 0);
+ class_addmethod(c, (method)bonk_forget, "forget", 0);
+ class_addmethod(c, (method)bonk_thresh, "thresh", A_FLOAT, A_FLOAT, 0);
+ class_addmethod(c, (method)bonk_print, "print", A_DEFFLOAT, 0);
+ class_addmethod(c, (method)bonk_read, "read", A_DEFSYM, 0);
+ class_addmethod(c, (method)bonk_write, "write", A_DEFSYM, 0);
+ class_addmethod(c, (method)bonk_assist, "assist", A_CANT, 0);
+
+ class_addmethod(c, (method)object_obex_dumpout, "dumpout", A_CANT, 0);
+ class_addmethod(c, (method)object_obex_quickref, "quickref", A_CANT, 0);
+
+ class_dspinit(c);
+
+ class_register(CLASS_BOX, c);
+ bonk_class = c;
+
+ post("bonk~ v1.3");
+ return (0);
+}
+
+static void *bonk_new(t_symbol *s, long ac, t_atom *av)
{
- int ret = -1;
- while (n)
- {
- n >>= 1;
- ret++;
+ short j;
+ t_bonk *x;
+
+ if (x = (t_bonk *)object_alloc(bonk_class)) {
+
+ t_insig *g;
+
+ x->x_npoints = DEFNPOINTS;
+ x->x_period = DEFPERIOD;
+ x->x_nfilters = DEFNFILTERS;
+ x->x_halftones = DEFHALFTONES;
+ x->x_firstbin = DEFFIRSTBIN;
+ x->x_overlap = DEFOVERLAP;
+ x->x_ninsig = 1;
+
+ x->x_hithresh = DEFHITHRESH;
+ x->x_lothresh = DEFLOTHRESH;
+ x->x_masktime = DEFMASKTIME;
+ x->x_maskdecay = DEFMASKDECAY;
+ x->x_debouncedecay = DEFDEBOUNCEDECAY;
+ x->x_minvel = DEFMINVEL;
+ x->x_attackbins = DEFATTACKBINS;
+
+ if (!x->x_period) x->x_period = x->x_npoints/2;
+ x->x_template = (t_template *)getbytes(0);
+ x->x_ntemplate = 0;
+ x->x_infill = 0;
+ x->x_countdown = 0;
+ x->x_willattack = 0;
+ x->x_attacked = 0;
+ x->x_maskphase = 0;
+ x->x_debug = 0;
+ x->x_learn = 0;
+ x->x_learndebounce = clock_getsystime();
+ x->x_learncount = 0;
+ x->x_useloudness = 0;
+ x->x_debouncevel = 0;
+ x->x_sr = sys_getsr();
+
+ if (ac) {
+ switch (av[0].a_type) {
+ case A_LONG:
+ x->x_ninsig = av[0].a_w.w_long;
+ break;
+ }
+ }
+
+ if (x->x_ninsig < 1) x->x_ninsig = 1;
+ if (x->x_ninsig > MAXCHANNELS) x->x_ninsig = MAXCHANNELS;
+
+ attr_args_process(x, ac, av);
+
+ x->x_insig = (t_insig *)getbytes(x->x_ninsig * sizeof(*x->x_insig));
+
+ dsp_setup((t_pxobject *)x, x->x_ninsig);
+
+ object_obex_store(x, gensym("dumpout"), outlet_new(x, NULL));
+
+ x->x_cookedout = listout((t_object *)x);
+
+ for (j = 0, g = x->x_insig + x->x_ninsig-1; j < x->x_ninsig; j++, g--) {
+ g->g_outlet = listout((t_object *)x);
+ }
+
+ x->x_clock = clock_new(x, (method)bonk_tick);
+
+ bonk_donew(x, x->x_npoints, x->x_period, x->x_ninsig, x->x_nfilters,
+ x->x_halftones, x->x_overlap, x->x_firstbin, sys_getsr());
}
- return (ret);
+ return (x);
}
-static char *strcpy(char *s1, const char *s2)
+/* Attribute setters. */
+void bonk_minvel_set(t_bonk *x, void *attr, long ac, t_atom *av)
{
- char *ret = s1;
+ if (ac && av) {
+ float f = atom_getfloat(av);
+ if (f < 0) f = 0;
+ x->x_minvel = f;
+ }
+}
- while ((*s1++ = *s2++) != 0)
- ;
+void bonk_lothresh_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ float f = atom_getfloat(av);
+ if (f > x->x_hithresh)
+ post("bonk: warning: low threshold greater than hi threshold");
+ x->x_lothresh = (f <= 0 ? 0.0001 : f);
+ }
+}
+
+void bonk_hithresh_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ float f = atom_getfloat(av);
+ if (f < x->x_lothresh)
+ post("bonk: warning: low threshold greater than hi threshold");
+ x->x_hithresh = (f <= 0 ? 0.0001 : f);
+ }
+}
- return ret;
+void bonk_masktime_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ int n = atom_getlong(av);
+ x->x_masktime = (n < 0) ? 0 : n;
+ }
}
-static void *bonk_new(int period, int nsig)
+void bonk_maskdecay_set(t_bonk *x, void *attr, long ac, t_atom *av)
{
- int i, j;
- t_hist *h;
- t_bonk *x = (t_bonk *)newobject(bonk_class);
- float *fp;
- t_insig *g;
+ if (ac && av) {
+ float f = atom_getfloat(av);
+ f = (f < 0) ? 0 : f;
+ f = (f > 1) ? 1 : f;
+ x->x_maskdecay = f;
+ }
+}
- if (nsig < 1) nsig = 1;
- if (nsig > MAXCHANNELS) nsig = MAXCHANNELS;
- x->x_insig = (t_insig *)getbytes(nsig * sizeof(*x->x_insig));
- dsp_setup((t_pxobject *)x, nsig);
- x->x_cookedout = listout((t_object *)x);
- for (j = 0, g = x->x_insig + nsig-1; j < nsig; j++, g--)
- {
- g->g_outlet = listout((t_object *)x);
+void bonk_debouncedecay_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ float f = atom_getfloat(av);
+ f = (f < 0) ? 0 : f;
+ f = (f > 1) ? 1 : f;
+ x->x_debouncedecay = f;
}
- x->x_cookedout = listout((t_object *)x);
- x->x_clock = clock_new(x, (method)bonk_tick);
+}
- bonk_donew(x, period, nsig);
- return (x);
+void bonk_debug_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ int n = atom_getlong(av);
+ x->x_debug = (n != 0);
+ }
+}
+
+void bonk_spew_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ int n = atom_getlong(av);
+ x->x_spew = (n != 0);
+ }
+}
+
+void bonk_useloudness_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ int n = atom_getlong(av);
+ x->x_useloudness = (n != 0);
+ }
+}
+
+void bonk_attackbins_set(t_bonk *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av) {
+ int n = atom_getlong(av);
+ n = (n < 1) ? 1 : n;
+ n = (n > MASKHIST) ? MASKHIST : n;
+ x->x_attackbins = n;
+ }
}
-void main()
+void bonk_learn_set(t_bonk *x, void *attr, long ac, t_atom *av)
{
- setup(&bonk_class, bonk_new, (method)bonk_free,
- (short)sizeof(t_bonk), 0L, A_DEFLONG, A_DEFLONG, 0);
- addmess((method)bonk_dsp, "dsp", 0);
- addbang((method)bonk_bang);
- addmess((method)bonk_forget, "forget", 0);
- addmess((method)bonk_learn, "learn", A_FLOAT, 0);
- addmess((method)bonk_thresh, "thresh", A_FLOAT, A_FLOAT, 0);
- addmess((method)bonk_mask, "mask", A_FLOAT, A_FLOAT, 0);
- addmess((method)bonk_minvel, "minvel", A_FLOAT, 0);
- addmess((method)bonk_debounce, "debounce", A_FLOAT, 0);
- addmess((method)bonk_print, "print", A_DEFFLOAT, 0);
- addmess((method)bonk_read, "read", A_DEFSYM, 0);
- addmess((method)bonk_write, "write", A_DEFSYM, 0);
- addmess((method)bonk_assist, "assist", A_CANT, 0);
- addmess((method)bonk_debug, "debug", A_FLOAT, 0);
- bonk_setupkernels();
- post("bonk~ v1.00");
- dsp_initclass();
- rescopy('STR#',3747);
+ if (ac && av) {
+ int n = atom_getlong(av);
+ if (n != 0) {
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ x->x_ntemplate * sizeof(x->x_template[0]), 0);
+ x->x_ntemplate = 0;
+ }
+ x->x_learn = (n != 0);
+ x->x_learncount = 0;
+ }
}
+/* end attr setters */
void bonk_assist(t_bonk *x, void *b, long m, long a, char *s)
{
- assist_string(3747,m,a,1,2,s);
}
/* get current system time */
double clock_getsystime()
{
-
return gettime();
}
@@ -1068,10 +1433,8 @@ double clock_gettimesince(double prevsystime)
return ((gettime() - prevsystime));
}
-
float qrsqrt(float f)
{
- return 1/sqrt(f);
-
+ return 1/sqrt(f);
}
#endif /* MSP */