diff options
Diffstat (limited to 'pd/extra/bonk~')
-rw-r--r-- | pd/extra/bonk~/README.txt | 30 | ||||
-rw-r--r-- | pd/extra/bonk~/bonk~.c | 1083 | ||||
-rw-r--r-- | pd/extra/bonk~/makefile | 97 | ||||
-rw-r--r-- | pd/extra/bonk~/templates.txt | 4 |
4 files changed, 1214 insertions, 0 deletions
diff --git a/pd/extra/bonk~/README.txt b/pd/extra/bonk~/README.txt new file mode 100644 index 00000000..6b0017cd --- /dev/null +++ b/pd/extra/bonk~/README.txt @@ -0,0 +1,30 @@ +Bonk is copyright (C) 1997 Regents of the University of California. +Permission is granted to use this software for any purpose, commercial +or noncommercial, as long as this notice is included with all copies. + +UC MAKES NO WARRANTY, EXPRESS OR IMPLIED, IN CONNECTION WITH THIS SOFTWARE! + +---------------------------------------------------------------------------- + +This is the README file for the "bonk" percussion detector. This software +is available from http://man104nfs.ucsd.edu/~mpuckett in versions for +IRIX 5.x and for NT on Intel boxes. + +Bonk will soon be available separately for Max/MSP on Macintoshes. + +TO INSTALL FOR IRIX 5.x: download from the Web page, which will give you a +file named "bonk-x.xx.tar.Z" (where x.xx is the version number). Unpack this +by typing "zcat bonk-x.xx.tar.Z | tar xf -" which will give you a directory +named "bonk" containing the source, the object code, and the "help patch." + +TO INSTALL FOR NT: download from the Web page, which will give you a file +named "bonk-x.xx.zip" (where x.xx is the version number). Unpack this by +typing "unzip bonk-x.xx.zip" to a terminal window which will give you a +directory named "bonk". The source, the object code, and the "help patch" +will be there. + +Pd currently has no search path facility; the object file (bonk.pd_irix5 or +bonk.dll) should be copied to the directories containing whatever patches you +want to use it with. + +-Miller Puckette (msp@ucsd.edu) diff --git a/pd/extra/bonk~/bonk~.c b/pd/extra/bonk~/bonk~.c new file mode 100644 index 00000000..6b8cfa76 --- /dev/null +++ b/pd/extra/bonk~/bonk~.c @@ -0,0 +1,1083 @@ +/* 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! +*/ + +#include <math.h> +#include <stdio.h> + +#ifdef NT +#pragma warning (disable: 4305 4244) +#endif + +#ifdef MSP + +#include "ext.h" +#include "z_dsp.h" +#include "math.h" +//#include "stdio.h" +#include "ext_support.h" +//#include "ext_strings.h" +#include "ext_proto.h" + +typedef double t_floatarg; // from m_pd.h +#define flog log +#define fexp exp +#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 +#endif /* MSP */ + +#ifdef PD +#include "m_pd.h" +static t_class *bonk_class; +#endif + +/* ------------------------ bonk~ ----------------------------- */ + +#define NPOINTS 256 +#define MAXCHANNELS 8 +#define DEFPERIOD 128 +#define DEFHITHRESH 60 +#define DEFLOTHRESH 50 +#define DEFMASKTIME 4 +#define DEFMASKDECAY 0.7 +#define DEFDEBOUNCEDECAY 0 +#define DEFMINVEL 7 + + + +typedef struct _filterkernel +{ + int k_npoints; + float k_freq; + float k_normalize; + float *k_stuff; +} t_filterkernel; + +#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}, + {128, 6, .01803}, {90, 6, .02222}, {64, 6, .02362}, {46, 6, .02773}, + {32, 6, .03227}, {22, 6, .03932}, {16, 6, .04489}}; +#endif + + /* here's the 1.1 rev: */ +static t_filterkernel bonk_filterkernels[] = + {{256, 1, .01562, 0}, {256, 3, .01562, 0}, {256, 5, .01562, 0}, + {212, 6, .01886, 0}, {150, 6, .01885, 0}, {106, 6, .02179, 0}, + {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]))) + +static float bonk_hanningwindow[NPOINTS]; + +typedef struct _hist +{ + float h_power; + float h_mask; + float h_before; + int h_countup; +} t_hist; + +typedef struct template +{ + float t_amp[NFILTERS]; +} t_template; + +typedef struct _insig +{ + t_hist g_hist[NFILTERS]; /* history for each filter */ +#ifdef PD + t_outlet *g_outlet; /* outlet for raw data */ +#endif +#ifdef MSP + void *g_outlet; /* outlet for raw data */ +#endif + float *g_inbuf; /* buffered input samples */ + t_float *g_invec; /* new input samples */ +} t_insig; + +typedef struct _bonk +{ +#ifdef PD + t_object x_obj; + t_outlet *x_cookedout; + t_clock *x_clock; +#endif /* PD */ +#ifdef MSP + t_pxobject x_obj; + void *x_cookedout; // t_outlet *x_cookedout; + void *x_clock; // t_clock *x_clock; + short x_vol; // to store the volume reference number. +#endif /* MSP */ + + t_hist x_hist[NFILTERS]; + 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_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; +} 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 t_int *bonk_perform(t_int *w); +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); +void bonk_setup(void); +void main(); +float qrsqrt(float f); +static void bonk_write(t_bonk *x, t_symbol *s); +static void bonk_read(t_bonk *x, t_symbol *s); + +double clock_getsystime(); +double clock_gettimesince(double prevsystime); +static char *strcpy(char *s1, const char *s2); +static int ilog2(int n); +#endif + +static void bonk_tick(t_bonk *x); + +static void bonk_donew(t_bonk *x, int period, int nsig) +{ + int i, j; + t_hist *h; + float *fp; + t_insig *g; + + 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; + } + x->x_ninsig = nsig; + 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_debug = 0; + x->x_hithresh = DEFHITHRESH; + x->x_lothresh = DEFLOTHRESH; + x->x_masktime = DEFMASKTIME; + x->x_maskdecay = DEFMASKDECAY; + x->x_learn = 0; + x->x_learndebounce = clock_getsystime(); + x->x_learncount = 0; + x->x_debouncedecay = DEFDEBOUNCEDECAY; + x->x_minvel = DEFMINVEL; + x->x_debouncevel = 0; +} + + +static void bonk_print(t_bonk *x, t_floatarg f); + +static void bonk_dotick(t_bonk *x, int hit) +{ + t_atom at[NFILTERS], *ap, at2[3]; + int i, j, k, n; + t_hist *h; + float powerout[NFILTERS*MAXCHANNELS], *pp, vel = 0, temperature = 0; + float *fp; + t_template *tp; + int nfit, ninsig = x->x_ninsig, ntemplate = x->x_ntemplate; + t_insig *gp; + int totalbins = NFILTERS * ninsig; + + 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++) + { + float power = (hit ? h->h_mask - h->h_before : h->h_power); + float intensity = *pp = + (power > 0 ? 100. * qrsqrt(qrsqrt(power)) : 0); + vel += intensity; + temperature += intensity * (float)j; + } + } + if (vel > 0) temperature /= vel; + else temperature = 0; + vel *= 0.5 / ninsig; /* fudge factor */ + if (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 (vel < x->x_debouncevel) + { + if (x->x_debug) + post("bounce cancelled: vel %f debounce %f", + 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); + return; + } + x->x_debouncevel = vel; + if (x->x_learn) + { + double lasttime = x->x_learndebounce; + double msec = clock_gettimesince(lasttime); + if ((!ntemplate) || (msec > 200)) + { + int countup = x->x_learncount; + /* normalize to 100 */ + float norm; + 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 */ + 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])); + for (i = ninsig, pp = powerout; i--; oldn++) + for (j = NFILTERS, fp = x->x_template[oldn].t_amp; j--; + pp++, fp++) + *fp = *pp * norm; + } + else + { + int oldn = ntemplate - ninsig; + 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); + } + } + countup++; + if (countup == x->x_learn) countup = 0; + x->x_learncount = countup; + } + else return; + } + x->x_learndebounce = clock_getsystime(); + if (ntemplate) + { + float bestfit = -1e30; + int templatecount; + nfit = -1; + for (i = 0, templatecount = 0, tp = x->x_template; + templatecount < ntemplate; i++) + { + float dotprod = 0; + for (k = 0, pp = powerout; + k < ninsig && templatecount < ntemplate; + k++, tp++, templatecount++) + { + for (j = NFILTERS, fp = tp->t_amp; + j--; fp++, pp++) + { + if (*fp < 0 || *pp < 0) post("bonk_tick bug 2"); + dotprod += *fp * *pp; + } + } + if (dotprod > bestfit) + { + bestfit = dotprod; + nfit = i; + } + } + if (nfit < 0) post("bonk_tick bug"); + } + else nfit = 0; + } + else nfit = -1; /* hit is zero; this is the "bang" method. */ + + 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) + { + float *pp2; + 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); + } +} + +static void bonk_tick(t_bonk *x) +{ + bonk_dotick(x, 1); +} + +static void bonk_doit(t_bonk *x) +{ + int i, j, 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; + 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++) + { + float power = 0, maskpow = h->h_mask; + 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) + { + float rsum = 0, isum = 0; + for (fp3 = fp1, fp4 = k->k_stuff, j = npoints; j--;) + { + float g = *fp3++; + rsum += g * *fp4++; + isum += g * *fp4++; + } + 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 && countup >= x->x_masktime) + maskpow *= x->x_maskdecay; + + if (power > maskpow) + { + maskpow = power; + countup = 0; + } + countup++; + h->h_countup = countup; + h->h_mask = 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 (growth < x->x_lothresh) + clock_delay(x->x_clock, 0); + else x->x_willattack++; + } + else if (growth > x->x_hithresh) + { + 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_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) + { + 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; + } + else x->x_infill = 0; + poodle = 1; +} + +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; + else + { + int i, j, infill = x->x_infill, ninsig = x->x_ninsig; + t_insig *gp; + 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 < n; j++) + *fp++ = *in1++; + } + infill += n; + x->x_infill = infill; + if (infill == NPOINTS) bonk_doit(x); + } + return (w+4); +} + +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; + t_insig *gp; + if (vsize > n) vsize = n; + + 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); +} + +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; +} + +static void bonk_mask(t_bonk *x, t_floatarg f1, t_floatarg f2) +{ + int ticks = f1; + if (ticks < 0) ticks = 0; + if (f2 < 0) f2 = 0; + else if (f2 > 1) f2 = 1; + x->x_masktime = ticks; + x->x_maskdecay = f2; +} + +static void bonk_debounce(t_bonk *x, t_floatarg f1) +{ + if (f1 < 0) f1 = 0; + else if (f1 > 1) f1 = 1; + x->x_debouncedecay = f1; +} + +static void bonk_minvel(t_bonk *x, t_floatarg f) +{ + if (f < 0) f = 0; + x->x_minvel = f; +} + +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("debounce %f", x->x_debouncedecay); + post("minvel %f", x->x_minvel); + 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]); + } + else post("no templates"); + if (x->x_learn) post("learn mode"); + if (f != 0) + { + int j, ninsig = x->x_ninsig; + t_insig *gp; + for (j = 0, gp = x->x_insig; j < ninsig; j++, gp++) + { + t_hist *h; + if (ninsig > 1) post("input %d:", j+1); + for (i = 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); + } + } + 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])); + 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; + 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++) + { + 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); + } + } + for (i = 0; i < NPOINTS; i++) + bonk_hanningwindow[i] = (0.5f - 0.5f * cos(i * (2*3.14159)/NPOINTS)); +} + +#ifdef PD +static void bonk_read(t_bonk *x, t_symbol *s) +{ + FILE *fd = fopen(s->s_name, "r"); + float vec[NFILTERS]; + int i, ntemplate = 0, remaining; + float *fp, *fp2; + if (!fd) + { + post("%s: open failed", s->s_name); + return; + } + x->x_template = (t_template *)t_resizebytes(x->x_template, + x->x_ntemplate * sizeof(t_template), 0); + while (1) + { + for (i = 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++; + } +nomore: + if (remaining = (ntemplate % x->x_ninsig)) + { + post("bonk_read: %d templates not a multiple of %d; dropping extras"); + x->x_template = (t_template *)t_resizebytes(x->x_template, + ntemplate * sizeof(t_template), + (ntemplate - remaining) * sizeof(t_template)); + ntemplate = ntemplate - remaining; + } + post("bonk: read %d templates\n", ntemplate); + x->x_ntemplate = ntemplate; + fclose(fd); +} +#endif /* PD */ + +#ifdef MSP +static void bonk_read(t_bonk *x, t_symbol *s) // MSP +{ + 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]) // if it is named + { + 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."); + //post("bonk~: size of file is %d", size); + } + 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); + + // post("bonk~: the file name is %s", name); + + if (readtohandle (name, vol, &buf, &size) != 0) + + { + post("bonk~: problem with reading file."); + return; + + } + else + { + post("bonk~: template read successfully."); + // post("bonk~: size of file is %d", size); + } + 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; + } // end of else +} +#endif /* MSP */ + +#ifdef PD +static void bonk_write(t_bonk *x, t_symbol *s) +{ + FILE *fd = fopen(s->s_name, "w"); + int i, ntemplate = x->x_ntemplate; + t_template *tp = x->x_template; + float *fp; + if (!fd) + { + post("%s: couldn't create", s->s_name); + return; + } + for (; ntemplate--; tp++) + { + for (i = 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) // MSP +{ + + char fn[236]; + short vol; + short bin = 0; // 0 = text + void* b; + int i, ntemplate = x->x_ntemplate; + t_template *tp = x->x_template; + if (s->s_name[0]) // if it is named + { + 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); + } + } // end of else +} +#endif /* MSP */ + +static void bonk_free(t_bonk *x) +{ + int i, ninsig = x->x_ninsig; + t_insig *gp = x->x_insig; + for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++) + freebytes(gp->g_inbuf, NPOINTS * sizeof(float)); + clock_free(x->x_clock); +} + +/* -------------------------- Pd glue ------------------------- */ +#ifdef PD + +static void *bonk_new(t_floatarg fperiod, t_floatarg fnsig) +{ + t_bonk *x = (t_bonk *)pd_new(bonk_class); + int nsig = fnsig, j; + t_insig *g; + if (nsig < 1) nsig = 1; + if (nsig > MAXCHANNELS) nsig = MAXCHANNELS; + + 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++) + { + g->g_outlet = outlet_new(&x->x_obj, gensym("list")); + if (j) + 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); + return (x); +} + +void bonk_tilde_setup(void) +{ + bonk_class = class_new(gensym("bonk~"), (t_newmethod)bonk_new, 0, + sizeof(t_bonk), 0, A_DEFFLOAT, A_DEFFLOAT, 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_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"); +} +#endif + +/* -------------------------- MSP glue ------------------------- */ +#ifdef MSP + +static int ilog2(int n) +{ + int ret = -1; + while (n) + { + n >>= 1; + ret++; + } + return (ret); +} + +static char *strcpy(char *s1, const char *s2) +{ + char *ret = s1; + + while ((*s1++ = *s2++) != 0) + ; + + return ret; +} + +static void *bonk_new(int period, int nsig) +{ + int i, j; + t_hist *h; + t_bonk *x = (t_bonk *)newobject(bonk_class); + float *fp; + t_insig *g; + + 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); // nsig inputs + 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); + } + x->x_cookedout = listout((t_object *)x); + x->x_clock = clock_new(x, (method)bonk_tick); + + bonk_donew(x, period, nsig); + return (x); +} + +void main() +{ + 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 Miller Puckette, Ted Apel"); + post("bonk~ v1.00"); + dsp_initclass(); + rescopy('STR#',3747); +} + +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(); +} + + /* elapsed time in milliseconds since the given system time */ +double clock_gettimesince(double prevsystime) +{ + return ((gettime() - prevsystime)); +} + + +float qrsqrt(float f) +{ + return 1/sqrt(f); + +} +#endif /* MSP */ diff --git a/pd/extra/bonk~/makefile b/pd/extra/bonk~/makefile new file mode 100644 index 00000000..731e5cb3 --- /dev/null +++ b/pd/extra/bonk~/makefile @@ -0,0 +1,97 @@ +NAME=bonk~ +CSYM=bonk_tilde + +current: pd_linux + +# ----------------------- NT ----------------------- + +pd_nt: $(NAME).dll + +.SUFFIXES: .dll + +PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo +VC="C:\Program Files\Microsoft Visual Studio\Vc98" + +PDNTINCLUDE = /I. /I\tcl\include /I\ftp\pd\src /I$(VC)\include + +PDNTLDIR = $(VC)\lib +PDNTLIB = $(PDNTLDIR)\libc.lib \ + $(PDNTLDIR)\oldnames.lib \ + $(PDNTLDIR)\kernel32.lib \ + \ftp\pd\bin\pd.lib + +.c.dll: + cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c + link /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB) + +# ----------------------- IRIX 5.x ----------------------- + +pd_irix5: $(NAME).pd_irix5 + +.SUFFIXES: .pd_irix5 + +SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2 + +SGIINCLUDE = -I../../src + +.c.pd_irix5: + cc $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c + ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o + rm -f $*.o ../$*.pd_linux + ln -s $*.pd_linux .. + +# ----------------------- IRIX 6.x ----------------------- + +pd_irix6: $(NAME).pd_irix6 + +.SUFFIXES: .pd_irix6 + +SGICFLAGS6 = -n32 -DPD -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \ + -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \ + -Ofast=ip32 + +.c.pd_irix6: + cc $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c + ld -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o + rm $*.o + +# ----------------------- LINUX i386 ----------------------- + +pd_linux: $(NAME).pd_linux + +.SUFFIXES: .pd_linux + +LINUXCFLAGS = -fPIC -DPD -O2 -funroll-loops -fomit-frame-pointer \ + -Wall -W -Wshadow -Wstrict-prototypes -Werror \ + -Wno-unused -Wno-parentheses -Wno-switch + +LINUXINCLUDE = -I../../src + +LSTRIP = strip --strip-unneeded -R .note -R .comment + +.c.pd_linux: + cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c + cc -Wl,-export_dynamic --shared -o $*.pd_linux $*.o -lm + $(LSTRIP) $*.pd_linux + rm -f $*.o ../$*.pd_linux + ln -s $*/$*.pd_linux .. + +# ----------------------- Mac OSX ----------------------- + +pd_darwin: $(NAME).pd_darwin + +.SUFFIXES: .pd_darwin + +DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \ + -Wno-unused -Wno-parentheses -Wno-switch + +.c.pd_darwin: + cc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c + cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o + rm -f $*.o ../$*.pd_darwin + ln -s $*/$*.pd_darwin .. + +# ---------------------------------------------------------- + +clean: + rm -f *.o *.pd_* so_locations diff --git a/pd/extra/bonk~/templates.txt b/pd/extra/bonk~/templates.txt new file mode 100644 index 00000000..f3528d78 --- /dev/null +++ b/pd/extra/bonk~/templates.txt @@ -0,0 +1,4 @@ + 10.47 9.65 14.95 23.77 28.32 38.84 53.21 41.20 31.25 21.70 16.48 + 6.52 13.93 27.82 58.05 24.11 35.26 35.98 37.78 22.54 13.56 10.75 + 30.45 28.86 29.42 21.94 29.92 35.70 38.49 32.01 28.19 27.38 22.10 + 66.77 46.27 28.82 25.95 22.84 20.61 20.33 14.18 6.86 8.92 7.37 |