aboutsummaryrefslogtreecommitdiff
path: root/pd
diff options
context:
space:
mode:
authorMiller Puckette <millerpuckette@users.sourceforge.net>2008-07-04 03:53:15 +0000
committerMiller Puckette <millerpuckette@users.sourceforge.net>2008-07-04 03:53:15 +0000
commit783aafff32c7e02727e73d86918fa524dfc76e22 (patch)
tree6530c7f914a406effea6b5623da4a47f6cf1c611 /pd
parentbc7cefb9a1494094846def83a29b3bed7485e330 (diff)
many bug fixes.
sigmund~ and bonk~ updates (ongoing) some new math objects svn path=/trunk/; revision=10140
Diffstat (limited to 'pd')
-rw-r--r--pd/doc/1.manual/x5.htm3
-rw-r--r--pd/extra/bonk~/bonk~-help.pd4
-rw-r--r--pd/extra/bonk~/bonk~.c1475
-rw-r--r--pd/extra/makefile32
-rw-r--r--pd/extra/sigmund~/sigmund~.c815
-rw-r--r--pd/src/CHANGELOG.txt5
-rw-r--r--pd/src/g_canvas.c16
-rw-r--r--pd/src/m_class.c9
-rw-r--r--pd/src/m_pd.h2
-rw-r--r--pd/src/makefile.in2
-rw-r--r--pd/src/makefile.nt3
-rw-r--r--pd/src/notes.txt4
-rw-r--r--pd/src/s_audio.c8
-rw-r--r--pd/src/s_loader.c20
-rw-r--r--pd/src/s_main.c8
-rw-r--r--pd/src/s_midi_oss.c4
-rw-r--r--pd/src/s_stuff.h2
-rw-r--r--pd/src/u_pdreceive.c118
18 files changed, 1572 insertions, 958 deletions
diff --git a/pd/doc/1.manual/x5.htm b/pd/doc/1.manual/x5.htm
index 53d6b1d9..634e0eeb 100644
--- a/pd/doc/1.manual/x5.htm
+++ b/pd/doc/1.manual/x5.htm
@@ -27,7 +27,8 @@
<P> Bug fix in pipe object: if sending a list to pipe, it didn't update the
delay time when asked to.
-<P>
+<P> Binbufs fixed to handle arbitrary length messages. (This fixed a problem
+reloading data structures with huge arrays).
<P> ------------------ 0.41-3,4 ---------------------------
diff --git a/pd/extra/bonk~/bonk~-help.pd b/pd/extra/bonk~/bonk~-help.pd
index 915d543b..d66ed5b0 100644
--- a/pd/extra/bonk~/bonk~-help.pd
+++ b/pd/extra/bonk~/bonk~-help.pd
@@ -1,4 +1,4 @@
-#N canvas 193 43 967 599 10;
+#N canvas 304 143 967 599 10;
#X obj 370 524 spigot;
#X msg 442 397 bang;
#X obj 429 488 bonk~;
@@ -131,6 +131,8 @@ set" in memory.;
the high one and then fall to the low one to make an attack. The unit
is the sum of the proportional growth in the 11 filter bands. Proportional
growth is essentially the logarithmic time derivative.;
+#X text 238 27 (NOTE: this documentation does not yet describe new
+features for Pd 0.42).;
#X connect 0 0 40 0;
#X connect 1 0 2 0;
#X connect 2 0 8 0;
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 */
diff --git a/pd/extra/makefile b/pd/extra/makefile
index 944475a1..9b2dd931 100644
--- a/pd/extra/makefile
+++ b/pd/extra/makefile
@@ -6,7 +6,7 @@ pd_nt: $(NAME).dll
.SUFFIXES: .dll
-PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
+PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo -D_CRT_SECURE_NO_WARNINGS
# VC="C:\Program Files\Microsoft Visual Studio\Vc98"
VC = "C:\Program Files\Microsoft Visual Studio 9.0\VC"
VSTK = "C:\Program Files\Microsoft SDKs\Windows\v6.0A"
@@ -23,36 +23,6 @@ PDNTLIB = /NODEFAULTLIB:libcmt /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel32 \
cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
link /nologo /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 $*.o
-
-# ----------------------- 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
diff --git a/pd/extra/sigmund~/sigmund~.c b/pd/extra/sigmund~/sigmund~.c
index ad98bedc..58a3858f 100644
--- a/pd/extra/sigmund~/sigmund~.c
+++ b/pd/extra/sigmund~/sigmund~.c
@@ -9,11 +9,24 @@
implement block ("-b") mode
*/
-#include "m_pd.h"
+/* From here to the first "#ifdef PD" or "#ifdef Max" should be extractable
+and usable in other contexts. The one external requirement is a real
+single-precision FFT, invoked as in the Mayer one: */
+
+#if (defined(NT) && defined(PD)) /* ignore this, it's just Microsoft nonsense */
+__declspec(dllimport) extern
+#endif
+void mayer_realfft(int npoints, float *buf);
+
+/* this routine is passed a buffer of npoints values, and returns the
+N/2+1 real parts of the DFT (frequency zero through Nyquist), followed
+by the N/2-1 imaginary points, in order of decreasing frequency. Pd 0.41,
+for example, defines this in the file d_fft_mayer.c or d_fft_fftsg.c. */
+
#include <math.h>
#include <stdio.h>
#include <string.h>
-#ifdef MSW
+#ifdef NT
#include <malloc.h>
#else
#include <alloca.h>
@@ -38,6 +51,8 @@ typedef struct peak
/********************** service routines **************************/
+/* these three are dapted from elsewhere in Pd but included here for
+cmolpeteness */
static int sigmund_ilog2(int n)
{
int ret = -1;
@@ -49,6 +64,22 @@ static int sigmund_ilog2(int n)
return (ret);
}
+static float sigmund_ftom(float f)
+{
+ return (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
+}
+
+#define LOGTEN 2.302585092994
+static float sigmund_powtodb(float f)
+{
+ if (f <= 0) return (0);
+ else
+ {
+ float val = 100 + 10./LOGTEN * log(f);
+ return (val < 0 ? 0 : val);
+ }
+}
+
/* parameters for von Hann window (change these to get Hamming if desired) */
#define W_ALPHA 0.5
#define W_BETA 0.5
@@ -171,8 +202,8 @@ static void sigmund_tweak(int npts, float *ftreal, float *ftimag,
ampoutimag = oneovern * ampcorrect *
(windreal * sinpidetune + windimag * cospidetune);
freqout = (cbin + 2*detune) * fperbin;
- if (loud > 1)
- post("amp %f, freq %f", ampout, freqout);
+ /* if (loud > 1)
+ post("amp %f, freq %f", ampout, freqout); */
peakptrs[peaki]->p_freq = freqout;
peakptrs[peaki]->p_amp = ampout;
@@ -206,15 +237,15 @@ static void sigmund_getrawpeaks(int npts, float *insamps,
float oneovern = 1.0/ (float)npts;
float fperbin = 0.5 * srate * oneovern;
int npts2 = 2*npts, i, bin;
- int count, peakcount = 0;
+ int peakcount = 0;
float *fp1, *fp2;
- float *rawpow, *rawreal, *rawimag, *maskbuf, *powbuf;
+ float *rawreal, *rawimag, *maskbuf, *powbuf;
float *bigbuf = alloca(sizeof (float ) * (2*NEGBINS + 6*npts));
int maxbin = hifreq/fperbin;
int tweak = (param3 == 0);
if (maxbin > npts - NEGBINS)
maxbin = npts - NEGBINS;
- if (loud) post("tweak %d", tweak);
+ /* if (loud) post("tweak %d", tweak); */
maskbuf = bigbuf + npts2;
powbuf = maskbuf + npts;
rawreal = powbuf + npts+NEGBINS;
@@ -231,19 +262,6 @@ static void sigmund_getrawpeaks(int npts, float *insamps,
rawreal[i] = bigbuf[i];
for (i = 1; i < npts-1; i++)
rawimag[i] = bigbuf[npts2-i];
- if (loud && npts == 1024)
- {
- float bigbuf2[2048];
- for (i = 0; i < 1024; i++)
- bigbuf2[i] = insamps[i];
- for (i = 1024; i < 2048; i++)
- bigbuf2[i] = 0;
- mayer_realfft(2048, bigbuf2);
- for (i = 1; i < 10; i++)
- post("(%10.2f, %10.2f) -> (%10.2f, %10.2f)",
- bigbuf2[i], bigbuf2[2048-i], rawreal[i], rawimag[i]);
- }
-
rawreal[-1] = rawreal[1];
rawreal[-2] = rawreal[2];
rawreal[-3] = rawreal[3];
@@ -265,7 +283,7 @@ static void sigmund_getrawpeaks(int npts, float *insamps,
{
float pow1, maxpower = 0, totalpower = 0, windreal, windimag, windpower,
detune, pidetune, sinpidetune, cospidetune, ampcorrect, ampout,
- ampoutreal, ampoutimag, freqout, freqcount1, freqcount2, powmask;
+ ampoutreal, ampoutimag, freqout, powmask;
int bestindex = -1;
for (bin = 2, fp1 = rawreal+2, fp2 = rawimag+2;
@@ -287,31 +305,27 @@ static void sigmund_getrawpeaks(int npts, float *insamps,
fp2 = rawimag+bestindex;
*power = 0.5 * totalpower *oneovern * oneovern;
powmask = maxpower * exp(-param1 * log(10.) / 10.);
- if (loud > 2)
+ /* if (loud > 2)
post("maxpower %f, powmask %f, param1 %f",
- maxpower, powmask, param1);
+ maxpower, powmask, param1); */
sigmund_remask(maxbin, bestindex, powmask, maxpower, maskbuf);
- if (loud > 1)
- post("best index %d, total power %f", bestindex, totalpower);
+ /* if (loud > 1)
+ post("best index %d, total power %f", bestindex, totalpower); */
windreal = fp1[1] - fp1[-1];
windimag = fp2[1] - fp2[-1];
windpower = windreal * windreal + windimag * windimag;
detune = ((fp1[1] * fp1[1] - fp1[-1]*fp1[-1])
+ (fp2[1] * fp2[1] - fp2[-1]*fp2[-1])) / (2 * windpower);
- if (loud > 2) post("(-1) %f %f; (1) %f %f",
- fp1[-1], fp2[-1], fp1[1], fp2[1]);
- if (loud > 2) post("peak %f %f",
- fp1[0], fp2[0]);
if (detune > 0.5)
detune = 0.5;
else if (detune < -0.5)
detune = -0.5;
- if (loud > 1)
+ /* if (loud > 1)
post("windpower %f, index %d, detune %f",
- windpower, bestindex, detune);
+ windpower, bestindex, detune); */
pidetune = PI * detune;
sinpidetune = sin(pidetune);
cospidetune = cos(pidetune);
@@ -337,8 +351,8 @@ static void sigmund_getrawpeaks(int npts, float *insamps,
}
for (i = 0; i < peakcount; i++)
{
- peakv[i].p_pit = ftom(peakv[i].p_freq);
- peakv[i].p_db = powtodb(peakv[i].p_amp);
+ peakv[i].p_pit = sigmund_ftom(peakv[i].p_freq);
+ peakv[i].p_db = sigmund_powtodb(peakv[i].p_amp);
}
*nfound = peakcount;
}
@@ -356,11 +370,9 @@ static void sigmund_getpitch(int npeak, t_peak *peakv, float *freqp,
{
float fperbin = 0.5 * srate / npts;
int npit = 48 * sigmund_ilog2(npts), i, j, k, nsalient;
- float bestbin, bestweight, sumamp, sumweight, sumfreq, sumallamp,
- freq;
+ float bestbin, bestweight, sumamp, sumweight, sumfreq, freq;
float *weights = (float *)alloca(sizeof(float) * npit);
t_peak *bigpeaks[PITCHNPEAK];
- int nbigpeaks;
if (npeak < 1)
{
freq = 0;
@@ -416,13 +428,6 @@ static void sigmund_getpitch(int npeak, t_peak *peakv, float *freqp,
}
sumweight += loudness;
}
-#if 0
- for (i = 0; i < npit; i++)
- {
- postfloat(weights[i]);
- if (!((i+1)%12)) post("");
- }
-#endif
bestbin = -1;
bestweight = -1e20;
for (i = 0; i < npit; i++)
@@ -466,7 +471,7 @@ static void sigmund_getpitch(int npeak, t_peak *peakv, float *freqp,
done:
if (!(freq >= 0 || freq <= 0))
{
- post("freq nan cancelled");
+ /* post("freq nan cancelled"); */
freq = 0;
}
*freqp = freq;
@@ -573,6 +578,7 @@ static void notefinder_doit(t_notefinder *x, float freq, float power,
x->n_hist[x->n_histphase].h_power = power;
x->n_age++;
*note = 0;
+#if 0
if (loud)
{
post("stable %d, age %d, vibmultiple %f, powerthresh %f, hifreq %f",
@@ -589,12 +595,13 @@ static void notefinder_doit(t_notefinder *x, float freq, float power,
x->n_hist[(x->n_histphase+NHISTPOINT-3)%NHISTPOINT].h_power);
for (i = 0, k = x->n_histphase; i < stableperiod; i++)
{
- post("pit %5.1f pow %f", ftom(x->n_hist[k].h_freq),
+ post("pit %5.1f pow %f", sigmund_ftom(x->n_hist[k].h_freq),
x->n_hist[k].h_power);
if (--k < 0)
k = NHISTPOINT - 1;
}
}
+#endif
/* look for shorter notes than "stableperiod" in length.
The amplitude must rise and then fall while the pitch holds
steady. */
@@ -713,7 +720,7 @@ static void notefinder_doit(t_notefinder *x, float freq, float power,
&& maxpow > powerthresh)
{
/* report new note */
- float sumf = 0, sumw = 0, thisf, thisw;
+ float sumf = 0, sumw = 0, thisw;
for (i = 0, k = x->n_histphase; i < stableperiod; i++)
{
thisw = x->n_hist[k].h_power;
@@ -730,7 +737,7 @@ static void notefinder_doit(t_notefinder *x, float freq, float power,
int k3 = x->n_histphase - i;
if (k3 < 0)
k3 += NHISTPOINT;
- startpost("%5.1f ", ftom(x->n_hist[k3].h_freq));
+ startpost("%5.1f ", sigmund_ftom(x->n_hist[k3].h_freq));
}
post("");
#endif
@@ -743,9 +750,26 @@ static void notefinder_doit(t_notefinder *x, float freq, float power,
return;
}
-/*************************** Glue for Pd ************************/
+/**************** object structure for Pd and Max. *********************/
+
+/* From here onward, the code is specific to eithr Pd, Max, or both. If
+neither "PD 'nor "MSP" is defined, none of this is compiled, so that the
+whole file can be included in other, non-PD and non-Max projects. */
+#ifdef PD
+#include "m_pd.h"
+#endif
+#ifdef MSP
+#include "ext.h"
+#include "z_dsp.h"
+#include "ext_support.h"
+#include "ext_proto.h"
+#include "ext_obex.h"
+typedef float t_floatarg;
+#define t_resizebytes(a, b, c) t_resizebytes((char *)(a), (b), (c))
+#endif
+
+#if (defined(PD) || defined (MSP))
-static t_class *sigmund_class;
#define NHIST 100
#define MODE_STREAM 1
@@ -773,17 +797,29 @@ static t_class *sigmund_class;
typedef struct _varout
{
+#ifdef PD
t_outlet *v_outlet;
+#endif /* PD */
+#ifdef MSP
+ void *v_outlet;
+#endif /* MSP */
int v_what;
} t_varout;
typedef struct _sigmund
{
+#ifdef PD
t_object x_obj;
- t_varout *x_varoutv;
- int x_nvarout;
t_clock *x_clock;
float x_f; /* for main signal inlet */
+#endif /* PD */
+#ifdef MSP
+ t_pxobject x_obj;
+ void *obex;
+ void *x_clock;
+#endif /* MSP */
+ t_varout *x_varoutv;
+ int x_nvarout;
float x_sr; /* sample rate */
int x_mode; /* MODE_STREAM, etc. */
int x_npts; /* number of points in analysis window */
@@ -798,31 +834,19 @@ typedef struct _sigmund
float x_stabletime; /* period of stability needed for note */
float x_growth; /* growth to set off a new note */
float x_minpower; /* minimum power, in DB, for a note */
- float x_param1;
+ float x_param1; /* three parameters for temporary use */
float x_param2;
float x_param3;
- t_notefinder x_notefinder;
- t_peak *x_trackv;
- int x_ntrack;
- unsigned int x_dopitch:1;
+ t_notefinder x_notefinder; /* note parsing state */
+ t_peak *x_trackv; /* peak tracking state */
+ int x_ntrack; /* number of peaks tracked */
+ unsigned int x_dopitch:1; /* which things to calculate */
unsigned int x_donote:1;
unsigned int x_dotracks:1;
} t_sigmund;
-static void sigmund_clock(t_sigmund *x);
-static void sigmund_clear(t_sigmund *x);
-static void sigmund_npts(t_sigmund *x, t_floatarg f);
-static void sigmund_hop(t_sigmund *x, t_floatarg f);
-static void sigmund_npeak(t_sigmund *x, t_floatarg f);
-static void sigmund_maxfreq(t_sigmund *x, t_floatarg f);
-static void sigmund_vibrato(t_sigmund *x, t_floatarg f);
-static void sigmund_stabletime(t_sigmund *x, t_floatarg f);
-static void sigmund_growth(t_sigmund *x, t_floatarg f);
-static void sigmund_minpower(t_sigmund *x, t_floatarg f);
-
-static void *sigmund_new(t_symbol *s, int argc, t_atom *argv)
+static void sigmund_preinit(t_sigmund *x)
{
- t_sigmund *x = (t_sigmund *)pd_new(sigmund_class);
x->x_npts = NPOINTS_DEF;
x->x_param1 = 0;
x->x_param2 = 0.6;
@@ -843,6 +867,238 @@ static void *sigmund_new(t_symbol *s, int argc, t_atom *argv)
x->x_ntrack = 0;
x->x_dopitch = x->x_donote = x->x_dotracks = 0;
x->x_inbuf = 0;
+}
+
+static void sigmund_npts(t_sigmund *x, t_floatarg f)
+{
+ int nwas = x->x_npts, npts = f;
+ /* check parameter ranges */
+ if (npts < NPOINTS_MIN)
+ post("sigmund~: minimum points %d", NPOINTS_MIN),
+ npts = NPOINTS_MIN;
+ if (npts != (1 << sigmund_ilog2(npts)))
+ post("sigmund~: adjusting analysis size to %d points",
+ (npts = (1 << sigmund_ilog2(npts))));
+ if (npts != nwas)
+ x->x_countdown = x->x_infill = 0;
+ if (x->x_mode == MODE_STREAM)
+ {
+ if (x->x_inbuf)
+ x->x_inbuf = (t_sample *)t_resizebytes(x->x_inbuf,
+ sizeof(*x->x_inbuf) * nwas, sizeof(*x->x_inbuf) * npts);
+ else x->x_inbuf = (t_sample *)getbytes(sizeof(*x->x_inbuf) * npts);
+ }
+ else x->x_inbuf = 0;
+ x->x_npts = npts;
+}
+
+static void sigmund_hop(t_sigmund *x, t_floatarg f)
+{
+ x->x_hop = f;
+ /* check parameter ranges */
+ if (x->x_hop != (1 << sigmund_ilog2(x->x_hop)))
+ post("sigmund~: adjusting analysis size to %d points",
+ (x->x_hop = (1 << sigmund_ilog2(x->x_hop))));
+}
+
+static void sigmund_npeak(t_sigmund *x, t_floatarg f)
+{
+ if (f < 1)
+ f = 1;
+ x->x_npeak = f;
+}
+
+static void sigmund_maxfreq(t_sigmund *x, t_floatarg f)
+{
+ x->x_maxfreq = f;
+}
+
+static void sigmund_vibrato(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_vibrato = f;
+}
+
+static void sigmund_stabletime(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_stabletime = f;
+}
+
+static void sigmund_growth(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_growth = f;
+}
+
+static void sigmund_minpower(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_minpower = f;
+}
+
+static void sigmund_doit(t_sigmund *x, int npts, float *arraypoints,
+ int loud, float srate)
+{
+ t_peak *peakv = (t_peak *)alloca(sizeof(t_peak) * x->x_npeak);
+ int nfound, i, cnt;
+ float freq = 0, power, note = 0;
+ sigmund_getrawpeaks(npts, arraypoints, x->x_npeak, peakv,
+ &nfound, &power, srate, loud, x->x_param1, x->x_param2, x->x_param3,
+ x->x_maxfreq);
+ if (x->x_dopitch)
+ sigmund_getpitch(nfound, peakv, &freq, npts, srate, loud);
+ if (x->x_donote)
+ notefinder_doit(&x->x_notefinder, freq, power, &note, x->x_vibrato,
+ x->x_stabletime * 0.001f * x->x_sr / (float)x->x_hop,
+ exp(LOG10*0.1*(x->x_minpower - 100)), x->x_growth, loud);
+ if (x->x_dotracks)
+ sigmund_peaktrack(nfound, peakv, x->x_ntrack, x->x_trackv, loud);
+
+ for (cnt = x->x_nvarout; cnt--;)
+ {
+ t_varout *v = &x->x_varoutv[cnt];
+ switch (v->v_what)
+ {
+ case OUT_PITCH:
+ outlet_float(v->v_outlet, sigmund_ftom(freq));
+ break;
+ case OUT_ENV:
+ outlet_float(v->v_outlet, sigmund_powtodb(power));
+ break;
+ case OUT_NOTE:
+ if (note > 0)
+ outlet_float(v->v_outlet, sigmund_ftom(note));
+ break;
+ case OUT_PEAKS:
+ for (i = 0; i < nfound; i++)
+ {
+ t_atom at[5];
+ SETFLOAT(at, (float)i);
+ SETFLOAT(at+1, peakv[i].p_freq);
+ SETFLOAT(at+2, 2*peakv[i].p_amp);
+ SETFLOAT(at+3, 2*peakv[i].p_ampreal);
+ SETFLOAT(at+4, 2*peakv[i].p_ampimag);
+ outlet_list(v->v_outlet, 0, 5, at);
+ }
+ break;
+ case OUT_TRACKS:
+ for (i = 0; i < x->x_ntrack; i++)
+ {
+ t_atom at[4];
+ SETFLOAT(at, (float)i);
+ SETFLOAT(at+1, x->x_trackv[i].p_freq);
+ SETFLOAT(at+2, 2*x->x_trackv[i].p_amp);
+ SETFLOAT(at+3, x->x_trackv[i].p_tmp);
+ outlet_list(v->v_outlet, 0, 4, at);
+ }
+ break;
+ }
+ }
+}
+
+static void sigmund_tick(t_sigmund *x)
+{
+ if (x->x_infill == x->x_npts)
+ {
+ sigmund_doit(x, x->x_npts, x->x_inbuf, x->x_loud, x->x_sr);
+ if (x->x_hop >= x->x_npts)
+ {
+ x->x_infill = 0;
+ x->x_countdown = x->x_hop - x->x_npts;
+ }
+ else
+ {
+ memmove(x->x_inbuf, x->x_inbuf + x->x_hop,
+ (x->x_infill = x->x_npts - x->x_hop) * sizeof(*x->x_inbuf));
+ x->x_countdown = 0;
+ }
+ x->x_loud = 0;
+ }
+}
+
+static t_int *sigmund_perform(t_int *w)
+{
+ t_sigmund *x = (t_sigmund *)(w[1]);
+ float *in = (float *)(w[2]);
+ int n = (int)(w[3]);
+
+ if (x->x_hop % n)
+ return (w+4);
+ if (x->x_countdown > 0)
+ x->x_countdown -= n;
+ else if (x->x_infill != x->x_npts)
+ {
+ int j;
+ float *fp = x->x_inbuf + x->x_infill;
+ for (j = 0; j < n; j++)
+ *fp++ = *in++;
+ x->x_infill += n;
+ if (x->x_infill == x->x_npts)
+ clock_delay(x->x_clock, 0);
+ }
+ return (w+4);
+}
+
+static void sigmund_dsp(t_sigmund *x, t_signal **sp)
+{
+ if (x->x_mode == MODE_STREAM)
+ {
+ if (x->x_hop % sp[0]->s_n)
+ post("sigmund: adjusting hop size to %d",
+ (x->x_hop = sp[0]->s_n * (x->x_hop / sp[0]->s_n)));
+ x->x_sr = sp[0]->s_sr;
+ dsp_add(sigmund_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigmund_print(t_sigmund *x)
+{
+ post("sigmund~ settings:");
+ post("npts %d", (int)x->x_npts);
+ post("hop %d", (int)x->x_hop);
+ post("npeak %d", (int)x->x_npeak);
+ post("maxfreq %g", x->x_maxfreq);
+ post("vibrato %g", x->x_vibrato);
+ post("stabletime %g", x->x_stabletime);
+ post("growth %g", x->x_growth);
+ post("minpower %g", x->x_minpower);
+}
+
+static void sigmund_free(t_sigmund *x)
+{
+ if (x->x_inbuf)
+ freebytes(x->x_inbuf, x->x_npts * sizeof(*x->x_inbuf));
+ if (x->x_trackv)
+ freebytes(x->x_trackv, x->x_ntrack * sizeof(*x->x_trackv));
+ clock_free(x->x_clock);
+}
+
+#endif /* PD or MSP */
+/*************************** Glue for Pd ************************/
+#ifdef PD
+
+static t_class *sigmund_class;
+
+static void sigmund_tick(t_sigmund *x);
+static void sigmund_clear(t_sigmund *x);
+static void sigmund_npts(t_sigmund *x, t_floatarg f);
+static void sigmund_hop(t_sigmund *x, t_floatarg f);
+static void sigmund_npeak(t_sigmund *x, t_floatarg f);
+static void sigmund_maxfreq(t_sigmund *x, t_floatarg f);
+static void sigmund_vibrato(t_sigmund *x, t_floatarg f);
+static void sigmund_stabletime(t_sigmund *x, t_floatarg f);
+static void sigmund_growth(t_sigmund *x, t_floatarg f);
+static void sigmund_minpower(t_sigmund *x, t_floatarg f);
+
+static void *sigmund_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_sigmund *x = (t_sigmund *)pd_new(sigmund_class);
+ sigmund_preinit(x);
while (argc > 0)
{
@@ -986,7 +1242,7 @@ static void *sigmund_new(t_symbol *s, int argc, t_atom *argv)
x->x_ntrack = x->x_npeak;
x->x_trackv = (t_peak *)getbytes(x->x_ntrack * sizeof(*x->x_trackv));
}
- x->x_clock = clock_new(&x->x_obj.ob_pd, (t_method)sigmund_clock);
+ x->x_clock = clock_new(&x->x_obj.ob_pd, (t_method)sigmund_tick);
x->x_infill = 0;
x->x_countdown = 0;
@@ -996,66 +1252,6 @@ static void *sigmund_new(t_symbol *s, int argc, t_atom *argv)
return (x);
}
-static void sigmund_doit(t_sigmund *x, int npts, float *arraypoints,
- int loud, float srate)
-{
- t_peak *peakv = (t_peak *)alloca(sizeof(t_peak) * x->x_npeak);
- int nfound, i, cnt;
- float freq = 0, power, note = 0;
- sigmund_getrawpeaks(npts, arraypoints, x->x_npeak, peakv,
- &nfound, &power, srate, loud, x->x_param1, x->x_param2, x->x_param3,
- x->x_maxfreq);
- if (x->x_dopitch)
- sigmund_getpitch(nfound, peakv, &freq, npts, srate, loud);
- if (x->x_donote)
- notefinder_doit(&x->x_notefinder, freq, power, &note, x->x_vibrato,
- x->x_stabletime * 0.001f * x->x_sr / (float)x->x_hop,
- exp(LOG10*0.1*(x->x_minpower - 100)), x->x_growth, loud);
- if (x->x_dotracks)
- sigmund_peaktrack(nfound, peakv, x->x_ntrack, x->x_trackv, loud);
-
- for (cnt = x->x_nvarout; cnt--;)
- {
- t_varout *v = &x->x_varoutv[cnt];
- switch (v->v_what)
- {
- case OUT_PITCH:
- outlet_float(v->v_outlet, ftom(freq));
- break;
- case OUT_ENV:
- outlet_float(v->v_outlet, powtodb(power));
- break;
- case OUT_NOTE:
- if (note > 0)
- outlet_float(v->v_outlet, ftom(note));
- break;
- case OUT_PEAKS:
- for (i = 0; i < nfound; i++)
- {
- t_atom at[5];
- SETFLOAT(at, (float)i);
- SETFLOAT(at+1, peakv[i].p_freq);
- SETFLOAT(at+2, 2*peakv[i].p_amp);
- SETFLOAT(at+3, 2*peakv[i].p_ampreal);
- SETFLOAT(at+4, 2*peakv[i].p_ampimag);
- outlet_list(v->v_outlet, &s_list, 5, at);
- }
- break;
- case OUT_TRACKS:
- for (i = 0; i < x->x_ntrack; i++)
- {
- t_atom at[4];
- SETFLOAT(at, (float)i);
- SETFLOAT(at+1, x->x_trackv[i].p_freq);
- SETFLOAT(at+2, 2*x->x_trackv[i].p_amp);
- SETFLOAT(at+3, x->x_trackv[i].p_tmp);
- outlet_list(v->v_outlet, &s_list, 4, at);
- }
- break;
- }
- }
-}
-
static void sigmund_list(t_sigmund *x, t_symbol *s, int argc, t_atom *argv)
{
t_symbol *syminput = atom_getsymbolarg(0, argc, argv);
@@ -1124,160 +1320,11 @@ static void sigmund_param3(t_sigmund *x, t_floatarg f)
x->x_param3 = f;
}
-static void sigmund_npts(t_sigmund *x, t_floatarg f)
-{
- int nwas = x->x_npts, npts = f;
- /* check parameter ranges */
- if (npts < NPOINTS_MIN)
- post("sigmund~: minimum points %d", NPOINTS_MIN),
- npts = NPOINTS_MIN;
- if (npts != (1 << sigmund_ilog2(npts)))
- post("sigmund~: adjusting analysis size to %d points",
- (npts = (1 << sigmund_ilog2(npts))));
- if (npts != nwas)
- x->x_countdown = x->x_infill = 0;
- if (x->x_mode == MODE_STREAM)
- {
- if (x->x_inbuf)
- x->x_inbuf = resizebytes(x->x_inbuf,
- sizeof(*x->x_inbuf) * nwas, sizeof(*x->x_inbuf) * npts);
- else x->x_inbuf = getbytes(sizeof(*x->x_inbuf) * npts);
- }
- else x->x_inbuf = 0;
- x->x_npts = npts;
-}
-
-static void sigmund_hop(t_sigmund *x, t_floatarg f)
-{
- x->x_hop = f;
- /* check parameter ranges */
- if (x->x_hop != (1 << sigmund_ilog2(x->x_hop)))
- post("sigmund~: adjusting analysis size to %d points",
- (x->x_hop = (1 << sigmund_ilog2(x->x_hop))));
-}
-
-static void sigmund_npeak(t_sigmund *x, t_floatarg f)
-{
- if (f < 1)
- f = 1;
- x->x_npeak = f;
-}
-
-static void sigmund_maxfreq(t_sigmund *x, t_floatarg f)
-{
- x->x_maxfreq = f;
-}
-
-static void sigmund_vibrato(t_sigmund *x, t_floatarg f)
-{
- if (f < 0)
- f = 0;
- x->x_vibrato = f;
-}
-
-static void sigmund_stabletime(t_sigmund *x, t_floatarg f)
-{
- if (f < 0)
- f = 0;
- x->x_stabletime = f;
-}
-
-static void sigmund_growth(t_sigmund *x, t_floatarg f)
-{
- if (f < 0)
- f = 0;
- x->x_growth = f;
-}
-
-static void sigmund_minpower(t_sigmund *x, t_floatarg f)
-{
- if (f < 0)
- f = 0;
- x->x_minpower = f;
-}
-
-static void sigmund_print(t_sigmund *x)
-{
- post("sigmund~ settings:");
- post("npts %d", (int)x->x_npts);
- post("hop %d", (int)x->x_hop);
- post("npeak %d", (int)x->x_npeak);
- post("maxfreq %g", x->x_maxfreq);
- post("vibrato %g", x->x_vibrato);
- post("stabletime %g", x->x_stabletime);
- post("growth %g", x->x_growth);
- post("minpower %g", x->x_minpower);
-}
-
static void sigmund_printnext(t_sigmund *x, t_float f)
{
x->x_loud = f;
}
-static void sigmund_clock(t_sigmund *x)
-{
- if (x->x_infill == x->x_npts)
- {
- sigmund_doit(x, x->x_npts, x->x_inbuf, x->x_loud, x->x_sr);
- if (x->x_hop >= x->x_npts)
- {
- x->x_infill = 0;
- x->x_countdown = x->x_hop - x->x_npts;
- }
- else
- {
- memmove(x->x_inbuf, x->x_inbuf + x->x_hop,
- (x->x_infill = x->x_npts - x->x_hop) * sizeof(*x->x_inbuf));
- x->x_countdown = 0;
- }
- x->x_loud = 0;
- }
-}
-
-static t_int *sigmund_perform(t_int *w)
-{
- t_sigmund *x = (t_sigmund *)(w[1]);
- float *in = (float *)(w[2]);
- int n = (int)(w[3]);
-
- if (x->x_hop % n)
- return (w+4);
- if (x->x_countdown > 0)
- x->x_countdown -= n;
- else if (x->x_infill != x->x_npts)
- {
- int i, j;
- float *fp = x->x_inbuf + x->x_infill;
- for (j = 0; j < n; j++)
- *fp++ = *in++;
- x->x_infill += n;
- if (x->x_infill == x->x_npts)
- clock_delay(x->x_clock, 0);
- }
- return (w+4);
-}
-
-static void sigmund_dsp(t_sigmund *x, t_signal **sp)
-{
- if (x->x_mode == MODE_STREAM)
- {
- if (x->x_hop % sp[0]->s_n)
- post("sigmund: adjusting hop size to %d",
- (x->x_hop = sp[0]->s_n * (x->x_hop / sp[0]->s_n)));
- x->x_sr = sp[0]->s_sr;
- dsp_add(sigmund_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
- }
-}
-
-static void sigmund_free(t_sigmund *x)
-{
- if (x->x_inbuf)
- freebytes(x->x_inbuf, x->x_npts * sizeof(*x->x_inbuf));
- if (x->x_trackv)
- freebytes(x->x_trackv, x->x_ntrack * sizeof(*x->x_trackv));
- clock_free(x->x_clock);
-}
-
void sigmund_tilde_setup(void)
{
sigmund_class = class_new(gensym("sigmund~"), (t_newmethod)sigmund_new,
@@ -1311,6 +1358,214 @@ void sigmund_tilde_setup(void)
gensym("print"), 0);
class_addmethod(sigmund_class, (t_method)sigmund_printnext,
gensym("printnext"), A_FLOAT, 0);
- post("sigmund version 0.03");
+ post("sigmund~ version 0.04");
}
+#endif /* PD */
+
+/************************ Max/MSP glue **********************************/
+
+/* -------------------------- MSP glue ------------------------- */
+#ifdef MSP
+static void *sigmund_class;
+
+static void *sigmund_new(t_symbol *s, long ac, t_atom *av)
+{
+ t_sigmund *x;
+ t_varout *g;
+ int i, j;
+ if (!(x = (t_sigmund *)object_alloc(sigmund_class)))
+ return (0);
+ sigmund_preinit(x);
+ attr_args_process(x, ac, av);
+ dsp_setup((t_pxobject *)x, 1);
+ object_obex_store(x, gensym("dumpout"), outlet_new(x, NULL));
+
+ for (i = 0; i < ac; i++)
+ if (av[i].a_type == A_SYM)
+ {
+ char *s = av[i].a_w.w_sym->s_name;
+ if (!strcmp(s, "pitch"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_what = OUT_PITCH;
+ x->x_nvarout = n2;
+ x->x_dopitch = 1;
+ }
+ else if (!strcmp(s, "env"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_what = OUT_ENV;
+ x->x_nvarout = n2;
+ }
+ else if (!strcmp(s, "note") || !strcmp(s, "notes"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_what = OUT_NOTE;
+ x->x_nvarout = n2;
+ x->x_dopitch = x->x_donote = 1;
+ }
+ else if (!strcmp(s, "peaks"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_what = OUT_PEAKS;
+ x->x_nvarout = n2;
+ }
+ else if (!strcmp(s, "tracks"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_what = OUT_TRACKS;
+ x->x_nvarout = n2;
+ x->x_dotracks = 1;
+ }
+ else if (s[0] != '@')
+ post("sigmund: ignoring unknown argument '%s'" ,s);
+ }
+ if (!x->x_nvarout)
+ {
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ 0, 2*sizeof(t_varout));
+ x->x_varoutv[0].v_what = OUT_PITCH;
+ x->x_varoutv[1].v_what = OUT_ENV;
+ x->x_nvarout = 2;
+ x->x_dopitch = 1;
+ }
+ for (j = 0, g = x->x_varoutv + x->x_nvarout-1; j < x->x_nvarout; j++, g--)
+ g->v_outlet = ((g->v_what == OUT_PITCH || g->v_what == OUT_ENV ||
+ g->v_what == OUT_NOTE) ?
+ floatout((t_object *)x) : listout((t_object *)x));
+ if (x->x_dotracks)
+ {
+ x->x_ntrack = x->x_npeak;
+ x->x_trackv = (t_peak *)getbytes(x->x_ntrack * sizeof(*x->x_trackv));
+ }
+ x->x_clock = clock_new(x, (method)sigmund_tick);
+ x->x_infill = 0;
+ x->x_countdown = 0;
+ sigmund_npts(x, x->x_npts);
+ notefinder_init(&x->x_notefinder);
+ return (x);
+}
+
+/* Attribute setters. */
+void sigmund_npts_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_npts(x, atom_getfloat(av));
+}
+
+void sigmund_hop_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_hop(x, atom_getfloat(av));
+}
+
+void sigmund_npeak_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_npeak(x, atom_getfloat(av));
+}
+
+void sigmund_maxfreq_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_maxfreq(x, atom_getfloat(av));
+}
+
+void sigmund_vibrato_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_vibrato(x, atom_getfloat(av));
+}
+
+void sigmund_stabletime_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_stabletime(x, atom_getfloat(av));
+}
+
+void sigmund_growth_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_growth(x, atom_getfloat(av));
+}
+
+void sigmund_minpower_set(t_sigmund *x, void *attr, long ac, t_atom *av)
+{
+ if (ac && av)
+ sigmund_minpower(x, atom_getfloat(av));
+}
+
+/* end attr setters */
+
+void sigmund_assist(t_sigmund *x, void *b, long m, long a, char *s)
+{
+}
+
+int main()
+{
+ t_class *c;
+ long attrflags = 0;
+ t_symbol *sym_long = gensym("long"), *sym_float32 = gensym("float32");
+
+ c = class_new("sigmund~", (method)sigmund_new,
+ (method)sigmund_free, sizeof(t_sigmund), (method)0L, A_GIMME, 0);
+
+ class_obexoffset_set(c, calcoffset(t_sigmund, obex));
+
+ class_addattr(c, attr_offset_new("npts", sym_long, attrflags,
+ (method)0L, (method)sigmund_npts_set,
+ calcoffset(t_sigmund, x_npts)));
+ class_addattr(c ,attr_offset_new("hop", sym_long, attrflags,
+ (method)0L, (method)sigmund_hop_set,
+ calcoffset(t_sigmund, x_hop)));
+ class_addattr(c ,attr_offset_new("maxfreq", sym_float32, attrflags,
+ (method)0L, (method)sigmund_maxfreq_set,
+ calcoffset(t_sigmund, x_maxfreq)));
+ class_addattr(c ,attr_offset_new("npeak", sym_long, attrflags,
+ (method)0L, (method)sigmund_npeak_set,
+ calcoffset(t_sigmund, x_npeak)));
+ class_addattr(c ,attr_offset_new("vibrato", sym_float32, attrflags,
+ (method)0L, (method)sigmund_vibrato_set,
+ calcoffset(t_sigmund, x_vibrato)));
+ class_addattr(c ,attr_offset_new("stabletime", sym_float32, attrflags,
+ (method)0L, (method)sigmund_stabletime_set,
+ calcoffset(t_sigmund, x_stabletime)));
+ class_addattr(c ,attr_offset_new("growth", sym_float32, attrflags,
+ (method)0L, (method)sigmund_growth_set,
+ calcoffset(t_sigmund, x_growth)));
+ class_addattr(c ,attr_offset_new("minpower", sym_float32, attrflags,
+ (method)0L, (method)sigmund_minpower_set,
+ calcoffset(t_sigmund, x_minpower)));
+
+ class_addmethod(c, (method)sigmund_dsp, "dsp", A_CANT, 0);
+ class_addmethod(c, (method)sigmund_print, "print", 0);
+ class_addmethod(c, (method)sigmund_print, "printnext", A_DEFFLOAT, 0);
+ class_addmethod(c, (method)sigmund_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);
+ sigmund_class = c;
+
+ post("sigmund~ v0.04");
+ return (0);
+}
+
+
+#endif /* MSP */
+
+
diff --git a/pd/src/CHANGELOG.txt b/pd/src/CHANGELOG.txt
index 9620a7fa..6d789171 100644
--- a/pd/src/CHANGELOG.txt
+++ b/pd/src/CHANGELOG.txt
@@ -2,6 +2,11 @@ This file describes implementation and API changes; stuff more visible to the
user appears in the "release notes" instead. See the bottom of this file
for original notes on source stype and organization.
+0.42.0
+
+changed definition of t_float, t_sample, t_floatarg so that they can be
+set via #defines (PD_FLOATTYPE, etc).
+
0.41.0
add support for callback-based audio I/O
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index c6481d28..3220360f 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -1338,7 +1338,7 @@ void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b)
}
}
-static void canvas_completepath(char *from, char *to)
+static void canvas_completepath(char *from, char *to, int bufsize)
{
if (sys_isabsolutepath(from))
{
@@ -1346,12 +1346,12 @@ static void canvas_completepath(char *from, char *to)
}
else
{ // if not absolute path, append Pd lib dir
- strncpy(to, sys_libdir->s_name, FILENAME_MAX-4);
- to[FILENAME_MAX-3] = '\0';
+ strncpy(to, sys_libdir->s_name, bufsize-4);
+ to[bufsize-3] = '\0';
strcat(to, "/");
}
- strncat(to, from, FILENAME_MAX-strlen(to));
- to[FILENAME_MAX-1] = '\0';
+ strncat(to, from, bufsize-strlen(to));
+ to[bufsize-1] = '\0';
}
static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
@@ -1375,7 +1375,8 @@ static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
}
else if ((argc > i+1) && !strcmp(flag, "-stdpath"))
{
- canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name, strbuf);
+ canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name,
+ strbuf, MAXPDSTRING);
e->ce_path = namelist_append(e->ce_path, strbuf, 0);
i++;
}
@@ -1386,7 +1387,8 @@ static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
}
else if ((argc > i+1) && !strcmp(flag, "-stdlib"))
{
- canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name, strbuf);
+ canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name,
+ strbuf, MAXPDSTRING);
sys_load_lib(0, strbuf);
i++;
}
diff --git a/pd/src/m_class.c b/pd/src/m_class.c
index aa44022d..cd4fbb1c 100644
--- a/pd/src/m_class.c
+++ b/pd/src/m_class.c
@@ -769,19 +769,22 @@ badarg:
s->s_name, c->c_name->s_name);
}
+ /* convenience routine giving a stdarg interface to typedmess(). Only
+ ten args supported; it seems unlikely anyone will need more since
+ longer messages are likely to be programmatically generated anyway. */
void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...)
{
va_list ap;
- t_atom arg[MAXPDARG], *at =arg;
+ t_atom arg[10], *at = arg;
int nargs = 0;
char *fp = fmt;
va_start(ap, fmt);
while (1)
{
- if (nargs > MAXPDARG)
+ if (nargs >= 10)
{
- pd_error(x, "pd_vmess: only %d allowed", MAXPDARG);
+ pd_error(x, "pd_vmess: only 10 allowed");
break;
}
switch(*fp++)
diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h
index f48a13b9..da6a7c66 100644
--- a/pd/src/m_pd.h
+++ b/pd/src/m_pd.h
@@ -11,7 +11,7 @@ extern "C" {
#define PD_MAJOR_VERSION 0
#define PD_MINOR_VERSION 42
#define PD_BUGFIX_VERSION 0
-#define PD_TEST_VERSION "test1"
+#define PD_TEST_VERSION "test3"
/* old name for "MSW" flag -- we have to take it for the sake of many old
"nmakefiles" for externs, which will define NT and not MSW */
diff --git a/pd/src/makefile.in b/pd/src/makefile.in
index b4ad8217..ab6209ff 100644
--- a/pd/src/makefile.in
+++ b/pd/src/makefile.in
@@ -158,6 +158,8 @@ externs:
make -C ../extra/lrshift~ @EXTERNTARGET@
make -C ../extra/pique @EXTERNTARGET@
make -C ../extra/sigmund~ @EXTERNTARGET@
+ make -C ../extra/pd~ @EXTERNTARGET@
+ make -C ../extra/stdout @EXTERNTARGET@
BINARYMODE=@binarymode@
diff --git a/pd/src/makefile.nt b/pd/src/makefile.nt
index addad543..1f2822ba 100644
--- a/pd/src/makefile.nt
+++ b/pd/src/makefile.nt
@@ -18,8 +18,6 @@ LIB = /NODEFAULTLIB:libcmt /NODEFAULTLIB:oldnames /NODEFAULTLIB:libc \
$(LDIR)\setupapi.lib ..\bin\pthreadVC.lib \
$(LD2)\libcmt.lib $(LD2)\oldnames.lib
-# \
-
GLIB = $(LIB) ..\bin\tcl84.lib ..\bin\tk84.lib
CFLAGS = /nologo /W3 /DMSW /DNT /DPD /DPD_INTERNAL /DWIN32 /DWINDOWS /Ox \
-DPA_LITTLE_ENDIAN -DUSEAPI_MMIO -DUSEAPI_PORTAUDIO -D__i386__ -DPA19
@@ -58,7 +56,6 @@ SRCPA = $(PASRC)/common/pa_stream.c \
$(PASRC)/os/win/pa_win_hostapis.c \
$(PASRC)/os/win/pa_win_util.c \
$(PASRC)/hostapi/wmme/pa_win_wmme.c
-# $(PADIR)/pa_win_wdmks/pa_win_wdmks.c
SRCASIO = $(PADIR)/pa_asio/pa_asio.cpp
diff --git a/pd/src/notes.txt b/pd/src/notes.txt
index 8f94137f..e5c85dca 100644
--- a/pd/src/notes.txt
+++ b/pd/src/notes.txt
@@ -1,4 +1,6 @@
---------------- dolist --------------------
+done:
+
test:
compile on various versions of linux
windows:
@@ -115,6 +117,8 @@ sublists should display on parent if desired? (new drawing instruction)
test and debug list elements of templates
sublists seem not to handle canvas allocation right (get.pd->pointer.pd bug)
append doesn't do symbols yet.
+-n flag for drawnumbers
+non-clickable arrays (plus arrays that respond more easily than default)
more features:
diff --git a/pd/src/s_audio.c b/pd/src/s_audio.c
index f56ac0d6..9f4e2051 100644
--- a/pd/src/s_audio.c
+++ b/pd/src/s_audio.c
@@ -192,10 +192,6 @@ void sys_set_audio_settings(int naudioindev, int *audioindev, int nchindev,
int indevs = 0, outdevs = 0, canmulti = 0, cancallback = 0;
audio_getdevs(indevlist, &indevs, outdevlist, &outdevs, &canmulti,
&cancallback, MAXNDEV, DEVDESCSIZE);
- if (sys_externalschedlib)
- {
- return;
- }
if (rate < 1)
rate = DEFAULTSRATE;
@@ -426,7 +422,9 @@ void sys_reopen_audio( void)
chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate);
else
#endif
- post("unknown audio API specified");
+ if (sys_audioapi == API_NONE)
+ ;
+ else post("unknown audio API specified");
if (outcome) /* failed */
{
audio_state = 0;
diff --git a/pd/src/s_loader.c b/pd/src/s_loader.c
index aac50898..bc637dce 100644
--- a/pd/src/s_loader.c
+++ b/pd/src/s_loader.c
@@ -8,6 +8,8 @@
#ifdef UNISTD
#include <stdlib.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#endif
#ifdef MSW
#include <io.h>
@@ -247,7 +249,7 @@ int sys_run_scheduler(const char *externalschedlibname,
typedef int (*t_externalschedlibmain)(const char *);
t_externalschedlibmain externalmainfunc;
char filename[MAXPDSTRING];
- snprintf(filename, sizeof(filename), "%s.%s", externalschedlibname,
+ snprintf(filename, sizeof(filename), "%s%s", externalschedlibname,
sys_dllextent);
sys_bashfilename(filename, filename);
#ifdef MSW
@@ -256,18 +258,28 @@ int sys_run_scheduler(const char *externalschedlibname,
if (!ntdll)
{
post("%s: couldn't load external scheduler lib ", filename);
- return (0);
+ return (1);
}
externalmainfunc =
(t_externalschedlibmain)GetProcAddress(ntdll, "main");
}
#else
{
- void *dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ void *dlobj;
+ struct stat statbuf;
+ /* if first-choice file extent can't 'stat', go for second */
+ if (stat(filename, &statbuf) < 0)
+ {
+ snprintf(filename, sizeof(filename), "%s%s", externalschedlibname,
+ sys_dllextent2);
+ sys_bashfilename(filename, filename);
+ }
+ dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
if (!dlobj)
{
post("%s: %s", filename, dlerror());
- return (0);
+ fprintf(stderr, "dlopen failed for %s: %s\n", filename, dlerror());
+ return (1);
}
externalmainfunc = (t_externalschedlibmain)dlsym(dlobj,
"pd_extern_sched");
diff --git a/pd/src/s_main.c b/pd/src/s_main.c
index dcc3bed9..0bc5a191 100644
--- a/pd/src/s_main.c
+++ b/pd/src/s_main.c
@@ -50,7 +50,7 @@ int sys_nosleep = 0; /* skip all "sleep" calls and spin instead */
char *sys_guicmd;
t_symbol *sys_libdir;
-static t_symbol *sys_guidir;
+t_symbol *sys_guidir;
static t_namelist *sys_openlist;
static t_namelist *sys_messagelist;
static int sys_version;
@@ -392,6 +392,8 @@ static char *(usagemessage[]) = {
"-nrt -- don't use real-time priority\n",
#endif
"-nosleep -- spin, don't sleep (may lower latency on multi-CPUs)\n",
+"-schedlib <file> -- plug in external scheduler\n",
+"-extraflags <s> -- string argument to send schedlib\n",
};
static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
@@ -810,7 +812,7 @@ int sys_argparse(int argc, char **argv)
sys_listplease = 1;
argc--; argv++;
}
- else if (!strcmp(*argv, "-schedlib"))
+ else if (!strcmp(*argv, "-schedlib") && argc > 1)
{
sys_externalschedlib = 1;
strncpy(sys_externalschedlibname, argv[1],
@@ -818,7 +820,7 @@ int sys_argparse(int argc, char **argv)
argv += 2;
argc -= 2;
}
- else if (!strcmp(*argv, "-extraflags"))
+ else if (!strcmp(*argv, "-extraflags") && argc > 1)
{
sys_extraflags = 1;
strncpy(sys_extraflagsstring, argv[1],
diff --git a/pd/src/s_midi_oss.c b/pd/src/s_midi_oss.c
index 354dc0d5..e1f7c8c6 100644
--- a/pd/src/s_midi_oss.c
+++ b/pd/src/s_midi_oss.c
@@ -81,7 +81,7 @@ void sys_do_open_midi(int nmidiin, int *midiinvec,
if (outdevindex >= 0 && fd >= 0)
oss_midioutfd[outdevindex] = fd;
}
- if (devno == 1 && fd < 0)
+ if (devno == 0 && fd < 0)
{
sys_setalarm(1000000);
fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
@@ -116,7 +116,7 @@ void sys_do_open_midi(int nmidiin, int *midiinvec,
int fd = oss_midioutfd[i];
char namebuf[80];
int devno = midioutvec[i];
- if (devno == 1 && fd < 0)
+ if (devno == 0 && fd < 0)
{
sys_setalarm(1000000);
fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
diff --git a/pd/src/s_stuff.h b/pd/src/s_stuff.h
index e53d3edc..3276b00b 100644
--- a/pd/src/s_stuff.h
+++ b/pd/src/s_stuff.h
@@ -49,6 +49,7 @@ EXTERN int sys_hostfontsize(int fontsize);
extern int sys_defaultfont;
extern t_symbol *sys_libdir; /* library directory for auxilliary files */
+extern t_symbol *sys_guidir; /* directory holding pd_gui (also pd, u_pdsend, etc) */
/* s_loader.c */
int sys_load_lib(t_canvas *canvas, char *filename);
@@ -172,6 +173,7 @@ void sys_setalarm(int microsec);
void sys_setvirtualalarm( void);
#endif
+#define API_NONE 0
#define API_ALSA 1
#define API_OSS 2
#define API_MMIO 3
diff --git a/pd/src/u_pdreceive.c b/pd/src/u_pdreceive.c
index 1feac305..e61397ed 100644
--- a/pd/src/u_pdreceive.c
+++ b/pd/src/u_pdreceive.c
@@ -2,10 +2,15 @@
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
-/* the "pdreceive" command. This is a standalone program that receives messages
+/* the "pdreceive" command. This is a standalone program that receives messages
from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
standard output. */
+/* May 2008 : fixed a buffer overflow problem; pdreceive sometimes
+ repeated infinitely its buffer during high speed transfer.
+ Moonix::Antoine Rousseau
+*/
+
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
@@ -26,10 +31,10 @@ standard output. */
typedef struct _fdpoll
{
int fdp_fd;
- char *fdp_inbuf;
- int fdp_inhead;
- int fdp_intail;
- int fdp_udp;
+ char *fdp_outbuf;/*output message buffer*/
+ int fdp_outlen; /*length of output message*/
+ int fdp_discard;/*buffer overflow: output message is incomplete, discard it*/
+ int fdp_gotsemi;/*last char from input was a semicolon*/
} t_fdpoll;
static int nfdpoll;
@@ -122,8 +127,8 @@ static void addport(int fd)
fp->fdp_fd = fd;
nfdpoll++;
if (fd >= maxfd) maxfd = fd + 1;
- fp->fdp_inhead = fp->fdp_intail = 0;
- if (!(fp->fdp_inbuf = malloc(BUFSIZE)))
+ fp->fdp_outlen = fp->fdp_discard = fp->fdp_gotsemi = 0;
+ if (!(fp->fdp_outbuf = malloc(BUFSIZE)))
{
fprintf(stderr, "out of memory");
exit(1);
@@ -141,7 +146,7 @@ static void rmport(t_fdpoll *x)
if (fp == x)
{
x_closesocket(fp->fdp_fd);
- free(fp->fdp_inbuf);
+ free(fp->fdp_outbuf);
while (i--)
{
fp[0] = fp[1];
@@ -191,75 +196,66 @@ static void udpread(void)
}
}
-static int tcpmakeoutput(t_fdpoll *x)
+static int tcpmakeoutput(t_fdpoll *x, char *inbuf, int len)
{
- char messbuf[BUFSIZE+1], *bp = messbuf;
- int indx;
- int inhead = x->fdp_inhead;
- int intail = x->fdp_intail;
- char *inbuf = x->fdp_inbuf;
- if (intail == inhead)
- return (0);
- for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
+ int i;
+ int outlen = x->fdp_outlen;
+ char *outbuf = x->fdp_outbuf;
+
+ for (i = 0 ; i < len ; i++)
{
+ char c = inbuf[i];
+
+ if((c != '\n') || (!x->fdp_gotsemi))
+ outbuf[outlen++] = c;
+ x->fdp_gotsemi = 0;
+ if (outlen >= (BUFSIZE-1)) /*output buffer overflow; reserve 1 for '\n' */
+ {
+ fprintf(stderr, "pdreceive: message too long; discarding\n");
+ outlen = 0;
+ x->fdp_discard = 1;
+ }
/* search for a semicolon. */
- char c = *bp++ = inbuf[indx];
if (c == ';')
{
- intail = (indx+1)&(BUFSIZE-1);
- if (inbuf[intail] == '\n')
- intail = (intail+1)&(BUFSIZE-1);
- *bp++ = '\n';
-#ifdef MSW
+ outbuf[outlen++] = '\n';
+ if (!x->fdp_discard)
{
- int j;
- for (j = 0; j < bp - messbuf; j++)
- putchar(messbuf[j]);
- }
+#ifdef MSW
+ {
+ int j;
+ for (j = 0; j < outlen; j++)
+ putchar(outbuf[j]);
+ }
#else
- write(1, messbuf, bp - messbuf);
+ write(1, outbuf, outlen);
#endif
- x->fdp_inhead = inhead;
- x->fdp_intail = intail;
- return (1);
- }
- }
+ } /* if (!x->fdp_discard) */
+
+ outlen = 0;
+ x->fdp_discard = 0;
+ x->fdp_gotsemi = 1;
+ } /* if (c == ';') */
+ } /* for */
+
+ x->fdp_outlen = outlen;
return (0);
}
static void tcpread(t_fdpoll *x)
{
- int readto =
- (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
- int ret;
+ int ret;
+ char inbuf[BUFSIZE];
- /* the input buffer might be full. If so, drop the whole thing */
- if (readto == x->fdp_inhead)
- {
- fprintf(stderr, "pd: dropped message from gui\n");
- x->fdp_inhead = x->fdp_intail = 0;
- readto = BUFSIZE;
- }
- else
+ ret = recv(x->fdp_fd, inbuf, BUFSIZE, 0);
+ if (ret < 0)
{
- ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
- readto - x->fdp_inhead, 0);
- if (ret < 0)
- {
- sockerror("recv (tcp)");
- rmport(x);
- }
- else if (ret == 0)
- rmport(x);
- else
- {
- x->fdp_inhead += ret;
- if (x->fdp_inhead >= BUFSIZE)
- x->fdp_inhead = 0;
- while (tcpmakeoutput(x))
- ;
- }
+ sockerror("recv (tcp)");
+ rmport(x);
}
+ else if (ret == 0)
+ rmport(x);
+ else tcpmakeoutput(x, inbuf, ret);
}
static void dopoll(void)