diff --git a/bin/helpbrowser.tcl b/bin/helpbrowser.tcl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/bin/pd.tk b/bin/pd.tk new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/bin/pkgIndex.tcl b/bin/pkgIndex.tcl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/extra/bonk~/bonk~-help.pd b/extra/bonk~/bonk~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..e52b7c506f1fde987bab3f725ca88ce3eeabb582 --- /dev/null +++ b/extra/bonk~/bonk~-help.pd @@ -0,0 +1,209 @@ +#N canvas 43 123 1054 583 12; +#X obj 382 492 spigot; +#X msg 484 293 bang; +#X obj 483 454 bonk~; +#X msg 483 357 print; +#X obj 435 428 adc~; +#X msg 637 506 \; pd dsp 1; +#X obj 300 492 spigot; +#N canvas 366 126 604 404 synth 0; +#X obj 112 24 r bonk-cooked; +#X obj 112 49 unpack; +#X obj 112 99 * 12; +#X obj 112 124 div 7; +#X obj 112 74 + 1; +#X obj 112 174 mtof; +#X obj 112 224 osc~; +#X obj 112 249 cos~; +#X obj 112 149 + 47; +#X obj 209 247 line~; +#X obj 209 272 *~; +#X obj 209 297 lop~ 500; +#X obj 112 274 *~; +#X obj 103 361 dac~; +#X obj 253 165 dbtorms; +#X obj 253 115 * 0.5; +#X obj 253 140 + 50; +#X obj 211 189 f; +#X msg 173 159 bang; +#X obj 258 83 inlet; +#X obj 111 307 hip~ 5; +#X msg 34 24 0 60; +#X obj 112 199 sig~; +#X msg 209 222 \$1 \, 0 200; +#X connect 0 0 1 0; +#X connect 1 0 4 0; +#X connect 2 0 3 0; +#X connect 3 0 8 0; +#X connect 4 0 2 0; +#X connect 5 0 18 0; +#X connect 5 0 22 0; +#X connect 6 0 7 0; +#X connect 7 0 12 0; +#X connect 8 0 5 0; +#X connect 9 0 10 0; +#X connect 9 0 10 1; +#X connect 10 0 11 0; +#X connect 11 0 12 1; +#X connect 12 0 20 0; +#X connect 14 0 17 1; +#X connect 15 0 16 0; +#X connect 16 0 14 0; +#X connect 17 0 23 0; +#X connect 18 0 17 0; +#X connect 19 0 15 0; +#X connect 20 0 13 1; +#X connect 20 0 13 0; +#X connect 21 0 1 0; +#X connect 22 0 6 0; +#X connect 23 0 9 0; +#X restore 869 523 pd synth; +#X floatatom 869 500 0 0 0 0 - - -; +#X msg 869 470 0; +#X msg 900 470 90; +#X text 625 472 click here; +#X text 626 485 to start DSP; +#X text 5 285 In this patch \, after starting DSP \, you can print +out the raw or cooked output using the two "spigots" or listen to a +synthesizer output by raising its volume.; +#X text 770 469 output volume; +#X text 784 487 (0-100); +#X msg 483 138 mask 4 0.7; +#X text 578 120 Describes how energy in each frequency band masks later +energy in the band. Here the masking is total for 4 analysis periods +and then drops by 0.7 each period.; +#X text 528 286 Poll the current spectrum via "raw" outlet \, You can +set a very high threshold if you don't want attacks mixed in.; +#X msg 483 331 debug 0; +#X text 561 331 turn debugging on or off.; +#X obj 349 493 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 431 493 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 382 522 print cooked; +#X obj 300 522 print raw; +#X text 162 491 enable printout:; +#X text 560 202 Minimum "velocity" to output (quieter notes are ignored.) +; +#X obj 485 481 s bonk-cooked; +#X text 8 145 Bonk's two outputs are the raw spectrum of the attack +(provided as a list of 11 numbers giving the signal "loudness" in the +11 frequency bands used) \, and the "cooked" output which gives only +an instrument number (counting up from zero) and a "velocity". This +"velocity" is the sum of the square roots of the amplitudes of the +bands \, normalized so that 100 is an attack of amplitude of about +1 The instrument number is significant only if Bonk has a "template +set" in memory.; +#X text 580 35 Set low and high thresholds. Signal growth must exceed +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 msg 483 384 print 1; +#X text 551 386 print out filterbank settings; +#X text 9 33 The Bonk object takes an audio signal input and looks +for "attacks" defined as sharp changes in the spectral envelope of +the incoming sound. Optionally \, and less reliably \, you can have +Bonk check the attack against a collection of stored templates to try +to guess which of two or more instruments was hit. Bonk is described +theoretically in the 1998 ICMC proceedings \, reprinted on crca.ucsd.edu/~msp +.; +#N canvas 723 241 701 719 creation-arguments 0; +#X text 228 14 creation arguments for bonk~; +#X text 70 272 -npts 256; +#X text 44 244 default value:; +#X text 70 308 -hop 128; +#X text 70 342 -nfilters 11; +#X text 68 380 -halftones 6; +#X text 76 514 -overlap 1; +#X text 79 567 -firstbin 1; +#X text 71 454 -minbandwidth 1.5; +#X text 122 147 All frequency parameters are specified in 'bins'. One +bin is the sample rate divided by the window size. The minimum possible +bandwidth is 1.5 bins. Higher bandwidths give numerically more robust +outputs.; +#X text 43 229 Arguments and; +#X text 212 270 window size in points; +#X text 210 306 analysis period ("hop size") in points; +#X text 212 340 number of filters to use; +#X text 212 379 desired bandwidth of filters in halftones \, effective +in the exponentially spaced region. (At lower center frequencies the +bandwidth is supported by the "minbandwidth" parameter below).; +#X text 212 511 overlap factor between filters. If 1 \, the filters +are spaced to line up at their half-power points. Other values specify +more or fewer filters proportionally.; +#X text 121 49 bonk~ uses a filterbank whose center frequencies are +spaced equally at low frequencies and proportionally at high ones - +i.e. \, they increase linearly \, then exponentially. They are determined +by the filters' bandwidths and overlap. The bandwidths are specified +proportionally to frequency but bounded below by a specified minimum. +; +#X text 210 455 minimum bandwidth in bins. If the bandwidth specified +by "halftones" is smaller than this \, this value is used. This must +be at least 1.5.; +#X text 212 567 center frequency \, in bins \, of the lowest filter. +The others are computed from this.; +#X restore 147 414 pd creation-arguments; +#N canvas 660 173 579 589 templates 0; +#X msg 76 197 learn 0; +#X msg 76 227 forget; +#X msg 76 257 write templates.txt; +#X msg 76 287 read templates.txt; +#X msg 76 107 debounce 0; +#X msg 76 137 learn 10; +#X obj 62 431 outlet; +#X text 155 133 Forget all templates and start learning new ones. The +argument gives the number of times you will hit each instrument (10 +recommended.) Turn on the output volume above for audible feedback +as you train Bonk. "Learn 0" exits learn mode.; +#X text 155 217 Forget the last template. In Learn mode \, use "forget" +to erase and record over a template.; +#X text 220 253 Write templates to a file in text-editable format. +; +#X text 221 283 Read templates from a file.; +#X text 157 104 Minimum time (msec) between attacks in learn mode; +#X connect 0 0 6 0; +#X connect 1 0 6 0; +#X connect 2 0 6 0; +#X connect 3 0 6 0; +#X connect 4 0 6 0; +#X connect 5 0 6 0; +#X restore 500 421 pd templates; +#X msg 483 68 thresh 2.5 5; +#X msg 483 173 attack-frames 1; +#X text 608 174 number of frames over which to measure growth; +#X text 605 422 more messages for managing templates; +#X msg 483 201 minvel 7; +#X msg 483 228 spew 0; +#X text 550 230 Turn spew mode on/off; +#X msg 483 255 useloudness 0; +#X text 597 254 experimental: use alternative loudness units; +#X text 212 9 BONK~ - attack detection and spectral envelope measurement +; +#X text 734 552 Updated for Pd version 0.42; +#X text 5 344 By default bonk's analysis is carried out on a 256-point +window (6 msec at 44.1 kHz) and the analysis period is 128 samples. +These and other parameters may be overridden using creation arguments +as shown in the subpatch below:; +#X text 552 356 Print out settings and templates.; +#X connect 0 0 23 0; +#X connect 1 0 2 0; +#X connect 2 0 6 0; +#X connect 2 1 0 0; +#X connect 2 1 27 0; +#X connect 3 0 2 0; +#X connect 4 0 2 0; +#X connect 6 0 24 0; +#X connect 8 0 7 0; +#X connect 9 0 8 0; +#X connect 10 0 8 0; +#X connect 16 0 2 0; +#X connect 19 0 2 0; +#X connect 21 0 6 1; +#X connect 22 0 0 1; +#X connect 30 0 2 0; +#X connect 34 0 2 0; +#X connect 35 0 2 0; +#X connect 36 0 2 0; +#X connect 39 0 2 0; +#X connect 40 0 2 0; +#X connect 42 0 2 0; diff --git a/extra/bonk~/bonk~.c b/extra/bonk~/bonk~.c new file mode 100644 index 0000000000000000000000000000000000000000..d0f18de967c4cf527cd20541668cc12348becf77 --- /dev/null +++ b/extra/bonk~/bonk~.c @@ -0,0 +1,1475 @@ +/* + ########################################################################### + # bonk~ - a Max/MSP external + # by miller puckette and ted apel + # 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> + +/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans@at.or.at> */ +#ifdef _MSC_VER +#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 +#define fexp exp +#define fsqrt sqrt +#define t_resizebytes(a, b, c) t_resizebytes((char *)(a), (b), (c)) + +void *bonk_class; +#define getbytes t_getbytes +#define freebytes t_freebytes +#endif /* MSP */ + +#ifdef PD +#include "m_pd.h" +static t_class *bonk_class; +#endif + +#ifndef _MSC_VER +#include <alloca.h> +#endif + +/* ------------------------ bonk~ ----------------------------- */ + +#define DEFNPOINTS 256 +#define MAXCHANNELS 8 +#define MINPOINTS 64 +#define DEFPERIOD 128 +#define DEFNFILTERS 11 +#define DEFHALFTONES 6 +#define DEFOVERLAP 1 +#define DEFFIRSTBIN 1 +#define DEFMINBANDWIDTH 1.5 +#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_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 */ + float b_minbandwidth; /* minimum bandwidth, default 1.5 */ + 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}, + {128, 6, .01803}, {90, 6, .02222}, {64, 6, .02362}, {46, 6, .02773}, + {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}, + {212, 6, .01886, 0}, {150, 6, .01885, 0}, {106, 6, .02179, 0}, + {76, 6, .0236, 0}, {54, 6, .02634, 0}, {38, 6, .03047, 0}, + {26, 6, .03667, 0}, {18, 6, .04458, 0}}; + +#define NFILTERS \ + ((int)(sizeof(bonk_filterkernels) / sizeof(bonk_filterkernels[0]))) + +#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 t_filterbank *bonk_filterbanklist; + +typedef struct _hist +{ + float h_power; + float h_before; + float h_outpower; + int h_countup; + float h_mask[MASKHIST]; +} t_hist; + +typedef struct template +{ + float t_amp[MAXNFILTERS]; +} t_template; + +typedef struct _insig +{ + t_hist g_hist[MAXNFILTERS]; /* history for each filter */ +#ifdef PD + t_outlet *g_outlet; /* outlet for raw data */ +#endif +#ifdef MSP + void *g_outlet; /* outlet for raw data */ +#endif + float *g_inbuf; /* buffered input samples */ + t_float *g_invec; /* new input samples */ +} t_insig; + +typedef struct _bonk +{ +#ifdef PD + t_object x_obj; + t_outlet *x_cookedout; + t_clock *x_clock; +#endif /* PD */ +#ifdef MSP + t_pxobject x_obj; + void *obex; + void *x_cookedout; + void *x_clock; +#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_minbandwidth; + 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_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_willattack; + int x_attacked; + int x_debug; + int x_learn; + int x_learncount; /* countup for "learn" mode */ + 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(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); +static void bonk_dsp(t_bonk *x, t_signal **sp); +void bonk_assist(t_bonk *x, void *b, long m, long a, char *s); +static void bonk_free(t_bonk *x); +void bonk_setup(void); +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); +char *strcpy(char *s1, const char *s2); +#endif + +static void bonk_tick(t_bonk *x); + +#define HALFWIDTH 0.75 /* half peak bandwidth at half power point in bins */ +#define SLIDE 0.25 /* relative slide between filter subwindows */ + +static t_filterbank *bonk_newfilterbank(int npoints, int nfilters, + float halftones, float overlap, float firstbin, float minbandwidth) +{ + 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_minbandwidth = minbandwidth; + 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 */ + + if (minbandwidth < 2*HALFWIDTH) + minbandwidth = 2*HALFWIDTH; + if (firstbin < minbandwidth/(2*HALFWIDTH)) + firstbin = minbandwidth/(2*HALFWIDTH); + cf = firstbin; + bw = cf * relspace * overlap; + if (bw < (0.5*minbandwidth)) + bw = (0.5*minbandwidth); + for (i = 0; i < nfilters; i++) + { + float *fp, newcf, newbw; + float normalizer = 0; + int filterpoints, skippoints, hoppoints, nhops; + + filterpoints = 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 = SLIDE * 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 * sqrt(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 < 0.5*minbandwidth) + { + newbw = 0.5*minbandwidth; + newcf = cf + minbandwidth / 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 minbandwidth, 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_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; + x->x_willattack = 0; + x->x_attacked = 0; + x->x_maskphase = 0; + x->x_debug = 0; + x->x_hithresh = DEFHITHRESH; + x->x_lothresh = DEFLOTHRESH; + x->x_masktime = DEFMASKTIME; + x->x_maskdecay = DEFMASKDECAY; + x->x_learn = 0; + x->x_learndebounce = clock_getsystime(); + x->x_learncount = 0; + x->x_debouncedecay = DEFDEBOUNCEDECAY; + x->x_minvel = DEFMINVEL; + x->x_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_minbandwidth == minbandwidth) + { + fb->b_refcount++; + x->x_filterbank = fb; + break; + } + if (!x->x_filterbank) + x->x_filterbank = bonk_newfilterbank(npoints, nfilters, + halftones, overlap, firstbin, minbandwidth), + x->x_filterbank->b_refcount++; +} + +static void bonk_tick(t_bonk *x) +{ + t_atom at[MAXNFILTERS], *ap, at2[3]; + int i, j, k, n; + t_hist *h; + float *pp, vel = 0, temperature = 0; + float *fp; + t_template *tp; + int nfit, ninsig = x->x_ninsig, ntemplate = x->x_ntemplate, nfilters = x->x_nfilters; + t_insig *gp; +#ifdef _MSC_VER + float powerout[MAXNFILTERS*MAXCHANNELS]; +#else + float *powerout = alloca(x->x_nfilters * x->x_ninsig * sizeof(*powerout)); +#endif + + for (i = ninsig, pp = powerout, gp = x->x_insig; i--; gp++) + { + for (j = 0, h = gp->g_hist; j < nfilters; j++, h++, pp++) + { + float power = h->h_outpower; + float intensity = *pp = (power > 0 ? 100. * qrsqrt(qrsqrt(power)) : 0); + vel += intensity; + temperature += intensity * (float)j; + } + } + if (vel > 0) temperature /= vel; + else temperature = 0; + vel *= 0.5 / ninsig; /* fudge factor */ + if (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 (vel < x->x_debouncevel) + { + if (x->x_debug) + post("bounce cancelled: vel %f debounce %f", + vel, x->x_debouncevel); + return; + } + if (vel < x->x_minvel) + { + if (x->x_debug) + post("low velocity cancelled: vel %f, minvel %f", + vel, x->x_minvel); + return; + } + x->x_debouncevel = vel; + if (x->x_learn) + { + double lasttime = x->x_learndebounce; + double msec = clock_gettimesince(lasttime); + if ((!ntemplate) || (msec > 200)) + { + int countup = x->x_learncount; + /* normalize to 100 */ + float norm; + for (i = nfilters * ninsig, norm = 0, pp = powerout; i--; pp++) + norm += *pp * *pp; + if (norm < 1.0e-15) norm = 1.0e-15; + norm = 100.f * qrsqrt(norm); + /* check if this is the first strike for a new template */ + if (!countup) + { + int oldn = ntemplate; + x->x_ntemplate = ntemplate = oldn + ninsig; + x->x_template = (t_template *)t_resizebytes(x->x_template, + oldn * sizeof(x->x_template[0]), + ntemplate * sizeof(x->x_template[0])); + for (i = ninsig, pp = powerout; i--; oldn++) + for (j = nfilters, fp = x->x_template[oldn].t_amp; j--; + pp++, fp++) + *fp = *pp * norm; + } + else + { + int oldn = ntemplate - ninsig; + if (oldn < 0) post("bonk_tick bug"); + for (i = ninsig, pp = powerout; i--; oldn++) + { + for (j = nfilters, fp = x->x_template[oldn].t_amp; j--; + pp++, fp++) + *fp = (countup * *fp + *pp * norm) + /(countup + 1.0f); + } + } + countup++; + if (countup == x->x_learn) countup = 0; + x->x_learncount = countup; + } + else return; + } + x->x_learndebounce = clock_getsystime(); + if (ntemplate) + { + float bestfit = -1e30; + int templatecount; + nfit = -1; + for (i = 0, templatecount = 0, tp = x->x_template; + templatecount < ntemplate; i++) + { + float dotprod = 0; + for (k = 0, pp = powerout; + k < ninsig && templatecount < ntemplate; + k++, tp++, templatecount++) + { + for (j = nfilters, fp = tp->t_amp; + j--; fp++, pp++) + { + if (*fp < 0 || *pp < 0) post("bonk_tick bug 2"); + dotprod += *fp * *pp; + } + } + if (dotprod > bestfit) + { + bestfit = dotprod; + nfit = i; + } + } + if (nfit < 0) post("bonk_tick bug"); + } + else nfit = 0; + } + else nfit = -1; /* hit is zero; this is the "bang" method. */ + + 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) + { + float *pp2; + for (i = 0, ap = at, pp2 = pp; i < nfilters; + i++, ap++, pp2++) + { + ap->a_type = A_FLOAT; + ap->a_w.w_float = *pp2; + } + outlet_list(gp->g_outlet, 0, nfilters, at); + } +} + +static void bonk_doit(t_bonk *x) +{ + int i, j, ch, n; + t_filterkernel *k; + t_hist *h; + 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; + 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[maskphase]; + float *inbuf= gp->g_inbuf + k->k_skippoints; + int countup = h->h_countup; + 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 = filterpoints; j--;) + { + float g = *fp3++; + rsum += g * *fp4++; + isum += g * *fp4++; + } + power += rsum * rsum + isum * isum; + } + if (!x->x_willattack) + h->h_before = maskpow; + + if (power > 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; + countup = 0; + } + countup++; + h->h_countup = countup; + h->h_mask[nextphase] = maskpow; + h->h_power = power; + } + } + 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) + x->x_willattack = 0; + else x->x_willattack++; + } + else if (growth > x->x_hithresh) + { + if (x->x_debug) post("attack: growth = %f", growth); + x->x_willattack = 1; + 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; + } + + /* if in "spew" mode just always output */ + if (x->x_spew) + { + 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); + } + 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 = 0; + if (x->x_countdown >= n) + x->x_countdown -= n; + else + { + int i, j, ninsig = x->x_ninsig; + t_insig *gp; + if (x->x_countdown > 0) + { + n -= x->x_countdown; + onset += x->x_countdown; + x->x_countdown = 0; + } + while (n > 0) + { + 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; + } + } + return (w+3); +} + +static void bonk_dsp(t_bonk *x, t_signal **sp) +{ + int i, n = sp[0]->s_n, ninsig = x->x_ninsig; + t_insig *gp; + + x->x_sr = sp[0]->s_sr; + + for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++) + gp->g_invec = (*(sp++))->s_vec; + + 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 <= 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; + if (ticks < 0) ticks = 0; + if (f2 < 0) f2 = 0; + else if (f2 > 1) f2 = 1; + x->x_masktime = ticks; + x->x_maskdecay = f2; +} + +static void bonk_debounce(t_bonk *x, t_floatarg f1) +{ + if (f1 < 0) f1 = 0; + else if (f1 > 1) f1 = 1; + x->x_debouncedecay = f1; +} + +static void bonk_minvel(t_bonk *x, t_floatarg f) +{ + if (f < 0) f = 0; + x->x_minvel = f; +} + +static void bonk_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-frames %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]); + } + else post("no templates"); +#endif + post("number of templates %d", x->x_ntemplate); + if (x->x_learn) post("learn mode"); + if (f != 0) + { + int j, ninsig = x->x_ninsig; + t_insig *gp; + for (j = 0, gp = x->x_insig; j < ninsig; j++, gp++) + { + t_hist *h; + if (ninsig > 1) post("input %d:", j+1); + for (i = x->x_nfilters, h = gp->g_hist; i--; h++) + post("pow %f mask %f before %f count %d", + 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/x->x_npoints); + 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_forget(t_bonk *x) +{ + int ntemplate = x->x_ntemplate, newn = ntemplate - x->x_ninsig; + if (newn < 0) newn = 0; + x->x_template = (t_template *)t_resizebytes(x->x_template, + x->x_ntemplate * sizeof(x->x_template[0]), + newn * sizeof(x->x_template[0])); + x->x_ntemplate = newn; + x->x_learncount = 0; +} + +static void bonk_bang(t_bonk *x) +{ + int i, ch; + t_insig *gp; + x->x_hit = 0; + for (ch = 0, gp = x->x_insig; ch < x->x_ninsig; ch++, gp++) + { + t_hist *h; + for (i = 0, h = gp->g_hist; i < x->x_nfilters; i++, h++) + h->h_outpower = h->h_power; + } + bonk_tick(x); +} + +static void bonk_read(t_bonk *x, t_symbol *s) +{ + FILE *fd = fopen(s->s_name, "r"); + float vec[MAXNFILTERS]; + int i, ntemplate = 0, remaining; + float *fp, *fp2; + if (!fd) + { + post("%s: open failed", s->s_name); + return; + } + x->x_template = (t_template *)t_resizebytes(x->x_template, + x->x_ntemplate * sizeof(t_template), 0); + while (1) + { + for (i = 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 = x->x_nfilters, fp = vec, + fp2 = x->x_template[ntemplate].t_amp; i--;) + *fp2++ = *fp++; + ntemplate++; + } +nomore: + if (remaining = (ntemplate % x->x_ninsig)) + { + post("bonk_read: %d templates not a multiple of %d; dropping extras"); + x->x_template = (t_template *)t_resizebytes(x->x_template, + ntemplate * sizeof(t_template), + (ntemplate - remaining) * sizeof(t_template)); + ntemplate = ntemplate - remaining; + } + post("bonk: read %d templates\n", ntemplate); + x->x_ntemplate = ntemplate; + fclose(fd); +} + +static void bonk_write(t_bonk *x, t_symbol *s) +{ + FILE *fd = fopen(s->s_name, "w"); + int i, ntemplate = x->x_ntemplate; + t_template *tp = x->x_template; + float *fp; + if (!fd) + { + post("%s: couldn't create", s->s_name); + return; + } + for (; ntemplate--; tp++) + { + for (i = 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); +} + +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, 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_symbol *s, int argc, t_atom *argv) +{ + t_bonk *x = (t_bonk *)pd_new(bonk_class); + int nsig = 1, period = DEFPERIOD, npts = DEFNPOINTS, + nfilters = DEFNFILTERS, j; + float halftones = DEFHALFTONES, overlap = DEFOVERLAP, + firstbin = DEFFIRSTBIN, minbandwidth = DEFMINBANDWIDTH; + t_insig *g; + + 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, "-minbandwidth") && argc > 1) + { + minbandwidth = 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++) + { + g->g_outlet = outlet_new(&x->x_obj, gensym("list")); + if (j) + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + } + x->x_cookedout = outlet_new(&x->x_obj, gensym("list")); + bonk_donew(x, npts, period, nsig, nfilters, halftones, overlap, + firstbin, minbandwidth, 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_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_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_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_attackbins, + gensym("attack-frames"), 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 + +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("minbandwidth", sym_float32, attrflags, (method)0L, (method)0L, calcoffset(t_bonk, x_minbandwidth)); + 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("attackframes", 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) +{ + 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_minbandwidth = DEFMINBANDWIDTH; + 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, x->x_minbandwidth, + sys_getsr()); + } + return (x); +} + +/* Attribute setters. */ +void bonk_minvel_set(t_bonk *x, void *attr, long ac, t_atom *av) +{ + if (ac && av) { + float f = atom_getfloat(av); + if (f < 0) f = 0; + x->x_minvel = f; + } +} + +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); + } +} + +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; + } +} + +void bonk_maskdecay_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_maskdecay = f; + } +} + +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; + } +} + +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 bonk_learn_set(t_bonk *x, void *attr, long ac, t_atom *av) +{ + 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) +{ +} + + /* get current system time */ +double clock_getsystime() +{ + return gettime(); +} + + /* elapsed time in milliseconds since the given system time */ +double clock_gettimesince(double prevsystime) +{ + return ((gettime() - prevsystime)); +} + +float qrsqrt(float f) +{ + return 1/sqrt(f); +} +#endif /* MSP */ diff --git a/extra/bonk~/makefile b/extra/bonk~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..af6399cca16d00a8033b4ba22ea02779fe98b80b --- /dev/null +++ b/extra/bonk~/makefile @@ -0,0 +1,4 @@ +NAME=bonk~ +CSYM=bonk_tilde + +include ../makefile diff --git a/extra/bonk~/templates.txt b/extra/bonk~/templates.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3528d78acad986c438e2c36cdef7d6f36642ba2 --- /dev/null +++ b/extra/bonk~/templates.txt @@ -0,0 +1,4 @@ + 10.47 9.65 14.95 23.77 28.32 38.84 53.21 41.20 31.25 21.70 16.48 + 6.52 13.93 27.82 58.05 24.11 35.26 35.98 37.78 22.54 13.56 10.75 + 30.45 28.86 29.42 21.94 29.92 35.70 38.49 32.01 28.19 27.38 22.10 + 66.77 46.27 28.82 25.95 22.84 20.61 20.33 14.18 6.86 8.92 7.37 diff --git a/extra/choice/choice.pd_linux b/extra/choice/choice.pd_linux deleted file mode 100755 index e462551346fee426bd8eab05b2c5d3030d9a0132..0000000000000000000000000000000000000000 Binary files a/extra/choice/choice.pd_linux and /dev/null differ diff --git a/extra/expr~/LICENSE.txt b/extra/expr~/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..a52b16e4064dfee29faf4b9fdbb058237b418fce --- /dev/null +++ b/extra/expr~/LICENSE.txt @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/extra/expr~/README.txt b/extra/expr~/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf84f2ae6e8f83170f2940db2e2094283dd64835 --- /dev/null +++ b/extra/expr~/README.txt @@ -0,0 +1,97 @@ + +You can get more information on the expr object at +http://www.crca.ucsd.edu/~yadegari/expr.html + +----------- + +New if Version 0.4 + +-access to variables (made by value object) +-multiple expression separated by ; +-added the following shorthands: + $y or $y1 = $y1[-1] and $y2 = $y2[-1] +-new functions: + if - conditional evaluation + cbrt - cube root + erf - error function + erfc - complementary error function + expm1 - exponential minus 1, + log1p - logarithm of 1 plus + isinf - is the value infinite, + finite - is the value finite + isnan -- is the resut a nan (Not a number) + copysign - copy sign of a number + ldexp - multiply floating-point number by integral power of 2 + imodf - get signed integral value from floating-point number + modf - get signed fractional value from floating-point number + drem - floating-point remainder function + + Thanks to Orm Finnendahl for adding the following functions: + fmod - floating-point remainder function + ceil - ceiling function: smallest integral value not less than argument + floor - largest integral value not greater than argument + +------------ + +New in Version 0.3 +-Full function functionality + +------------ + +The object "expr" is used for expression evaluaion of control data. + +Expr~ and fexpr~ are extentions to the expr object to work with vectors. +The expr~ object is designed to efficiently combine signal and control +stream processing by vector operations on the basis of the block size of +the environment. + +fexpr~ object provides a flexible mechanism for building FIR and +IIR filters by evaluating expressions on a sample by sample basis +and providing access to prior samples of the input and output audio +streams. When fractional offset is used, fexpr~ uses linear interpolation +to determine the value of the indexed sample. fexpr~ evaluates the +expression for every single sample and at every evaluation previous +samples (limited by the audio vector size) can be accessed. $x is used to +denote a singnal input whose samples we would like to access. The syntax +is $x followed by the inlet number and indexed by brackets, for example +$x1[-1] specifies the previous sample of the first inlet. Therefore, +if we are to build a simple filter which replaces every sample by +the average of that sample and its previous one, we would use "fexpr~ +($x1[0]+$x1[-1])/2 ". For ease of when the brackets are omitted, the +current sample is implied, so we can right the previous filter expression +as follows: " fexpr~ ($x1+$x1[-1])/2". To build IIR filters $y is used +to access the previous samples of the output stream. + +The three objects expr, expr~, and fexpr~ are implemented in the same object +so the files expr~.pd_linux and fexpr~.pd_linux are links to expr.pd_linux +This release has been compiled and tested on Linux 6.0. + +-------- + +Here are some syntax information: (refer to help-expr.pd for examples) + +Syntyax: +The syntax is very close to how expression are written in +C. Variables are specified as follows where the '#' stands +for the inlet number: +$i#: integer input variable +$f#: float input variable +$s#: symbol input variable + +Used for expr~ only: +$v#: signal (vector) input (vector by vector evaluation) + +Used for fexpr~ only: +$x#[n]: the sample from inlet # indexed by n, where n has to + satisfy 0 => n >= -vector size, + ($x# is a shorthand for $x#[0], specifying the current sample) + +$y#[n]: the output value indexed by n, where n has to + satisfy 0 > n >= -vector size, + $y[n] is a shorthand for $y1[n] + + +I'll appreciate hearing about bugs, comments, suggestions, ... + +Shahrokh Yadegari (sdy@ucsd.edu) +7/10/02 diff --git a/extra/expr~/fts_to_pd.h b/extra/expr~/fts_to_pd.h new file mode 100644 index 0000000000000000000000000000000000000000..9ca2fc4222da17a148135192391a5b9a46d9f6a9 --- /dev/null +++ b/extra/expr~/fts_to_pd.h @@ -0,0 +1,41 @@ +/* fts_to_pd.h -- alias some fts names to compile in Pd. + +copyright 1999 Miller Puckette; +permission is granted to use this file for any purpose. +*/ + + +#define fts_malloc malloc +#define fts_calloc calloc +#define fts_free free +#define fts_realloc realloc +#define fts_atom_t t_atom +#define fts_object_t t_object +typedef t_symbol *fts_symbol_t; + +#ifdef MSP +#define t_atom Atom +#define t_symbol Symbol +#define pd_new(x) newobject(x); +#define pd_free(x) freeobject(x); +#define t_outlet void +#define t_binbuf void +typedef t_class *t_pd; +typedef float t_floatarg; + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +void pd_error(void *object, char *fmt, ...); + +#endif /* MSP */ + +#define post_error pd_error +#define fts_is_floatg(x) ((x)->a_type == A_FLOAT) + +#define fts_new_symbol_copy gensym + +#define fts_symbol_name(x) ((x)->s_name) diff --git a/extra/expr~/makefile b/extra/expr~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..4c6481407e601a0afed81ac3be4b69d478b7719f --- /dev/null +++ b/extra/expr~/makefile @@ -0,0 +1,191 @@ + +current: expr.pd_linux expr~.pd_linux fexpr~.pd_linux \ + ../expr.pd_linux ../expr~.pd_linux ../fexpr~.pd_linux + +install: install_linux + +clean: clean_linux + +PDEXTERN=/usr/local/lib/pd/externs + +# ----------------------- NT ----------------------- + +pd_nt: expr.dll + +NTOBJ = vexp.obj vexp_fun.obj vexp_if.obj + +PDNTCFLAGS = /W3 /DNT /DPD /nologo +VC = "C:\Program Files\Microsoft Visual Studio 9.0\VC" +VSTK = "C:\Program Files\Microsoft SDKs\Windows\v6.0A" + +PDNTINCLUDE = /I. /I..\..\src /I$(VC)\include + +PDNTLDIR = $(VC)\lib +PDNTLIB = /NODEFAULTLIB:libcmt /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel32 \ + $(PDNTLDIR)\libcmt.lib $(PDNTLDIR)\oldnames.lib \ + $(VSTK)\lib\kernel32.lib \ + ..\..\bin\pd.lib + +.c.obj: + cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c + +expr.dll: $(NTOBJ) + link /dll /export:expr_setup /export:expr_tilde_setup \ + /export:fexpr_tilde_setup $(NTOBJ) $(PDNTLIB) + ren vexp.dll expr.dll + copy expr.dll ..\expr.dll + copy expr.dll ..\expr~.dll + copy expr.dll ..\fexpr~.dll + copy help-expr.pd ..\help-expr.pd + +# ----------------------- IRIX 5.x ----------------------- + +pd_irix5: + +.SUFFIXES: .pd_irix5 + +SGICFLAGS5 = -o32 -DPD -DSGI -O2 + + +SGIINCLUDE = -I/usr/people/msp/pd/pd/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: + +.SUFFIXES: .pd_irix6 + +SGICFLAGS6 = -DPD -DSGI -n32 \ + -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \ + -Ofast=ip32 + +SGICFLAGS5 = -DPD -O2 -DSGI + +SGIINCLUDE = -I/usr/people/msp/pd/pd/src + +.c.pd_irix6: + $(CC) $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c + ld -elf -shared -rdata_shared -o $*.pd_irix6 $*.o + rm $*.o + +# ----------------------- LINUX i386 ----------------------- + +LINUXOBJ = vexp.pd_linux_o vexp_fun.pd_linux_o vexp_if.pd_linux_o +.SUFFIXES: .pd_linux_o + +LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -fPIC \ + -fno-strict-aliasing -Wall -W -Wshadow -Wstrict-prototypes \ + -Wno-unused -Wno-parentheses -Wno-switch + +LINUXINCLUDE = -I../../src + +.c.pd_linux_o: + $(CC) -g $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.pd_linux_o -c $*.c + +expr.pd_linux: $(LINUXOBJ) + $(CC) -shared -o expr.pd_linux $(LINUXOBJ) -lc -lm + strip --strip-unneeded expr.pd_linux + +expr~.pd_linux: expr.pd_linux + -ln -s expr.pd_linux expr~.pd_linux + +fexpr~.pd_linux: expr.pd_linux + -ln -s expr.pd_linux fexpr~.pd_linux + +../expr.pd_linux: expr.pd_linux + -ln -s expr~/expr.pd_linux ../expr.pd_linux + +../expr~.pd_linux: expr.pd_linux + -ln -s expr~/expr.pd_linux ../expr~.pd_linux + +../fexpr~.pd_linux: expr.pd_linux + -ln -s expr~/expr.pd_linux ../fexpr~.pd_linux + +install_linux: + install expr.pd_linux $(PDEXTERN) + rm -f $(PDEXTERN)/expr~.pd_linux + rm -f $(PDEXTERN)/fexpr~.pd_linux + cd $(PDEXTERN); \ + -ln -s expr.pd_linux expr~.pd_linux + -ln -s expr.pd_linux fexpr~.pd_linux + + +linux_clean: + rm -f *.pd_linux_o *.o + +# ----------------------- MAC OSX ----------------------- + +MACOSXOBJ3 = vexp.d_ppc_o vexp_fun.d_ppc_o vexp_if.d_ppc_o +MACOSXOBJ = vexp.d_fat_o vexp_fun.d_fat_o vexp_if.d_fat_o +.SUFFIXES: .d_ppc_o .d_fat_o + +MACOSXCFLAGS = -DMACOSX -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \ + -Wno-unused -Wno-parentheses -Wno-switch + +MACOSXINCLUDE = -I../../src + +d_ppc: expr.d_ppc expr~.d_ppc fexpr~.d_ppc +.c.d_ppc_o: + $(CC) -g $(MACOSXCFLAGS) $(MACOSXINCLUDE) -o $*.d_ppc_o -c $*.c + +expr.d_ppc: $(MACOSXOBJ3) + $(CC) -bundle -undefined suppress -flat_namespace \ + -o expr.d_ppc $(MACOSXOBJ3) -lm + rm -f ../expr.d_ppc + -ln -s expr~/expr.d_ppc .. + +expr~.d_ppc: expr.d_ppc + -ln -s expr.d_ppc expr~.d_ppc + rm -f ../expr~.d_ppc + -ln -s expr~/expr~.d_ppc .. + +fexpr~.d_ppc: expr.d_ppc + -ln -s expr.d_ppc fexpr~.d_ppc + rm -f ../fexpr~.d_ppc + -ln -s expr~/fexpr~.d_ppc .. + +install_d_fat: + install expr.d_fat $(PDEXTERN) + rm -f $(PDEXTERN)/expr~.d_fat + rm -f $(PDEXTERN)/fexpr~.d_fat + cd $(PDEXTERN); \ + -ln -s expr.d_fat expr~.d_fat; \ + -ln -s expr.d_fat fexpr~.d_fat + +d_fat: expr.d_fat expr~.d_fat fexpr~.d_fat +.c.d_fat_o: + $(CC) -g $(MACOSXCFLAGS) $(MACOSXINCLUDE) -arch i386 -arch ppc \ + -o $*.d_fat_o -c $*.c + +expr.d_fat: $(MACOSXOBJ) + $(CC) -arch i386 -arch ppc -bundle -undefined suppress -flat_namespace \ + -o expr.d_fat $(MACOSXOBJ) -lm + rm -f ../expr.d_fat + -ln -s expr~/expr.d_fat .. + +expr~.d_fat: expr.d_fat + -ln -s expr.d_fat expr~.d_fat + rm -f ../expr~.d_fat + -ln -s expr~/expr~.d_fat .. + +fexpr~.d_fat: expr.d_fat + -ln -s expr.d_fat fexpr~.d_fat + rm -f ../fexpr~.d_fat + -ln -s expr~/fexpr~.d_fat .. + +install_d_ppc: + install expr.d_ppc $(PDEXTERN) + rm -f $(PDEXTERN)/expr~.d_ppc + rm -f $(PDEXTERN)/fexpr~.d_ppc + cd $(PDEXTERN); \ + -ln -s expr.d_ppc expr~.d_ppc; \ + -ln -s expr.d_ppc fexpr~.d_ppc + +clean_d_ppc: + rm -f *.d_ppc_o *.o + diff --git a/extra/expr~/vexp.c b/extra/expr~/vexp.c new file mode 100644 index 0000000000000000000000000000000000000000..732944deba515452b0ebfbc8bd81524cce48e9c9 --- /dev/null +++ b/extra/expr~/vexp.c @@ -0,0 +1,2142 @@ +/* + * jMax + * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * See file LICENSE for further informations on licensing terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Based on Max/ISPW by Miller Puckette. + * + * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell. + * + */ + +/* "expr" was written by Shahrokh Yadegari c. 1989. -msp */ +/* "expr~" and "fexpr~" conversion by Shahrokh Yadegari c. 1999,2000 */ + +/* + * Feb 2002 - added access to variables + * multiple expression support + * new short hand forms for fexpr~ + * now $y or $y1 = $y1[-1] and $y2 = $y2[-1] + * --sdy + * + * July 2002 + * fixed bugs introduced in last changes in store and ET_EQ + * --sdy + * + */ + +/* + * vexp.c -- a variable expression evaluator + * + * This modules implements an expression evaluator using the + * operator-precedence parsing. It transforms an infix expression + * to a prefix stack ready to be evaluated. The expression sysntax + * is close to that of C. There are a few operators that are not + * supported and functions are also recognized. Strings can be + * passed to functions when they are quoted in '"'s. "[]" are implememted + * as an easy way of accessing the content of tables, and the syntax + * table_name[index]. + * Variables (inlets) are specified with the following syntax: $x#, + * where x is either i(integers), f(floats), and s(strings); and # + * is a digit that coresponds to the inlet number. The string variables + * can be used as strings when they are quoted and can also be used as + * table names when they are followed by "[]". + * + * signal vectors have been added to this implementation: + * $v# denotes a signal vector + * $x#[index] is the value of a sample at the index of a the signal vector + * $x# is the shorthand for $x#[0] + * $y[index] is the value of the sample output at the index of a the + * signal output + * "index" for $x#[index] has to have this range (0 <= index < vectorsize) + * "index" for $y[index] has to have this range (0 < index < vectorsize) + */ + +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "vexp.h" +#ifdef MSP +#undef isdigit +#define isdigit(x) (x >= '0' && x <= '9') +#endif + +char *atoif(char *s, long int *value, long int *type); + +static struct ex_ex *ex_lex(struct expr *expr, long int *n); +struct ex_ex *ex_match(struct ex_ex *eptr, long int op); +struct ex_ex *ex_parse(struct expr *expr, struct ex_ex *iptr, + struct ex_ex *optr, long int *argc); +struct ex_ex *ex_eval(struct expr *expr, struct ex_ex *eptr, + struct ex_ex *optr, int i); + +int expr_donew(struct expr *exprr, int ac, t_atom *av); +struct ex_ex *eval_func(struct expr *expr,struct ex_ex *eptr, + struct ex_ex *optr, int i); +struct ex_ex *eval_tab(struct expr *expr, struct ex_ex *eptr, + struct ex_ex *optr, int i); +struct ex_ex *eval_var(struct expr *expr, struct ex_ex *eptr, + struct ex_ex *optr, int i); +struct ex_ex *eval_store(struct expr *expr, struct ex_ex *eptr, + struct ex_ex *optr, int i); +struct ex_ex *eval_sigidx(struct expr *expr, struct ex_ex *eptr, + struct ex_ex *optr, int i); +static int cal_sigidx(struct ex_ex *optr, /* The output value */ + int i, float rem_i, /* integer and fractinal part of index */ + int idx, /* index of current fexpr~ processing */ + int vsize, /* vector size */ + float *curvec, float *prevec); /* current and previous table */ +t_ex_func *find_func(char *s); +void ex_dzdetect(struct expr *expr); + +#define MAX_ARGS 10 +extern t_ex_func ex_funcs[]; + +struct ex_ex nullex; + +void set_tokens (char *s); +int getoken (struct expr *expr, struct ex_ex *eptr); +void ex_print (struct ex_ex *eptr); +#ifdef MSP +void atom_string(t_atom *a, char *buf, unsigned int bufsize); + +void atom_string(t_atom *a, char *buf, unsigned int bufsize) +{ + char tbuf[30]; + switch(a->a_type) + { + case A_SEMI: strcpy(buf, ";"); break; + case A_COMMA: strcpy(buf, ","); break; +#ifdef PD + case A_POINTER: + strcpy(buf, "(pointer)"); + break; +#endif + case A_FLOAT: + sprintf(tbuf, "%g", a->a_w.w_float); + if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf); + else if (a->a_w.w_float < 0) strcpy(buf, "-"); + else strcat(buf, "+"); + break; + case A_LONG: + sprintf(tbuf, "%d", a->a_w.w_long); + if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf); + else if (a->a_w.w_float < 0) strcpy(buf, "-"); + else strcat(buf, "+"); + break; + case A_SYMBOL: + { + char *sp; + unsigned int len; + int quote; + for (sp = a->a_w.w_symbol->s_name, len = 0, quote = 0; *sp; sp++, len++) + if (*sp == ';' || *sp == ',' || *sp == '\\' || + (*sp == '$' && sp == a->a_w.w_symbol->s_name && sp[1] >= '0' + && sp[1] <= '9')) + quote = 1; + if (quote) + { + char *bp = buf, *ep = buf + (bufsize-2); + sp = a->a_w.w_symbol->s_name; + while (bp < ep && *sp) + { + if (*sp == ';' || *sp == ',' || *sp == '\\' || + (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9')) + *bp++ = '\\'; + *bp++ = *sp++; + } + if (*sp) *bp++ = '*'; + *bp = 0; + /* post("quote %s -> %s", a->a_w.w_symbol->s_name, buf); */ + } + else + { + if (len < bufsize-1) strcpy(buf, a->a_w.w_symbol->s_name); + else + { + strncpy(buf, a->a_w.w_symbol->s_name, bufsize - 2); + strcpy(buf + (bufsize - 2), "*"); + } + } + } + break; +#ifdef PD + case A_DOLLAR: + sprintf(buf, "$%d", a->a_w.w_index); + break; + case A_DOLLSYM: + sprintf(buf, "$%s", a->a_w.w_symbol->s_name); + break; +#else /* MAX */ + case A_DOLLAR: + sprintf(buf, "$%s", a->a_w.w_symbol->s_name); + break; +#endif + default: + post("atom_string bug"); + } +} +#endif /* MSP */ +/* + * expr_donew -- create a new "expr" object. + * returns 1 on failure, 0 on success. + */ +int +expr_donew(struct expr *expr, int ac, t_atom *av) +{ + struct ex_ex *list; + struct ex_ex *ret; + long max_node = 0; /* maximum number of nodes needed */ + char *exp_string; + int exp_strlen; + t_binbuf *b; + int i; + + memset(expr->exp_var, 0, MAX_VARS * sizeof (*expr->exp_var)); +#ifdef PD + b = binbuf_new(); + binbuf_add(b, ac, av); + binbuf_gettext(b, &exp_string, &exp_strlen); + +#else /* MSP */ + { + char *buf = getbytes(0), *newbuf; + int length = 0; + char string[250]; + t_atom *ap; + int indx; + + for (ap = av, indx = 0; indx < ac; indx++, ap = ++av) { + int newlength; + if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) && + length && buf[length-1] == ' ') length--; + atom_string(ap, string, 250); + newlength = length + strlen(string) + 1; + if (!(newbuf = t_resizebytes(buf, length, newlength))) break; + buf = newbuf; + strcpy(buf + length, string); + length = newlength; + if (ap->a_type == A_SEMI) buf[length-1] = '\n'; + else buf[length-1] = ' '; + } + + if (length && buf[length-1] == ' ') { + if (newbuf = t_resizebytes(buf, length, length-1)) + { + buf = newbuf; + length--; + } + } + exp_string = buf; + exp_strlen = length; + } +#endif + exp_string = (char *)t_resizebytes(exp_string, exp_strlen,exp_strlen+1); + exp_string[exp_strlen] = 0; + expr->exp_string = exp_string; + expr->exp_str = exp_string; + expr->exp_nexpr = 0; + ret = (struct ex_ex *) 0; + /* + * if ret == 0 it means that we have no expression + * so we let the pass go through to build a single null stack + */ + while (*expr->exp_str || !ret) { + list = ex_lex(expr, &max_node); + if (!list) { /* syntax error */ + goto error; + } + expr->exp_stack[expr->exp_nexpr] = + (struct ex_ex *)fts_malloc(max_node * sizeof (struct ex_ex)); + expr->exp_nexpr++; + ret = ex_match(list, (long)0); + if (!ret) /* syntax error */ + goto error; + ret = ex_parse(expr, + list, expr->exp_stack[expr->exp_nexpr - 1], (long *)0); + if (!ret) + goto error; + } + *ret = nullex; + t_freebytes(exp_string, exp_strlen+1); + return (0); +error: + for (i = 0; i < expr->exp_nexpr; i++) { + fts_free(expr->exp_stack[i]); + expr->exp_stack[i] = 0; + } + expr->exp_nexpr = 0; + if (list) + fts_free(list); + t_freebytes(exp_string, exp_strlen+1); + return (1); +} + +/* + * ex_lex -- This routine is a bit more than a lexical parser since it will + * also do some syntax checking. It reads the string s and will + * return a linked list of struct ex_ex. + * It will also put the number of the nodes in *n. + */ +struct ex_ex * +ex_lex(struct expr *expr, long int *n) +{ + struct ex_ex *list_arr; + struct ex_ex *exptr; + long non = 0; /* number of nodes */ + long maxnode = 0; + + list_arr = (struct ex_ex *)fts_malloc(sizeof (struct ex_ex) * MINODES); + if (! list_arr) { + post("ex_lex: no mem\n"); + return ((struct ex_ex *)0); + } + exptr = list_arr; + maxnode = MINODES; + + while (8) + { + if (non >= maxnode) { + maxnode += MINODES; + + list_arr = fts_realloc((void *)list_arr, + sizeof (struct ex_ex) * maxnode); + if (!list_arr) { + post("ex_lex: no mem\n"); + return ((struct ex_ex *)0); + } + exptr = &(list_arr)[non]; + } + + if (getoken(expr, exptr)) { + fts_free(list_arr); + return ((struct ex_ex *)0); + } + non++; + + if (!exptr->ex_type) + break; + + exptr++; + } + *n = non; + + return list_arr; +} + +/* + * ex_match -- this routine walks through the eptr and matches the + * perentheses and brackets, it also converts the function + * names to a pointer to the describing structure of the + * specified function + */ +/* operator to match */ +struct ex_ex * +ex_match(struct ex_ex *eptr, long int op) +{ + int firstone = 1; + struct ex_ex *ret; + t_ex_func *fun; + + for (; 8; eptr++, firstone = 0) { + switch (eptr->ex_type) { + case 0: + if (!op) + return (eptr); + post("expr syntax error: an open %s not matched\n", + op == OP_RP ? "parenthesis" : "bracket"); + return (exNULL); + case ET_INT: + case ET_FLT: + case ET_II: + case ET_FI: + case ET_SI: + case ET_VI: + case ET_SYM: + case ET_VSYM: + continue; + case ET_YO: + if (eptr[1].ex_type != ET_OP || eptr[1].ex_op != OP_LB) + eptr->ex_type = ET_YOM1; + continue; + case ET_XI: + if (eptr[1].ex_type != ET_OP || eptr[1].ex_op != OP_LB) + eptr->ex_type = ET_XI0; + continue; + case ET_TBL: + case ET_FUNC: + case ET_LP: + /* CHANGE + case ET_RP: + */ + case ET_LB: + /* CHANGE + case ET_RB: + */ + post("ex_match: unexpected type, %ld\n", eptr->ex_type); + return (exNULL); + case ET_OP: + if (op == eptr->ex_op) + return (eptr); + /* + * if we are looking for a right peranthesis + * or a right bracket and find the other kind, + * it has to be a syntax error + */ + if ((eptr->ex_op == OP_RP && op == OP_RB) || + (eptr->ex_op == OP_RB && op == OP_RP)) { + post("expr syntax error: prenthesis or brackets not matched\n"); + return (exNULL); + } + /* + * Up to now we have marked the unary minuses as + * subrtacts. Any minus that is the first one in + * chain or is preceeded by anything except ')' and + * ']' is a unary minus. + */ + if (eptr->ex_op == OP_SUB) { + ret = eptr - 1; + if (firstone || (ret->ex_type == ET_OP && + ret->ex_op != OP_RB && ret->ex_op != OP_RP)) + eptr->ex_op = OP_UMINUS; + } else if (eptr->ex_op == OP_LP) { + ret = ex_match(eptr + 1, OP_RP); + if (!ret) + return (ret); + eptr->ex_type = ET_LP; + eptr->ex_ptr = (char *) ret; + eptr = ret; + } else if (eptr->ex_op == OP_LB) { + ret = ex_match(eptr + 1, OP_RB); + if (!ret) + return (ret); + eptr->ex_type = ET_LB; + eptr->ex_ptr = (char *) ret; + eptr = ret; + } + continue; + case ET_STR: + if (eptr[1].ex_op == OP_LB) { + char *tmp; + + eptr->ex_type = ET_TBL; + tmp = eptr->ex_ptr; + if (ex_getsym(tmp, (t_symbol **)&(eptr->ex_ptr))) { + post("expr: syntax error: problms with ex_getsym\n"); + return (exNULL); + } + fts_free((void *)tmp); + } else if (eptr[1].ex_op == OP_LP) { + fun = find_func(eptr->ex_ptr); + if (!fun) { + post( + "expr: error: function %s not found\n", + eptr->ex_ptr); + return (exNULL); + } + eptr->ex_type = ET_FUNC; + eptr->ex_ptr = (char *) fun; + } else { + char *tmp; + + if (eptr[1].ex_type && eptr[1].ex_type!=ET_OP){ + post("expr: syntax error: bad string '%s'\n", eptr->ex_ptr); + return (exNULL); + } + /* it is a variable */ + eptr->ex_type = ET_VAR; + tmp = eptr->ex_ptr; + if (ex_getsym(tmp, + (t_symbol **)&(eptr->ex_ptr))) { + post("expr: variable '%s' not found",tmp); + return (exNULL); + } + } + continue; + default: + post("ex_match: bad type\n"); + return (exNULL); + } + } + /* NOTREACHED */ +} + +/* + * ex_parse -- This function if called when we have already done some + * parsing on the expression, and we have already matched + * our brackets and parenthesis. The main job of this + * function is to convert the infix expression to the + * prefix form. + * First we find the operator with the lowest precedence and + * put it on the stack ('optr', it is really just an array), then + * we call ourself (ex_parse()), on its arguments (unary operators + * only have one operator.) + * When "argc" is set it means that we are parsing the arguments + * of a function and we will increment *argc anytime we find + * a a segment that can qualify as an argument (counting commas). + * + * returns 0 on syntax error + */ +/* number of argument separated by comma */ +struct ex_ex * +ex_parse(struct expr *x, struct ex_ex *iptr, struct ex_ex *optr, long int *argc) +{ + struct ex_ex *eptr; + struct ex_ex *lowpre = 0; /* pointer to the lowest precedence */ + struct ex_ex savex; + long pre = HI_PRE; + long count; + + if (!iptr) { + post("ex_parse: input is null, iptr = 0x%lx\n", iptr); + return (exNULL); + } + if (!iptr->ex_type) + return (exNULL); + + /* + * the following loop finds the lowest precedence operator in the + * the input token list, comma is explicitly checked here since + * that is a special operator and is only legal in functions + */ + for (eptr = iptr, count = 0; eptr->ex_type; eptr++, count++) + switch (eptr->ex_type) { + case ET_SYM: + case ET_VSYM: + if (!argc) { + post("expr: syntax error: symbols allowed for functions only\n"); + ex_print(eptr); + return (exNULL); + } + case ET_INT: + case ET_FLT: + case ET_II: + case ET_FI: + case ET_XI0: + case ET_YOM1: + case ET_VI: + case ET_VAR: + if (!count && !eptr[1].ex_type) { + *optr++ = *eptr; + return (optr); + } + break; + case ET_XI: + case ET_YO: + case ET_SI: + case ET_TBL: + if (eptr[1].ex_type != ET_LB) { + post("expr: syntax error: brackets missing\n"); + ex_print(eptr); + return (exNULL); + } + /* if this table is the only token, parse the table */ + if (!count && + !((struct ex_ex *) eptr[1].ex_ptr)[1].ex_type) { + savex = *((struct ex_ex *) eptr[1].ex_ptr); + *((struct ex_ex *) eptr[1].ex_ptr) = nullex; + *optr++ = *eptr; + lowpre = ex_parse(x, &eptr[2], optr, (long *)0); + *((struct ex_ex *) eptr[1].ex_ptr) = savex; + return(lowpre); + } + eptr = (struct ex_ex *) eptr[1].ex_ptr; + break; + case ET_OP: + if (eptr->ex_op == OP_COMMA) { + if (!argc || !count || !eptr[1].ex_type) { + post("expr: syntax error: illegal comma\n"); + ex_print(eptr[1].ex_type ? eptr : iptr); + return (exNULL); + } + } + if (!eptr[1].ex_type) { + post("expr: syntax error: missing operand\n"); + ex_print(iptr); + return (exNULL); + } + if ((eptr->ex_op & PRE_MASK) <= pre) { + pre = eptr->ex_op & PRE_MASK; + lowpre = eptr; + } + break; + case ET_FUNC: + if (eptr[1].ex_type != ET_LP) { + post("expr: ex_parse: no parenthesis\n"); + return (exNULL); + } + /* if this function is the only token, parse it */ + if (!count && + !((struct ex_ex *) eptr[1].ex_ptr)[1].ex_type) { + long ac; + + if (eptr[1].ex_ptr == (char *) &eptr[2]) { + post("expr: syntax error: missing argument\n"); + ex_print(eptr); + return (exNULL); + } + ac = 0; + savex = *((struct ex_ex *) eptr[1].ex_ptr); + *((struct ex_ex *) eptr[1].ex_ptr) = nullex; + *optr++ = *eptr; + lowpre = ex_parse(x, &eptr[2], optr, &ac); + if (!lowpre) + return (exNULL); + ac++; + if (ac != + ((t_ex_func *)eptr->ex_ptr)->f_argc){ + post("expr: syntax error: function '%s' needs %ld arguments\n", + ((t_ex_func *)eptr->ex_ptr)->f_name, + ((t_ex_func *)eptr->ex_ptr)->f_argc); + return (exNULL); + } + *((struct ex_ex *) eptr[1].ex_ptr) = savex; + return (lowpre); + } + eptr = (struct ex_ex *) eptr[1].ex_ptr; + break; + case ET_LP: + case ET_LB: + if (!count && + !((struct ex_ex *) eptr->ex_ptr)[1].ex_type) { + if (eptr->ex_ptr == (char *)(&eptr[1])) { + post("expr: syntax error: empty '%s'\n", + eptr->ex_type==ET_LP?"()":"[]"); + ex_print(eptr); + return (exNULL); + } + savex = *((struct ex_ex *) eptr->ex_ptr); + *((struct ex_ex *) eptr->ex_ptr) = nullex; + lowpre = ex_parse(x, &eptr[1], optr, (long *)0); + *((struct ex_ex *) eptr->ex_ptr) = savex; + return (lowpre); + } + eptr = (struct ex_ex *)eptr->ex_ptr; + break; + case ET_STR: + default: + ex_print(eptr); + post("expr: ex_parse: type = 0x%lx\n", eptr->ex_type); + return (exNULL); + } + + if (pre == HI_PRE) { + post("expr: syntax error: missing operation\n"); + ex_print(iptr); + return (exNULL); + } + if (count < 2) { + post("expr: syntax error: mission operand\n"); + ex_print(iptr); + return (exNULL); + } + if (count == 2) { + if (lowpre != iptr) { + post("expr: ex_parse: unary operator should be first\n"); + return (exNULL); + } + if (!unary_op(lowpre->ex_op)) { + post("expr: syntax error: not a uniary operator\n"); + ex_print(iptr); + return (exNULL); + } + *optr++ = *lowpre; + eptr = ex_parse(x, &lowpre[1], optr, argc); + return (eptr); + } + if (lowpre == iptr) { + post("expr: syntax error: mission operand\n"); + ex_print(iptr); + return (exNULL); + } + savex = *lowpre; + *lowpre = nullex; + if (savex.ex_op != OP_COMMA) + *optr++ = savex; + else + (*argc)++; + eptr = ex_parse(x, iptr, optr, argc); + if (eptr) { + eptr = ex_parse(x, &lowpre[1], eptr, argc); + *lowpre = savex; + } + return (eptr); +} + +/* + * this is the devide zero check for a a non devide operator + */ +#define DZC(ARG1,OPR,ARG2) (ARG1 OPR ARG2) + +#define EVAL(OPR); \ +eptr = ex_eval(expr, ex_eval(expr, eptr, &left, idx), &right, idx); \ +switch (left.ex_type) { \ +case ET_INT: \ + switch(right.ex_type) { \ + case ET_INT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = (float)DZC(left.ex_int, OPR, right.ex_int); \ + for (j = 0; j < expr->exp_vsize; j++) \ + *op++ = scalar; \ + } else { \ + optr->ex_type = ET_INT; \ + optr->ex_int = DZC(left.ex_int, OPR, right.ex_int); \ + } \ + break; \ + case ET_FLT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = DZC(((float)left.ex_int), OPR, right.ex_flt);\ + for (j = 0; j < expr->exp_vsize; j++) \ + *op++ = scalar; \ + } else { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = DZC(((float)left.ex_int), OPR, \ + right.ex_flt); \ + } \ + break; \ + case ET_VEC: \ + case ET_VI: \ + if (optr->ex_type != ET_VEC) { \ + if (optr->ex_type == ET_VI) { \ + post("expr~: Int. error %d", __LINE__); \ + abort(); \ + } \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float)*expr->exp_vsize); \ + } \ + scalar = left.ex_int; \ + rp = right.ex_vec; \ + op = optr->ex_vec; \ + for (i = 0; i < expr->exp_vsize; i++) { \ + *op++ = DZC (scalar, OPR, *rp); \ + rp++; \ + } \ + break; \ + case ET_SYM: \ + default: \ + post_error((fts_object_t *) expr, \ + "expr: ex_eval(%d): bad right type %ld\n", \ + __LINE__, right.ex_type); \ + nullret = 1; \ + } \ + break; \ +case ET_FLT: \ + switch(right.ex_type) { \ + case ET_INT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = DZC((float) left.ex_flt, OPR, right.ex_int); \ + for (j = 0; j < expr->exp_vsize; j++) \ + *op++ = scalar; \ + } else { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = DZC(left.ex_flt, OPR, right.ex_int); \ + } \ + break; \ + case ET_FLT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = DZC(left.ex_flt, OPR, right.ex_flt); \ + for (j = 0; j < expr->exp_vsize; j++) \ + *op++ = scalar; \ + } else { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt= DZC(left.ex_flt, OPR, right.ex_flt); \ + } \ + break; \ + case ET_VEC: \ + case ET_VI: \ + if (optr->ex_type != ET_VEC) { \ + if (optr->ex_type == ET_VI) { \ + post("expr~: Int. error %d", __LINE__); \ + abort(); \ + } \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float)*expr->exp_vsize); \ + } \ + scalar = left.ex_flt; \ + rp = right.ex_vec; \ + op = optr->ex_vec; \ + for (i = 0; i < expr->exp_vsize; i++) { \ + *op++ = DZC(scalar, OPR, *rp); \ + rp++; \ + } \ + break; \ + case ET_SYM: \ + default: \ + post_error((fts_object_t *) expr, \ + "expr: ex_eval(%d): bad right type %ld\n", \ + __LINE__, right.ex_type); \ + nullret = 1; \ + } \ + break; \ +case ET_VEC: \ +case ET_VI: \ + if (optr->ex_type != ET_VEC) { \ + if (optr->ex_type == ET_VI) { \ + post("expr~: Int. error %d", __LINE__); \ + abort(); \ + } \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float)*expr->exp_vsize); \ + } \ + op = optr->ex_vec; \ + lp = left.ex_vec; \ + switch(right.ex_type) { \ + case ET_INT: \ + scalar = right.ex_int; \ + for (i = 0; i < expr->exp_vsize; i++) { \ + *op++ = DZC(*lp, OPR, scalar); \ + lp++; \ + } \ + break; \ + case ET_FLT: \ + scalar = right.ex_flt; \ + for (i = 0; i < expr->exp_vsize; i++) { \ + *op++ = DZC(*lp, OPR, scalar); \ + lp++; \ + } \ + break; \ + case ET_VEC: \ + case ET_VI: \ + rp = right.ex_vec; \ + for (i = 0; i < expr->exp_vsize; i++) { \ + /* \ + * on a RISC processor one could copy \ + * 8 times in each round to get a considerable \ + * improvement \ + */ \ + *op++ = DZC(*lp, OPR, *rp); \ + rp++; lp++; \ + } \ + break; \ + case ET_SYM: \ + default: \ + post_error((fts_object_t *) expr, \ + "expr: ex_eval(%d): bad right type %ld\n", \ + __LINE__, right.ex_type); \ + nullret = 1; \ + } \ + break; \ +case ET_SYM: \ +default: \ + post_error((fts_object_t *) expr, \ + "expr: ex_eval(%d): bad left type %ld\n", \ + __LINE__, left.ex_type); \ +} \ +break; + +/* + * evaluate a unary operator, TYPE is applied to float operands + */ +#define EVAL_UNARY(OPR, TYPE) \ + eptr = ex_eval(expr, eptr, &left, idx); \ + switch(left.ex_type) { \ + case ET_INT: \ + if (optr->ex_type == ET_VEC) { \ + ex_mkvector(optr->ex_vec,(float)(OPR left.ex_int),\ + expr->exp_vsize);\ + break; \ + } \ + optr->ex_type = ET_INT; \ + optr->ex_int = OPR left.ex_int; \ + break; \ + case ET_FLT: \ + if (optr->ex_type == ET_VEC) { \ + ex_mkvector(optr->ex_vec, OPR (TYPE left.ex_flt),\ + expr->exp_vsize);\ + break; \ + } \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = OPR (TYPE left.ex_flt); \ + break; \ + case ET_VI: \ + case ET_VEC: \ + j = expr->exp_vsize; \ + if (optr->ex_type != ET_VEC) { \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float)*expr->exp_vsize); \ + } \ + op = optr->ex_vec; \ + lp = left.ex_vec; \ + j = expr->exp_vsize; \ + for (i = 0; i < j; i++) \ + *op++ = OPR (TYPE *lp++); \ + break; \ + default: \ + post_error((fts_object_t *) expr, \ + "expr: ex_eval(%d): bad left type %ld\n", \ + __LINE__, left.ex_type); \ + nullret++; \ + } \ + break; + +void +ex_mkvector(t_float *fp, t_float x, int size) +{ + while (size--) + *fp++ = x; +} + +/* + * ex_dzdetect -- divide by zero detected + */ +void +ex_dzdetect(struct expr *expr) +{ + char *etype; + + if (!expr->exp_error & EE_DZ) { + if (IS_EXPR(expr)) + etype = "expr"; + else if (IS_EXPR_TILDE(expr)) + etype = "expr~"; + else if (IS_FEXPR_TILDE(expr)) + etype = "fexpr~"; + else { + post ("expr -- ex_dzdetect internal error"); + etype = ""; + } + post ("%s divide by zero detected", etype); + expr->exp_error |= EE_DZ; + } +} + + +/* + * ex_eval -- evaluate the array of prefix expression + * ex_eval returns the pointer to the first unevaluated node + * in the array. This is a recursive routine. + */ + +/* SDY +all the returns in this function need to be changed so that the code +ends up at the end to check for newly allocated right and left vectors which +need to be freed + +look into the variable nullret +*/ +struct ex_ex * +ex_eval(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx) +/* the expr object data pointer */ +/* the operation stack */ +/* the result pointer */ +/* the sample numnber processed for fexpr~ */ +{ + int i, j; + t_float *lp, *rp, *op; /* left, right, and out pointer to vectors */ + t_float scalar; + int nullret = 0; /* did we have an error */ + struct ex_ex left, right; /* left and right operands */ + + left.ex_type = 0; + left.ex_int = 0; + right.ex_type = 0; + right.ex_int = 0; + + if (!eptr) + return (exNULL); + switch (eptr->ex_type) { + case ET_INT: + if (optr->ex_type == ET_VEC) + ex_mkvector(optr->ex_vec, (float) eptr->ex_int, + expr->exp_vsize); + else + *optr = *eptr; + return (++eptr); + + case ET_FLT: + + if (optr->ex_type == ET_VEC) + ex_mkvector(optr->ex_vec, eptr->ex_flt, expr->exp_vsize); + else + *optr = *eptr; + return (++eptr); + + case ET_SYM: + if (optr->ex_type == ET_VEC) { + post_error((fts_object_t *) expr, + "expr: ex_eval: cannot turn string to vector\n"); + return (exNULL); + } + *optr = *eptr; + return (++eptr); + case ET_II: + if (eptr->ex_int == -1) { + post_error((fts_object_t *) expr, + "expr: ex_eval: inlet number not set\n"); + return (exNULL); + } + if (optr->ex_type == ET_VEC) { + ex_mkvector(optr->ex_vec, + (t_float)expr->exp_var[eptr->ex_int].ex_int, + expr->exp_vsize); + } else { + optr->ex_type = ET_INT; + optr->ex_int = expr->exp_var[eptr->ex_int].ex_int; + } + return (++eptr); + case ET_FI: + if (eptr->ex_int == -1) { + post_error((fts_object_t *) expr, + "expr: ex_eval: inlet number not set\n"); + return (exNULL); + } + if (optr->ex_type == ET_VEC) { + ex_mkvector(optr->ex_vec, + expr->exp_var[eptr->ex_int].ex_flt, expr->exp_vsize); + } else { + optr->ex_type = ET_FLT; + optr->ex_flt = expr->exp_var[eptr->ex_int].ex_flt; + } + return (++eptr); + + case ET_VSYM: + if (optr->ex_type == ET_VEC) { + post_error((fts_object_t *) expr, + "expr: IntErr. vsym in for vec out\n"); + return (exNULL); + } + if (eptr->ex_int == -1) { + post_error((fts_object_t *) expr, + "expr: ex_eval: inlet number not set\n"); + return (exNULL); + } + optr->ex_type = ET_SYM; + optr->ex_ptr = expr->exp_var[eptr->ex_int].ex_ptr; + return(++eptr); + + case ET_VI: + if (optr->ex_type != ET_VEC) + *optr = expr->exp_var[eptr->ex_int]; + else if (optr->ex_vec != expr->exp_var[eptr->ex_int].ex_vec) + memcpy(optr->ex_vec, expr->exp_var[eptr->ex_int].ex_vec, + expr->exp_vsize * sizeof (t_float)); + return(++eptr); + case ET_VEC: + if (optr->ex_type != ET_VEC) { + optr->ex_type = ET_VEC; + optr->ex_vec = eptr->ex_vec; + eptr->ex_type = ET_INT; + eptr->ex_int = 0; + } else if (optr->ex_vec != eptr->ex_vec) { + memcpy(optr->ex_vec, eptr->ex_vec, + expr->exp_vsize * sizeof (t_float)); +/* do we need to free here? or can we free higher up */ +/* SDY the next lines do not make sense */ +post("calling fts_free\n"); +abort(); + fts_free(optr->ex_vec); + optr->ex_type = ET_INT; + eptr->ex_int = 0; + } else { /* this should not happen */ + post("expr int. error, optr->ex_vec = %d",optr->ex_vec); + abort(); + } + return(++eptr); + case ET_XI0: + /* short hand for $x?[0] */ + + /* SDY delete the following check */ + if (!IS_FEXPR_TILDE(expr) || optr->ex_type==ET_VEC) { + post("%d:exp->exp_flags = %d", __LINE__,expr->exp_flags); + abort(); + } + optr->ex_type = ET_FLT; + optr->ex_flt = expr->exp_var[eptr->ex_int].ex_vec[idx]; + return(++eptr); + case ET_YOM1: + /* + * short hand for $y?[-1] + * if we are calculating the first sample of the vector + * we need to look at the previous results buffer + */ + optr->ex_type = ET_FLT; + if (idx == 0) + optr->ex_flt = + expr->exp_p_res[eptr->ex_int][expr->exp_vsize - 1]; + else + optr->ex_flt=expr->exp_tmpres[eptr->ex_int][idx-1]; + return(++eptr); + + case ET_YO: + case ET_XI: + /* SDY delete the following */ + if (!IS_FEXPR_TILDE(expr) || optr->ex_type==ET_VEC) { + post("%d:expr->exp_flags = %d", __LINE__,expr->exp_flags); + abort(); + } + return (eval_sigidx(expr, eptr, optr, idx)); + + case ET_TBL: + case ET_SI: + return (eval_tab(expr, eptr, optr, idx)); + case ET_FUNC: + return (eval_func(expr, eptr, optr, idx)); + case ET_VAR: + return (eval_var(expr, eptr, optr, idx)); + case ET_OP: + break; + case ET_STR: + case ET_LP: + case ET_LB: + default: + post_error((fts_object_t *) expr, + "expr: ex_eval: unexpected type %d\n", eptr->ex_type); + return (exNULL); + } + if (!eptr[1].ex_type) { + post_error((fts_object_t *) expr, + "expr: ex_eval: not enough nodes 1\n"); + return (exNULL); + } + if (!unary_op(eptr->ex_op) && !eptr[2].ex_type) { + post_error((fts_object_t *) expr, + "expr: ex_eval: not enough nodes 2\n"); + return (exNULL); + } + + switch((eptr++)->ex_op) { + case OP_STORE: + return (eval_store(expr, eptr, optr, idx)); + case OP_NOT: + EVAL_UNARY(!, +); + case OP_NEG: + EVAL_UNARY(~, (long)); + case OP_UMINUS: + EVAL_UNARY(-, +); + case OP_MUL: + EVAL(*); + case OP_ADD: + EVAL(+); + case OP_SUB: + EVAL(-); + case OP_LT: + EVAL(<); + case OP_LE: + EVAL(<=); + case OP_GT: + EVAL(>); + case OP_GE: + EVAL(>=); + case OP_EQ: + EVAL(==); + case OP_NE: + EVAL(!=); +/* + * following operators convert their argument to integer + */ +#undef DZC +#define DZC(ARG1,OPR,ARG2) (((int)ARG1) OPR ((int)ARG2)) + case OP_SL: + EVAL(<<); + case OP_SR: + EVAL(>>); + case OP_AND: + EVAL(&); + case OP_XOR: + EVAL(^); + case OP_OR: + EVAL(|); + case OP_LAND: + EVAL(&&); + case OP_LOR: + EVAL(||); +/* + * for modulo we need to convert to integer and check for divide by zero + */ +#undef DZC +#define DZC(ARG1,OPR,ARG2) (((ARG2)?(((int)ARG1) OPR ((int)ARG2)) \ + : (ex_dzdetect(expr),0))) + case OP_MOD: + EVAL(%); +/* + * define the divide by zero check for divide + */ +#undef DZC +#define DZC(ARG1,OPR,ARG2) (((ARG2)?(ARG1 OPR ARG2):(ex_dzdetect(expr),0))) + case OP_DIV: + EVAL(/); + case OP_LP: + case OP_RP: + case OP_LB: + case OP_RB: + case OP_COMMA: + case OP_SEMI: + default: + post_error((fts_object_t *) expr, "expr: ex_print: bad op 0x%x\n", eptr->ex_op); + return (exNULL); + } + + + /* + * the left and right nodes could have been transformed to vectors + * down the chain + */ + if (left.ex_type == ET_VEC) + fts_free(left.ex_vec); + if (right.ex_type == ET_VEC) + fts_free(right.ex_vec); + if (nullret) + return (exNULL); + else + return (eptr); +} + +/* + * eval_func -- evaluate a function, call ex_eval() on all the arguments + * so that all of them are terminal nodes. The call the + * appropriate function + */ +struct ex_ex * +eval_func(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx) +/* the expr object data pointer */ +/* the operation stack */ +/* the result pointer */ +{ + int i; + struct ex_ex args[MAX_ARGS]; + t_ex_func *f; + + f = (t_ex_func *)(eptr++)->ex_ptr; + if (!f || !f->f_name) { + return (exNULL); + } + if (f->f_argc > MAX_ARGS) { + post_error((fts_object_t *) expr, "expr: eval_func: asking too many arguments\n"); + return (exNULL); + } + + for (i = 0; i < f->f_argc; i++) { + args[i].ex_type = 0; + args[i].ex_int = 0; + eptr = ex_eval(expr, eptr, &args[i], idx); + } + (*f->f_func)(expr, f->f_argc, args, optr); + for (i = 0; i < f->f_argc; i++) { + if (args[i].ex_type == ET_VEC) + fts_free(args[i].ex_vec); + } + return (eptr); +} + + +/* + * eval_store -- evaluate the '=' operator, + * make sure the first operator is a legal left operator + * and call ex_eval on the right operator + */ +struct ex_ex * +eval_store(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx) +/* the expr object data pointer */ +/* the operation stack */ +/* the result pointer */ +{ + struct ex_ex arg; + int isvalue; + char *tbl = (char *) 0; + char *var = (char *) 0; + int badleft = 0; + +post("store called\n"); +ex_print(eptr); +eptr = ex_eval(expr, ++eptr, optr, idx); +return (eptr); + +#ifdef notdef /* SDY */ + arg.ex_type = ET_INT; + arg.ex_int = 0; + if (eptr->ex_type == ET_VAR) { + var = (char *) eptr->ex_ptr; + + eptr = ex_eval(expr, ++eptr, &arg, idx); + (void)max_ex_var_store(expr, (t_symbol *)var, &arg, optr); + if (arg.ex_type == ET_VEC) + fts_free(arg.ex_vec); + } + + + if (eptr->ex_type == ET_SI) { + eptr++; + if (eptr->ex_type = + } + + /* the left operator should either be a value or a array member */ + switch (eptr->ex_type) { + case ET_SI: + if ((eptr + 1)->ex_type == OP_LB) { + } + if (!expr->exp_var[eptr->ex_int].ex_ptr) { + if (!(expr->exp_error & EE_NOTABLE)) { + post("expr: syntax error: no string for inlet %d", eptr->ex_int + 1); + post("expr: No more table errors will be reported"); + post("expr: till the next reset"); + expr->exp_error |= EE_NOTABLE; + } + badleft++; + } else + tbl = (char *) expr->exp_var[eptr->ex_int].ex_ptr; + break; + case ET_TBL: + } +#endif /* SDY */ +} + +/* + * eval_tab -- evaluate a table operation + */ +struct ex_ex * +eval_tab(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx) +/* the expr object data pointer */ +/* the operation stack */ +/* the result pointer */ +{ + struct ex_ex arg; + char *tbl = (char *) 0; + int notable = 0; + + if (eptr->ex_type == ET_SI) { + if (!expr->exp_var[eptr->ex_int].ex_ptr) { +/* SDY post_error() does not work in MAX/MSP yet + post_error((fts_object_t *) expr, + "expr: syntax error: no string for inlet %d\n", eptr->ex_int + 1); +*/ + if (!(expr->exp_error & EE_NOTABLE)) { + post("expr: syntax error: no string for inlet %d", eptr->ex_int + 1); + post("expr: No more table errors will be reported"); + post("expr: till the next reset"); + expr->exp_error |= EE_NOTABLE; + } + notable++; + } else + tbl = (char *) expr->exp_var[eptr->ex_int].ex_ptr; + } else if (eptr->ex_type == ET_TBL) + tbl = (char *) eptr->ex_ptr; + else { + post_error((fts_object_t *) expr, "expr: eval_tbl: bad type %ld\n", eptr->ex_type); + notable++; + + } + arg.ex_type = 0; + arg.ex_int = 0; + eptr = ex_eval(expr, ++eptr, &arg, idx); + + optr->ex_type = ET_INT; + optr->ex_int = 0; + if (!notable) + (void)max_ex_tab(expr, (t_symbol *)tbl, &arg, optr); + if (arg.ex_type == ET_VEC) + fts_free(arg.ex_vec); + return (eptr); +} + +/* + * eval_var -- evaluate a variable + */ +struct ex_ex * +eval_var(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx) +/* the expr object data pointer */ +/* the operation stack */ +/* the result pointer */ +{ + struct ex_ex arg; + char *var = (char *) 0; + int novar = 0; + + if (eptr->ex_type == ET_SI) { + if (!expr->exp_var[eptr->ex_int].ex_ptr) { +/* SDY post_error() does not work in MAX/MSP yet +post_error((fts_object_t *) expr, +"expr: syntax error: no string for inlet %d\n", eptr->ex_int + 1); +*/ + if (!(expr->exp_error & EE_NOVAR)) { + post("expr: syntax error: no string for inlet %d", eptr->ex_int + 1); + post("expr: No more table errors will be reported"); + post("expr: till the next reset"); + expr->exp_error |= EE_NOVAR; + } + novar++; + } else + var = (char *) expr->exp_var[eptr->ex_int].ex_ptr; + } else if (eptr->ex_type == ET_VAR) + var = (char *) eptr->ex_ptr; + else { + post_error((fts_object_t *) expr, "expr: eval_tbl: bad type %ld\n", eptr->ex_type); + novar++; + + } + + optr->ex_type = ET_INT; + optr->ex_int = 0; + if (!novar) + (void)max_ex_var(expr, (t_symbol *)var, optr); + return (++eptr); +} + +/* + * eval_sigidx -- evaluate the value of an indexed signal for fexpr~ + */ +struct ex_ex * +eval_sigidx(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx) +/* the expr object data pointer */ +/* the operation stack */ +/* the result pointer */ +/* the index */ +{ + struct ex_ex arg; + struct ex_ex *reteptr; + int i = 0, j = 0; + float fi = 0, /* index in float */ + rem_i = 0; /* remains of the float */ + char *tbl; + + arg.ex_type = 0; + arg.ex_int = 0; + reteptr = ex_eval(expr, eptr + 1, &arg, idx); + if (arg.ex_type == ET_FLT) { + fi = arg.ex_flt; /* float index */ + i = (int) arg.ex_flt; /* integer index */ + rem_i = arg.ex_flt - i; /* remains of integer */ + } else if (arg.ex_type == ET_INT) { + fi = arg.ex_int; /* float index */ + i = arg.ex_int; + rem_i = 0; + } else { + post("eval_sigidx: bad res type (%d)", arg.ex_type); + } + optr->ex_type = ET_FLT; + /* + * indexing an input vector + */ + if (eptr->ex_type == ET_XI) { + if (fi > 0) { + if (!(expr->exp_error & EE_BI_INPUT)) { + expr->exp_error |= EE_BI_INPUT; + post("expr: input vector index > 0, (vector x%d[%f])", + eptr->ex_int + 1, i + rem_i); + post("fexpr~: index assumed to be = 0"); + post("fexpr~: no error report till next reset"); + ex_print(eptr); + } + /* just replace it with zero */ + i = 0; + rem_i = 0; + } + if (cal_sigidx(optr, i, rem_i, idx, expr->exp_vsize, + expr->exp_var[eptr->ex_int].ex_vec, + expr->exp_p_var[eptr->ex_int])) { + if (!(expr->exp_error & EE_BI_INPUT)) { + expr->exp_error |= EE_BI_INPUT; + post("expr: input vector index < -VectorSize, (vector x%d[%f])", eptr->ex_int + 1, fi); + ex_print(eptr); + post("fexpr~: index assumed to be = -%d", + expr->exp_vsize); + post("fexpr~: no error report till next reset"); + } + } + + /* + * indexing an output vector + */ + } else if (eptr->ex_type == ET_YO) { + /* for output vectors index of zero is not legal */ + if (fi >= 0) { + if (!(expr->exp_error & EE_BI_OUTPUT)) { + expr->exp_error |= EE_BI_OUTPUT; + post("fexpr~: bad output index, (%f)", fi); + ex_print(eptr); + post("fexpr~: no error report till next reset"); + post("fexpr~: index assumed to be = -1"); + } + i = -1; + } + if (eptr->ex_int >= expr->exp_nexpr) { + post("fexpr~: $y%d illegal: not that many exprs", + eptr->ex_int); + optr->ex_flt = 0; + return (reteptr); + } + if (cal_sigidx(optr, i, rem_i, idx, expr->exp_vsize, + expr->exp_tmpres[eptr->ex_int], + expr->exp_p_res[eptr->ex_int])) { + if (!(expr->exp_error & EE_BI_OUTPUT)) { + expr->exp_error |= EE_BI_OUTPUT; + post("fexpr~: bad output index, (%f)", fi); + ex_print(eptr); + post("fexpr~: index assumed to be = -%d", + expr->exp_vsize); + } + } + } else { + optr->ex_flt = 0; + post("fexpr~:eval_sigidx: internal error - unknown vector (%d)", + eptr->ex_type); + } + return (reteptr); +} + +/* + * cal_sigidx -- given two tables (one current one previous) calculate an + * evaluation of a float index into the vectors by linear + * interpolation + * return 0 on success, 1 on failure (index out of bound) + */ +static int +cal_sigidx(struct ex_ex *optr, /* The output value */ + int i, float rem_i, /* integer and fractinal part of index */ + int idx, /* index of current fexpr~ processing */ + int vsize, /* vector size */ + float *curvec, float *prevec) /* current and previous table */ +{ + int n; + + n = i + idx; + if (n > 0) { + /* from the curvec */ + if (rem_i) + optr->ex_flt = curvec[n] + + rem_i * (curvec[n] - curvec[n - 1]); + else + optr->ex_flt = curvec[n]; + return (0); + } + if (n == 0) { + /* + * this is the case that the remaining float + * is between two tables + */ + if (rem_i) + optr->ex_flt = *curvec + + rem_i * (*curvec - prevec[vsize - 1]); + else + optr->ex_flt = *curvec; + return (0); + } + /* find the index in the saved buffer */ + n = vsize + n; + if (n > 0) { + if (rem_i) + optr->ex_flt = prevec[n] + + rem_i * (prevec[n] - prevec[n - 1]); + else + optr->ex_flt = prevec[n]; + return (0); + } + /* out of bound */ + optr->ex_flt = *prevec; + return (1); +} + +/* + * getoken -- return 1 on syntax error otherwise 0 + */ +int +getoken(struct expr *expr, struct ex_ex *eptr) +{ + char *p; + long i; + + + if (!expr->exp_str) { + post("expr: getoken: expression string not set\n"); + return (0); + } +retry: + if (!*expr->exp_str) { + eptr->ex_type = 0; + eptr->ex_int = 0; + return (0); + } + if (*expr->exp_str == ';') { + expr->exp_str++; + eptr->ex_type = 0; + eptr->ex_int = 0; + return (0); + } + eptr->ex_type = ET_OP; + switch (*expr->exp_str++) { + case '\\': + case ' ': + case '\t': + goto retry; + case ';': + post("expr: syntax error: ';' not implemented\n"); + return (1); + case ',': + eptr->ex_op = OP_COMMA; + break; + case '(': + eptr->ex_op = OP_LP; + break; + case ')': + eptr->ex_op = OP_RP; + break; + case ']': + eptr->ex_op = OP_RB; + break; + case '~': + eptr->ex_op = OP_NEG; + break; + /* we will take care of unary minus later */ + case '*': + eptr->ex_op = OP_MUL; + break; + case '/': + eptr->ex_op = OP_DIV; + break; + case '%': + eptr->ex_op = OP_MOD; + break; + case '+': + eptr->ex_op = OP_ADD; + break; + case '-': + eptr->ex_op = OP_SUB; + break; + case '^': + eptr->ex_op = OP_XOR; + break; + case '[': + eptr->ex_op = OP_LB; + break; + case '!': + if (*expr->exp_str == '=') { + eptr->ex_op = OP_NE; + expr->exp_str++; + } else + eptr->ex_op = OP_NOT; + break; + case '<': + switch (*expr->exp_str) { + case '<': + eptr->ex_op = OP_SL; + expr->exp_str++; + break; + case '=': + eptr->ex_op = OP_LE; + expr->exp_str++; + break; + default: + eptr->ex_op = OP_LT; + break; + } + break; + case '>': + switch (*expr->exp_str) { + case '>': + eptr->ex_op = OP_SR; + expr->exp_str++; + break; + case '=': + eptr->ex_op = OP_GE; + expr->exp_str++; + break; + default: + eptr->ex_op = OP_GT; + break; + } + break; + case '=': + if (*expr->exp_str++ != '=') { + post("expr: syntax error: =\n"); + return (1); + } + eptr->ex_op = OP_EQ; + break; +/* do not allow the store till the function is fixed + if (*expr->exp_str != '=') + eptr->ex_op = OP_STORE; + else { + expr->exp_str++; + eptr->ex_op = OP_EQ; + } + break; +*/ + + case '&': + if (*expr->exp_str == '&') { + expr->exp_str++; + eptr->ex_op = OP_LAND; + } else + eptr->ex_op = OP_AND; + break; + + case '|': + if ((*expr->exp_str == '|')) { + expr->exp_str++; + eptr->ex_op = OP_LOR; + } else + eptr->ex_op = OP_OR; + break; + case '$': + switch (*expr->exp_str++) { + case 'I': + case 'i': + eptr->ex_type = ET_II; + break; + case 'F': + case 'f': + eptr->ex_type = ET_FI; + break; + case 'S': + case 's': + eptr->ex_type = ET_SI; + break; + case 'V': + case 'v': + if (IS_EXPR_TILDE(expr)) { + eptr->ex_type = ET_VI; + break; + } + post("$v? works only for expr~"); + post("expr: syntax error: %s\n", &expr->exp_str[-2]); + return (1); + case 'X': + case 'x': + if (IS_FEXPR_TILDE(expr)) { + eptr->ex_type = ET_XI; + if (isdigit(*expr->exp_str)) + break; + /* for $x[] is a shorhand for $x1[] */ + eptr->ex_int = 0; + goto noinletnum; + } + post("$x? works only for fexpr~"); + post("expr: syntax error: %s\n", &expr->exp_str[-2]); + return (1); + case 'y': + case 'Y': + if (IS_FEXPR_TILDE(expr)) { + eptr->ex_type = ET_YO; + /*$y takes no number */ + if (isdigit(*expr->exp_str)) + break; + /* for $y[] is a shorhand for $y1[] */ + eptr->ex_int = 0; + goto noinletnum; + } + post("$y works only for fexpr~"); + default: + post("expr: syntax error: %s\n", &expr->exp_str[-2]); + return (1); + } + p = atoif(expr->exp_str, &eptr->ex_op, &i); + if (!p) { + post("expr: syntax error: %s\n", &expr->exp_str[-2]); + return (1); + } + if (i != ET_INT) { + post("expr: syntax error: %s\n", expr->exp_str); + return (1); + } + /* + * make the user inlets one based rather than zero based + * therefore we decrement the number that user has supplied + */ + if (!eptr->ex_op || (eptr->ex_op)-- > MAX_VARS) { + post("expr: syntax error: inlet or outlet out of range: %s\n", + expr->exp_str); + return (1); + } + + /* + * until we can change the input type of inlets on + * the fly (at pd_new() + * time) the first input to expr~ is always a vectore + * and $f1 or $i1 is + * illegal for fexr~ + */ + if (eptr->ex_op == 0 && + (IS_FEXPR_TILDE(expr) || IS_EXPR_TILDE(expr)) && + (eptr->ex_type==ET_II || eptr->ex_type==ET_FI || + eptr->ex_type==ET_SI)) { + post("first inlet of expr~/fexpr~ can only be a vector"); + return (1); + } + /* record the inlet or outlet type and check for consistency */ + if (eptr->ex_type == ET_YO ) { + /* it is an outlet for fexpr~*/ + /* no need to do anything */ + ; + } else if (!expr->exp_var[eptr->ex_op].ex_type) + expr->exp_var[eptr->ex_op].ex_type = eptr->ex_type; + else if (expr->exp_var[eptr->ex_op].ex_type != eptr->ex_type) { + post("expr: syntax error: inlets can only have one type: %s\n", expr->exp_str); + return (1); + } + expr->exp_str = p; +noinletnum: + break; + case '"': + { + struct ex_ex ex; + + p = expr->exp_str; + if (!*expr->exp_str || *expr->exp_str == '"') { + post("expr: syntax error: empty symbol: %s\n", --expr->exp_str); + return (1); + } + if (getoken(expr, &ex)) + return (1); + switch (ex.ex_type) { + case ET_STR: + if (ex_getsym(ex.ex_ptr, (t_symbol **)&(eptr->ex_ptr))) { + post("expr: syntax error: getoken: problms with ex_getsym\n"); + return (1); + } + eptr->ex_type = ET_SYM; + break; + case ET_SI: + *eptr = ex; + eptr->ex_type = ET_VSYM; + break; + default: + post("expr: syntax error: bad symbol name: %s\n", p); + return (1); + } + if (*expr->exp_str++ != '"') { + post("expr: syntax error: missing '\"'\n"); + return (1); + } + break; + } + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + p = atoif(--expr->exp_str, &eptr->ex_int, &eptr->ex_type); + if (!p) + return (1); + expr->exp_str = p; + break; + + default: + /* + * has to be a string, it should either be a + * function or a table + */ + p = --expr->exp_str; + for (i = 0; name_ok(*p); i++) + p++; + if (!i) { + post("expr: syntax error: %s\n", expr->exp_str); + return (1); + } + eptr->ex_ptr = (char *)fts_malloc(i + 1); + strncpy(eptr->ex_ptr, expr->exp_str, (int) i); + (eptr->ex_ptr)[i] = 0; + expr->exp_str = p; + /* + * we mark this as a string and later we will change this + * to either a function or a table + */ + eptr->ex_type = ET_STR; + break; + } + return (0); +} + +/* + * atoif -- ascii to float or integer (understands hex numbers also) + */ +char * +atoif(char *s, long int *value, long int *type) +{ + char *p; + long int_val = 0; + int flt = 0; + float pos = 0; + float flt_val = 0; + int base = 10; + + p = s; + if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) { + base = 16; + p += 2; + } + while (8) { + switch (*p) { + case '.': + if (flt || base != 10) { + post("expr: syntax error: %s\n", s); + return ((char *) 0); + } + flt++; + pos = 10; + flt_val = int_val; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (flt) { + flt_val += (*p - '0') / pos; + pos *= 10; + } else { + int_val *= base; + int_val += (*p - '0'); + } + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + if (base != 16 || flt) { + post("expr: syntax error: %s\n", s); + return ((char *) 0); + } + int_val *= base; + int_val += (*p - 'a' + 10); + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + if (base != 16 || flt) { + post("expr: syntax error: %s\n", s); + return ((char *) 0); + } + int_val *= base; + int_val += (*p - 'A' + 10); + break; + default: + if (flt) { + *type = ET_FLT; + *((float *) value) = flt_val; + } else { + *type = ET_INT; + *value = int_val; + } + return (p); + } + p++; + } +} + +/* + * find_func -- returns a pointer to the found function structure + * otherwise it returns 0 + */ +t_ex_func * +find_func(char *s) +{ + t_ex_func *f; + + for (f = ex_funcs; f->f_name; f++) + if (!strcmp(f->f_name, s)) + return (f); + return ((t_ex_func *) 0); +} + + +/* + * ex_print -- print an expression array + */ + +void +ex_print(struct ex_ex *eptr) +{ + + while (eptr->ex_type) { + switch (eptr->ex_type) { + case ET_INT: + post("%ld ", eptr->ex_int); + break; + case ET_FLT: + post("%f ", eptr->ex_flt); + break; + case ET_STR: + post("%s ", eptr->ex_ptr); + break; + case ET_TBL: + case ET_VAR: + post("%s ", ex_symname((fts_symbol_t )eptr->ex_ptr)); + break; + case ET_SYM: + post("\"%s\" ", ex_symname((fts_symbol_t )eptr->ex_ptr)); + break; + case ET_VSYM: + post("\"$s%ld\" ", eptr->ex_int + 1); + break; + case ET_FUNC: + post("%s ", + ((t_ex_func *)eptr->ex_ptr)->f_name); + break; + case ET_LP: + post("%c", '('); + break; + /* CHANGE + case ET_RP: + post("%c ", ')'); + break; + */ + case ET_LB: + post("%c", '['); + break; + /* CHANGE + case ET_RB: + post("%c ", ']'); + break; + */ + case ET_II: + post("$i%ld ", eptr->ex_int + 1); + break; + case ET_FI: + post("$f%ld ", eptr->ex_int + 1); + break; + case ET_SI: + post("$s%lx ", eptr->ex_ptr); + break; + case ET_VI: + post("$v%lx ", eptr->ex_vec); + break; + case ET_VEC: + post("vec = %ld ", eptr->ex_vec); + break; + case ET_YOM1: + case ET_YO: + post("$y%d", eptr->ex_int + 1); + break; + case ET_XI: + case ET_XI0: + post("$x%d", eptr->ex_int + 1); + break; + case ET_OP: + switch (eptr->ex_op) { + case OP_LP: + post("%c", '('); + break; + case OP_RP: + post("%c ", ')'); + break; + case OP_LB: + post("%c", '['); + break; + case OP_RB: + post("%c ", ']'); + break; + case OP_NOT: + post("%c", '!'); + break; + case OP_NEG: + post("%c", '~'); + break; + case OP_UMINUS: + post("%c", '-'); + break; + case OP_MUL: + post("%c", '*'); + break; + case OP_DIV: + post("%c", '/'); + break; + case OP_MOD: + post("%c", '%'); + break; + case OP_ADD: + post("%c", '+'); + break; + case OP_SUB: + post("%c", '-'); + break; + case OP_SL: + post("%s", "<<"); + break; + case OP_SR: + post("%s", ">>"); + break; + case OP_LT: + post("%c", '<'); + break; + case OP_LE: + post("%s", "<="); + break; + case OP_GT: + post("%c", '>'); + break; + case OP_GE: + post("%s", ">="); + break; + case OP_EQ: + post("%s", "=="); + break; + case OP_STORE: + post("%s", "="); + break; + case OP_NE: + post("%s", "!="); + break; + case OP_AND: + post("%c", '&'); + break; + case OP_XOR: + post("%c", '^'); + break; + case OP_OR: + post("%c", '|'); + break; + case OP_LAND: + post("%s", "&&"); + break; + case OP_LOR: + post("%s", "||"); + break; + case OP_COMMA: + post("%c", ','); + break; + case OP_SEMI: + post("%c", ';'); + break; + default: + post("expr: ex_print: bad op 0x%lx\n", eptr->ex_op); + } + break; + default: + post("expr: ex_print: bad type 0x%lx\n", eptr->ex_type); + } + eptr++; + } + post("\n"); +} + +#ifdef _WIN32 +void ABORT( void) {bug("expr");} +#endif diff --git a/extra/expr~/vexp.h b/extra/expr~/vexp.h new file mode 100644 index 0000000000000000000000000000000000000000..d096842f58299bf079067d728009170a375a2827 --- /dev/null +++ b/extra/expr~/vexp.h @@ -0,0 +1,248 @@ +/* + * jMax + * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * See file LICENSE for further informations on licensing terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Based on Max/ISPW by Miller Puckette. + * + * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell. + * + */ + +/* "expr" was written by Shahrokh Yadegari c. 1989. -msp */ +/* "expr~" and "fexpr~" conversion by Shahrokh Yadegari c. 1999,2000 */ + +#define MSP +#ifdef PD +#undef MSP +#endif + +#ifdef PD +#include "m_pd.h" +#else /* MSP */ +#include "ext.h" +#include "z_dsp.h" +#endif + +#include "fts_to_pd.h" +/* This is put in fts_to_pd.h + +#ifdef MSP +#define t_atom Atom +#define t_symbol Symbol +#define pd_new(x) newobject(x); +#define t_outlet void +#endif +*/ + +/* + * Currently the maximum number of variables (inlets) that are supported + * is 10. + */ + +#define MAX_VARS 9 +#define MINODES 10 /* was 200 */ + +/* terminal defines */ + +/* + * operations + * (x<<16|y) x defines the level of precedence, + * the lower the number the lower the precedence + * separators are defines as operators just for convenience + */ + +#define OP_SEMI ((long)(1<<16|1)) /* ; */ +#define OP_COMMA ((long)(2<<16|2)) /* , */ +#define OP_LOR ((long)(3<<16|3)) /* || */ +#define OP_LAND ((long)(4<<16|4)) /* && */ +#define OP_OR ((long)(5<<16|5)) /* | */ +#define OP_XOR ((long)(6<<16|6)) /* ^ */ +#define OP_AND ((long)(7<<16|7)) /* & */ +#define OP_NE ((long)(8<<16|8)) /* != */ +#define OP_EQ ((long)(8<<16|9)) /* == */ +#define OP_GE ((long)(9<<16|10)) /* >= */ +#define OP_GT ((long)(9<<16|11)) /* > */ +#define OP_LE ((long)(9<<16|12)) /* <= */ +#define OP_LT ((long)(9<<16|13)) /* < */ +#define OP_SR ((long)(10<<16|14)) /* >> */ +#define OP_SL ((long)(10<<16|15)) /* << */ +#define OP_SUB ((long)(11<<16|16)) /* - */ +#define OP_ADD ((long)(11<<16|17)) /* + */ +#define OP_MOD ((long)(12<<16|18)) /* % */ +#define OP_DIV ((long)(12<<16|19)) /* / */ +#define OP_MUL ((long)(12<<16|20)) /* * */ +#define OP_UMINUS ((long)(13<<16|21)) /* - unary minus */ +#define OP_NEG ((long)(13<<16|22)) /* ~ one complement */ +#define OP_NOT ((long)(13<<16|23)) /* ! */ +#define OP_RB ((long)(14<<16|24)) /* ] */ +#define OP_LB ((long)(14<<16|25)) /* [ */ +#define OP_RP ((long)(14<<16|26)) /* ) */ +#define OP_LP ((long)(14<<16|27)) /* ( */ +#define OP_STORE ((long)(15<<16|28)) /* = */ +#define HI_PRE ((long)(100<<16)) /* infinite precedence */ +#define PRE_MASK ((long)0xffff0000) /* precedence level mask */ + +struct ex_ex; + +#define name_ok(c) (((c)=='_') || ((c)>='a' && (c)<='z') || \ + ((c)>='A' && (c)<='Z') || ((c) >= '0' && (c) <= '9')) +#define unary_op(x) ((x) == OP_NOT || (x) == OP_NEG || (x) == OP_UMINUS) + +struct ex_ex { + union { + long v_int; + float v_flt; + t_float *v_vec; /* this is an for allocated vector */ + long op; + char *ptr; + } ex_cont; /* content */ +#define ex_int ex_cont.v_int +#define ex_flt ex_cont.v_flt +#define ex_vec ex_cont.v_vec +#define ex_op ex_cont.op +#define ex_ptr ex_cont.ptr + long ex_type; /* type of the node */ +}; +#define exNULL ((struct ex_ex *)0) + +/* defines for ex_type */ +#define ET_INT 1 /* an int */ +#define ET_FLT 2 /* a float */ +#define ET_OP 3 /* operator */ +#define ET_STR 4 /* string */ +#define ET_TBL 5 /* a table, the content is a pointer */ +#define ET_FUNC 6 /* a function */ +#define ET_SYM 7 /* symbol ("string") */ +#define ET_VSYM 8 /* variable symbol ("$s?") */ + /* we treat parenthesis and brackets */ + /* special to keep a pointer to their */ + /* match in the content */ +#define ET_LP 9 /* left parenthesis */ +#define ET_LB 10 /* left bracket */ +#define ET_II 11 /* and integer inlet */ +#define ET_FI 12 /* float inlet */ +#define ET_SI 13 /* string inlet */ +#define ET_VI 14 /* signal inlet */ +#define ET_VEC 15 /* allocated signal vector */ + /* special types for fexpr~ */ +#define ET_YO 16 /* vector output for fexpr~ */ +#define ET_YOM1 17 /* shorthand for $y?[-1] */ +#define ET_XI 18 /* vector input for fexpr~ */ +#define ET_XI0 20 /* shorthand for $x?[0] */ +#define ET_VAR 21 /* variable */ + +/* defines for ex_flags */ +#define EF_TYPE_MASK 0x07 /* first three bits define the type of expr */ +#define EF_EXPR 0x01 /* expr - control in and out */ +#define EF_EXPR_TILDE 0x02 /* expr~ signal and control in, signal out */ +#define EF_FEXPR_TILDE 0x04 /* fexpr~ filter expression */ + +#define EF_STOP 0x08 /* is it stopped used for expr~ and fexpr~ */ +#define EF_VERBOSE 0x10 /* verbose mode */ + +#define IS_EXPR(x) ((((x)->exp_flags&EF_TYPE_MASK)|EF_EXPR) == EF_EXPR) +#define IS_EXPR_TILDE(x) \ + ((((x)->exp_flags&EF_TYPE_MASK)|EF_EXPR_TILDE)==EF_EXPR_TILDE) +#define IS_FEXPR_TILDE(x) \ + ((((x)->exp_flags&EF_TYPE_MASK)|EF_FEXPR_TILDE)==EF_FEXPR_TILDE) + +#define SET_EXPR(x) (x)->exp_flags |= EF_EXPR; \ + (x)->exp_flags &= ~EF_EXPR_TILDE; \ + (x)->exp_flags &= ~EF_FEXPR_TILDE; + +#define SET_EXPR_TILDE(x) (x)->exp_flags &= ~EF_EXPR; \ + (x)->exp_flags |= EF_EXPR_TILDE; \ + (x)->exp_flags &= ~EF_FEXPR_TILDE; + +#define SET_FEXPR_TILDE(x) (x)->exp_flags &= ~EF_EXPR; \ + (x)->exp_flags &= ~EF_EXPR_TILDE; \ + (x)->exp_flags |= EF_FEXPR_TILDE; + +/* + * defines for expr_error + */ +#define EE_DZ 0x01 /* divide by zero error */ +#define EE_BI_OUTPUT 0x02 /* Bad output index */ +#define EE_BI_INPUT 0x04 /* Bad input index */ +#define EE_NOTABLE 0x08 /* NO TABLE */ +#define EE_NOVAR 0x10 /* NO VARIABLE */ + +typedef struct expr { +#ifdef PD + t_object exp_ob; +#else /* MSP */ + t_pxobject exp_ob; +#endif + int exp_flags; /* are we expr~, fexpr~, or expr */ + int exp_error; /* reported errors */ + int exp_nexpr; /* number of expressions */ + char *exp_string; /* the full expression string */ + char *exp_str; /* current parsing position */ + t_outlet *exp_outlet[MAX_VARS]; +#ifdef PD + struct _exprproxy *exp_proxy; +#else /* MAX */ + void *exp_proxy[MAX_VARS]; + long exp_proxy_id; +#endif + struct ex_ex *exp_stack[MAX_VARS]; + struct ex_ex exp_var[MAX_VARS]; + struct ex_ex exp_res[MAX_VARS]; /* the evluation result */ + t_float *exp_p_var[MAX_VARS]; + t_float *exp_p_res[MAX_VARS]; /* the previous evaluation result */ + t_float *exp_tmpres[MAX_VARS]; /* temporty result for fexpr~ */ + int exp_vsize; /* the size of the signal vector */ + int exp_nivec; /* # of vector inlets */ + float exp_f; /* control value to be transformed to signal */ +} t_expr; + +typedef struct ex_funcs { + char *f_name; /* function name */ + void (*f_func)(t_expr *, long, struct ex_ex *, struct ex_ex *); + /* the real function performing the function (void, no return!!!) */ + long f_argc; /* number of arguments */ +} t_ex_func; + +/* function prototypes for pd-related functions called withing vexp.h */ + +extern int max_ex_tab(struct expr *expr, t_symbol *s, struct ex_ex *arg, struct ex_ex *optr); +extern int max_ex_var(struct expr *expr, t_symbol *s, struct ex_ex *optr); +extern int ex_getsym(char *p, t_symbol **s); +extern const char *ex_symname(t_symbol *s); +void ex_mkvector(t_float *fp, t_float x, int size); +extern void ex_size(t_expr *expr, long int argc, struct ex_ex *argv, + struct ex_ex *optr); +extern void ex_sum(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +extern void ex_Sum(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +extern void ex_avg(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +extern void ex_Avg(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +extern void ex_store(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); + +int value_getonly(t_symbol *s, t_float *f); + + +/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans@at.or.at> */ +#ifdef _MSC_VER +#pragma warning (disable: 4305 4244) +#endif + +#ifdef _WIN32 +#define abort ABORT +void ABORT(void); +#endif diff --git a/extra/expr~/vexp_fun.c b/extra/expr~/vexp_fun.c new file mode 100644 index 0000000000000000000000000000000000000000..26b0b7675c4b1296370bc3e3d1ca3a93941bbd33 --- /dev/null +++ b/extra/expr~/vexp_fun.c @@ -0,0 +1,1315 @@ +/* + * jMax + * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * See file LICENSE for further informations on licensing terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Based on Max/ISPW by Miller Puckette. + * + * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell. + * + */ + +/* "expr" was written by Shahrokh Yadegari c. 1989. -msp + * + * Nov. 2001 --sdy + * conversion for expr~ + * + * Jan, 2002 --sdy + * added fmod() + * + * May 2002 + * added floor and ceil for expr -- Orm Finnendahl + * + * July 2002 --sdy + * added the following math funtions: + * cbrt - cube root + * erf - error function + * erfc - complementary error function + * expm1 - exponential minus 1, + * log1p - logarithm of 1 plus + * isinf - is the value infinite, + * finite - is the value finite + * isnan -- is the resut a nan (Not a number) + * copysign - copy sign of a number + * ldexp - multiply floating-point number by integral power of 2 + * imodf - get signed integral value from floating-point number + * modf - get signed fractional value from floating-point number + * drem - floating-point remainder function + * + * The following are done but not popular enough in math libss + * to be included yet + * hypoth - Euclidean distance function + * trunc + * round + * nearbyint - + */ + + + +/* + * vexp_func.c -- this file include all the functions for vexp. + * the first two arguments to the function are the number + * of argument and an array of arguments (argc, argv) + * the last argument is a pointer to a struct ex_ex for + * the result. Up do this point, the content of the + * struct ex_ex that these functions receive are either + * ET_INT (long), ET_FLT (float), or ET_SYM (char **, it is + * char ** and not char * since NewHandle of Mac returns + * a char ** for relocatability.) The common practice in + * these functions is that they figure out the type of their + * result according to the type of the arguments. In general + * the ET_SYM is used an ET_INT when we expect a value. + * It is the users responsibility not to pass strings to the + * function. + */ + +#include <stdlib.h> +#include <string.h> + +#define __STRICT_BSD__ +#include <math.h> +#undef __STRICT_BSD__ + + +#include "vexp.h" + +/* forward declarations */ + +static void ex_min(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_max(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_toint(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_rint(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_tofloat(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_pow(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_exp(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_log(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_ln(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_sin(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_cos(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_asin(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_acos(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_tan(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_atan(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_sinh(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_cosh(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_asinh(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_acosh(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_tanh(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_atanh(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_atan2(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_sqrt(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_fact(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_random(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_abs(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_fmod(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_ceil(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_floor(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_if(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_ldexp(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_imodf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_modf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +#ifndef _WIN32 +static void ex_cbrt(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_erf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_erfc(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_expm1(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_log1p(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_isinf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_finite(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_isnan(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_copysign(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_drem(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +#endif +#ifdef notdef +/* the following will be added once they are more popular in math libraries */ +static void ex_round(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_trunc(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_nearbyint(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +static void ex_hypoth(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr); +#endif + + +t_ex_func ex_funcs[] = { + {"min", ex_min, 2}, + {"max", ex_max, 2}, + {"int", ex_toint, 1}, + {"rint", ex_rint, 1}, + {"float", ex_tofloat, 1}, + {"fmod", ex_fmod, 2}, + {"floor", ex_floor, 2}, + {"ceil", ex_ceil, 2}, + {"pow", ex_pow, 2}, + {"sqrt", ex_sqrt, 1}, + {"exp", ex_exp, 1}, + {"log10", ex_log, 1}, + {"ln", ex_ln, 1}, + {"log", ex_ln, 1}, + {"sin", ex_sin, 1}, + {"cos", ex_cos, 1}, + {"tan", ex_tan, 1}, + {"asin", ex_asin, 1}, + {"acos", ex_acos, 1}, + {"atan", ex_atan, 1}, + {"atan2", ex_atan2, 2}, + {"sinh", ex_sinh, 1}, + {"cosh", ex_cosh, 1}, + {"tanh", ex_tanh, 1}, + {"fact", ex_fact, 1}, + {"random", ex_random, 2}, /* random number */ + {"abs", ex_abs, 1}, + {"if", ex_if, 3}, + {"ldexp ", ex_ldexp, 1}, + {"imodf ", ex_imodf, 1}, + {"modf", ex_modf, 1}, +#ifndef _WIN32 + {"cbrt", ex_cbrt, 1}, + {"erf", ex_erf, 1}, + {"erfc", ex_erfc, 1}, + {"expm1", ex_expm1, 1}, + {"log1p", ex_log1p, 1}, + {"isinf", ex_isinf, 1}, + {"finite", ex_finite, 1}, + {"isnan", ex_isnan, 1}, + {"copysig", ex_copysign, 1}, + {"drem", ex_drem, 1}, + {"asinh", ex_asinh, 1}, + {"acosh", ex_acosh, 1}, + {"atanh", ex_atanh, 1}, /* hyperbolic atan */ +#endif +#ifdef PD + {"size", ex_size, 1}, + {"sum", ex_sum, 1}, + {"Sum", ex_Sum, 3}, + {"avg", ex_avg, 1}, + {"Avg", ex_Avg, 3}, + {"store", ex_store, 3}, +#endif +#ifdef notdef +/* the following will be added once they are more popular in math libraries */ + {"round", ex_round, 1}, + {"trunc", ex_trunc, 1}, + {"nearbyint", ex_nearbyint, 1}, + {"hypoth", ex_hypoth, 1}, +#endif + {0, 0, 0} +}; + +/* + * FUN_EVAL -- do type checking, evaluate a function, + * if fltret is set return float + * otherwise return value based on regular typechecking, + */ +#define FUNC_EVAL(left, right, func, leftfuncast, rightfuncast, optr, fltret) \ +switch (left->ex_type) { \ +case ET_INT: \ + switch(right->ex_type) { \ + case ET_INT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = (float)func(leftfuncast left->ex_int, \ + rightfuncast right->ex_int); \ + j = e->exp_vsize; \ + while (j--) \ + *op++ = scalar; \ + } else { \ + if (fltret) { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = (float)func(leftfuncast \ + left->ex_int, rightfuncast right->ex_int); \ + } else { \ + optr->ex_type = ET_INT; \ + optr->ex_int = (int)func(leftfuncast \ + left->ex_int, rightfuncast right->ex_int); \ + } \ + } \ + break; \ + case ET_FLT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = (float)func(leftfuncast left->ex_int, \ + rightfuncast right->ex_flt); \ + j = e->exp_vsize; \ + while (j--) \ + *op++ = scalar; \ + } else { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = (float)func(leftfuncast left->ex_int, \ + rightfuncast right->ex_flt); \ + } \ + break; \ + case ET_VEC: \ + case ET_VI: \ + if (optr->ex_type != ET_VEC) { \ + if (optr->ex_type == ET_VI) { \ + post("expr~: Int. error %d", __LINE__); \ + abort(); \ + } \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float)*e->exp_vsize); \ + } \ + scalar = left->ex_int; \ + rp = right->ex_vec; \ + op = optr->ex_vec; \ + j = e->exp_vsize; \ + while (j--) { \ + *op++ = (float)func(leftfuncast scalar, \ + rightfuncast *rp); \ + rp++; \ + } \ + break; \ + case ET_SYM: \ + default: \ + post_error((fts_object_t *) e, \ + "expr: FUNC_EVAL(%d): bad right type %ld\n", \ + __LINE__, right->ex_type);\ + } \ + break; \ +case ET_FLT: \ + switch(right->ex_type) { \ + case ET_INT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = (float)func(leftfuncast left->ex_flt, \ + rightfuncast right->ex_int); \ + j = e->exp_vsize; \ + while (j--) \ + *op++ = scalar; \ + } else { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = (float)func(leftfuncast left->ex_flt, \ + rightfuncast right->ex_int); \ + } \ + break; \ + case ET_FLT: \ + if (optr->ex_type == ET_VEC) { \ + op = optr->ex_vec; \ + scalar = (float)func(leftfuncast left->ex_flt, \ + rightfuncast right->ex_flt); \ + j = e->exp_vsize; \ + while (j--) \ + *op++ = scalar; \ + } else { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = (float)func(leftfuncast left->ex_flt, \ + rightfuncast right->ex_flt); \ + } \ + break; \ + case ET_VEC: \ + case ET_VI: \ + if (optr->ex_type != ET_VEC) { \ + if (optr->ex_type == ET_VI) { \ + post("expr~: Int. error %d", __LINE__); \ + abort(); \ + } \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float) * e->exp_vsize);\ + } \ + scalar = left->ex_flt; \ + rp = right->ex_vec; \ + op = optr->ex_vec; \ + j = e->exp_vsize; \ + while (j--) { \ + *op++ = (float)func(leftfuncast scalar, \ + rightfuncast *rp); \ + rp++; \ + } \ + break; \ + case ET_SYM: \ + default: \ + post_error((fts_object_t *) e, \ + "expr: FUNC_EVAL(%d): bad right type %ld\n", \ + __LINE__, right->ex_type);\ + } \ + break; \ +case ET_VEC: \ +case ET_VI: \ + if (optr->ex_type != ET_VEC) { \ + if (optr->ex_type == ET_VI) { \ + post("expr~: Int. error %d", __LINE__); \ + abort(); \ + } \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float) * e->exp_vsize); \ + } \ + op = optr->ex_vec; \ + lp = left->ex_vec; \ + switch(right->ex_type) { \ + case ET_INT: \ + scalar = right->ex_int; \ + j = e->exp_vsize; \ + while (j--) { \ + *op++ = (float)func(leftfuncast *lp, \ + rightfuncast scalar); \ + lp++; \ + } \ + break; \ + case ET_FLT: \ + scalar = right->ex_flt; \ + j = e->exp_vsize; \ + while (j--) { \ + *op++ = (float)func(leftfuncast *lp, \ + rightfuncast scalar); \ + lp++; \ + } \ + break; \ + case ET_VEC: \ + case ET_VI: \ + rp = right->ex_vec; \ + j = e->exp_vsize; \ + while (j--) { \ + /* \ + * on a RISC processor one could copy \ + * 8 times in each round to get a considerable \ + * improvement \ + */ \ + *op++ = (float)func(leftfuncast *lp, \ + rightfuncast *rp); \ + rp++; lp++; \ + } \ + break; \ + case ET_SYM: \ + default: \ + post_error((fts_object_t *) e, \ + "expr: FUNC_EVAL(%d): bad right type %ld\n", \ + __LINE__, right->ex_type);\ + } \ + break; \ +case ET_SYM: \ +default: \ + post_error((fts_object_t *) e, \ + "expr: FUNC_EVAL(%d): bad left type %ld\n", \ + __LINE__, left->ex_type); \ +} + +/* + * FUNC_EVAL_UNARY - evaluate a unary function, + * if fltret is set return float + * otherwise return value based on regular typechecking, + */ +#define FUNC_EVAL_UNARY(left, func, leftcast, optr, fltret) \ +switch(left->ex_type) { \ +case ET_INT: \ + if (optr->ex_type == ET_VEC) { \ + ex_mkvector(optr->ex_vec, \ + (float)(func (leftcast left->ex_int)), e->exp_vsize);\ + break; \ + } \ + if (fltret) { \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = (float) func(leftcast left->ex_int); \ + break; \ + } \ + optr->ex_type = ET_INT; \ + optr->ex_int = (int) func(leftcast left->ex_int); \ + break; \ +case ET_FLT: \ + if (optr->ex_type == ET_VEC) { \ + ex_mkvector(optr->ex_vec, \ + (float)(func (leftcast left->ex_flt)), e->exp_vsize);\ + break; \ + } \ + optr->ex_type = ET_FLT; \ + optr->ex_flt = (float) func(leftcast left->ex_flt); \ + break; \ +case ET_VI: \ +case ET_VEC: \ + if (optr->ex_type != ET_VEC) { \ + optr->ex_type = ET_VEC; \ + optr->ex_vec = (t_float *) \ + fts_malloc(sizeof (t_float)*e->exp_vsize); \ + } \ + op = optr->ex_vec; \ + lp = left->ex_vec; \ + j = e->exp_vsize; \ + while (j--) \ + *op++ = (float)(func (leftcast *lp++)); \ + break; \ +default: \ + post_error((fts_object_t *) e, \ + "expr: FUNV_EVAL_UNARY(%d): bad left type %ld\n",\ + __LINE__, left->ex_type); \ +} + +#undef min +#undef max +#define min(x,y) (x > y ? y : x) +#define max(x,y) (x > y ? x : y) + +#define FUNC_DEF(ex_func, func, castleft, castright, fltret); \ +static void \ +ex_func(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)\ +{ \ + struct ex_ex *left, *right; \ + float *op; /* output pointer */ \ + float *lp, *rp; /* left and right vector pointers */ \ + float scalar; \ + int j; \ + \ + left = argv++; \ + right = argv; \ + FUNC_EVAL(left, right, func, castleft, castright, optr, fltret); \ +} + + +#define FUNC_DEF_UNARY(ex_func, func, cast, fltret); \ +static void \ +ex_func(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)\ +{ \ + struct ex_ex *left; \ + float *op; /* output pointer */ \ + float *lp, *rp; /* left and right vector pointers */ \ + float scalar; \ + int j; \ + \ + left = argv++; \ + \ + FUNC_EVAL_UNARY(left, func, cast, optr, fltret); \ +} + +/* + * ex_min -- if any of the arguments are or the output are vectors, a vector + * of floats is generated otherwise the type of the result is the + * type of the smaller value + */ +static void +ex_min(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left, *right; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + right = argv; + + FUNC_EVAL(left, right, min, (double), (double), optr, 0); +} + +/* + * ex_max -- if any of the arguments are or the output are vectors, a vector + * of floats is generated otherwise the type of the result is the + * type of the larger value + */ +static void +ex_max(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left, *right; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + right = argv; + + FUNC_EVAL(left, right, max, (double), (double), optr, 0); +} + +/* + * ex_toint -- convert to integer + */ +static void +ex_toint(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + +#define toint(x) ((int)(x)) + FUNC_EVAL_UNARY(left, toint, (int), optr, 0); + } + +#ifdef _WIN32 +/* No rint in NT land ??? */ +double rint(double x); + +double +rint(double x) +{ + return (floor(x + 0.5)); +} +#endif + +/* + * ex_rint -- rint() round to the nearest int according to the common + * rounding mechanism + */ +static void +ex_rint(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + + FUNC_EVAL_UNARY(left, rint, (double), optr, 1); +} + +/* + * ex_tofloat -- convert to float + */ +static void +ex_tofloat(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + +#define tofloat(x) ((float)(x)) + FUNC_EVAL_UNARY(left, tofloat, (int), optr, 1); +} + + +/* + * ex_pow -- the power of + */ +static void +ex_pow(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left, *right; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + right = argv; + FUNC_EVAL(left, right, pow, (double), (double), optr, 1); +} + +/* + * ex_sqrt -- square root + */ +static void +ex_sqrt(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, sqrt, (double), optr, 1); +} + +/* + * ex_exp -- e to the power of + */ +static void +ex_exp(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, exp, (double), optr, 1); +} + +/* + * ex_log -- 10 based logarithm + */ +static void +ex_log(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, log10, (double), optr, 1); +} + +/* + * ex_ln -- natural log + */ +static void +ex_ln(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, log, (double), optr, 1); +} + +static void +ex_sin(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, sin, (double), optr, 1); +} + +static void +ex_cos(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, cos, (double), optr, 1); +} + + +static void +ex_tan(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, tan, (double), optr, 1); +} + +static void +ex_asin(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, asin, (double), optr, 1); +} + +static void +ex_acos(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, acos, (double), optr, 1); +} + + +static void +ex_atan(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, atan, (double), optr, 1); +} + +/* + *ex_atan2 -- + */ +static void +ex_atan2(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left, *right; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + right = argv; + FUNC_EVAL(left, right, atan2, (double), (double), optr, 1); +} + +/* + * ex_fmod -- floating point modulo + */ +static void +ex_fmod(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left, *right; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + right = argv; + FUNC_EVAL(left, right, fmod, (double), (double), optr, 1); +} + + +/* + * ex_floor -- floor + */ +static void +ex_floor(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + FUNC_EVAL_UNARY(left, floor, (double), optr, 1); +} + + +/* + * ex_ceil -- ceil + */ +static void +ex_ceil(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + FUNC_EVAL_UNARY(left, ceil, (double), optr, 1); +} + +static void +ex_sinh(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, sinh, (double), optr, 1); +} + +static void +ex_cosh(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, cosh, (double), optr, 1); +} + + +static void +ex_tanh(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, tanh, (double), optr, 1); +} + + +#ifndef _WIN32 +static void +ex_asinh(t_expr *e, long argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, asinh, (double), optr, 1); +} + +static void +ex_acosh(t_expr *e, long argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, acosh, (double), optr, 1); +} + +static void +ex_atanh(t_expr *e, long argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, atanh, (double), optr, 1); +} +#endif + +static int +ex_dofact(int i) +{ + int ret = 0; + + if (i) + ret = 1; + else + return (0); + + do { + ret *= i; + } while (--i); + + return(ret); +} + +static void +ex_fact(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, ex_dofact, (int), optr, 0); +} + +static int +ex_dorandom(int i1, int i2) +{ + return(i1 + (((i2 - i1) * (rand() & 0x7fffL)) >> 15)); +} +/* + * ex_random -- return a random number + */ +static void +ex_random(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left, *right; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + right = argv; + FUNC_EVAL(left, right, ex_dorandom, (int), (int), optr, 0); +} + + +static void +ex_abs(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float scalar; + int j; + + left = argv++; + + FUNC_EVAL_UNARY(left, fabs, (double), optr, 0); +} + +/* + *ex_if -- floating point modulo + */ +static void +ex_if(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + struct ex_ex *left, *right, *cond, *res; + float *op; /* output pointer */ + float *lp, *rp; /* left and right vector pointers */ + float *cp; /* condition pointer */ + float leftvalue, rightvalue; + int j; + + cond = argv++; + left = argv++; + right = argv; + + switch (cond->ex_type) { + case ET_VEC: + case ET_VI: + if (optr->ex_type != ET_VEC) { + if (optr->ex_type == ET_VI) { + /* SDY remove this test */ + post("expr~: Int. error %d", __LINE__); + return; + } + optr->ex_type = ET_VEC; + optr->ex_vec = (t_float *) + fts_malloc(sizeof (t_float) * e->exp_vsize); + } + op = optr->ex_vec; + j = e->exp_vsize; + cp = cond->ex_vec; + switch (left->ex_type) { + case ET_INT: + leftvalue = left->ex_int; + switch (right->ex_type) { + case ET_INT: + rightvalue = right->ex_int; + while (j--) { + if (*cp++) + *op++ = leftvalue; + else + *op++ = rightvalue; + } + return; + case ET_FLT: + rightvalue = right->ex_flt; + while (j--) { + if (*cp++) + *op++ = leftvalue; + else + *op++ = rightvalue; + } + return; + case ET_VEC: + case ET_VI: + rp = right->ex_vec; + while (j--) { + if (*cp++) + *op++ = leftvalue; + else + *op++ = *rp; + rp++; + } + return; + case ET_SYM: + default: + post_error((fts_object_t *) e, + "expr: FUNC_EVAL(%d): bad right type %ld\n", + __LINE__, right->ex_type); + return; + } + case ET_FLT: + leftvalue = left->ex_flt; + switch (right->ex_type) { + case ET_INT: + rightvalue = right->ex_int; + while (j--) { + if (*cp++) + *op++ = leftvalue; + else + *op++ = rightvalue; + } + return; + case ET_FLT: + rightvalue = right->ex_flt; + while (j--) { + if (*cp++) + *op++ = leftvalue; + else + *op++ = rightvalue; + } + return; + case ET_VEC: + case ET_VI: + rp = right->ex_vec; + while (j--) { + if (*cp++) + *op++ = leftvalue; + else + *op++ = *rp; + rp++; + } + return; + case ET_SYM: + default: + post_error((fts_object_t *) e, + "expr: FUNC_EVAL(%d): bad right type %ld\n", + __LINE__, right->ex_type); + return; + } + case ET_VEC: + case ET_VI: + lp = left->ex_vec; + switch (right->ex_type) { + case ET_INT: + rightvalue = right->ex_int; + while (j--) { + if (*cp++) + *op++ = *lp; + else + *op++ = rightvalue; + lp++; + } + return; + case ET_FLT: + rightvalue = right->ex_flt; + while (j--) { + if (*cp++) + *op++ = *lp; + else + *op++ = rightvalue; + lp++; + } + return; + case ET_VEC: + case ET_VI: + rp = right->ex_vec; + while (j--) { + if (*cp++) + *op++ = *lp; + else + *op++ = *rp; + lp++; rp++; + } + return; + case ET_SYM: + default: + post_error((fts_object_t *) e, + "expr: FUNC_EVAL(%d): bad right type %ld\n", + __LINE__, right->ex_type); + return; + } + case ET_SYM: + default: + post_error((fts_object_t *) e, + "expr: FUNC_EVAL(%d): bad left type %ld\n", + __LINE__, left->ex_type); + return; + } + case ET_INT: + if (cond->ex_int) + res = left; + else + res = right; + break; + case ET_FLT: + if (cond->ex_flt) + res = left; + else + res = right; + break; + case ET_SYM: + default: + post_error((fts_object_t *) e, + "expr: FUNC_EVAL(%d): bad condition type %ld\n", + __LINE__, cond->ex_type); + return; + } + switch(res->ex_type) { + case ET_INT: + if (optr->ex_type == ET_VEC) { + ex_mkvector(optr->ex_vec, (float)res->ex_int, + e->exp_vsize); + return; + } + *optr = *res; + return; + case ET_FLT: + if (optr->ex_type == ET_VEC) { + ex_mkvector(optr->ex_vec, (float)res->ex_flt, + e->exp_vsize); + return; + } + *optr = *res; + return; + case ET_VEC: + case ET_VI: + if (optr->ex_type != ET_VEC) { + if (optr->ex_type == ET_VI) { + /* SDY remove this test */ + post("expr~: Int. error %d", __LINE__); + return; + } + optr->ex_type = ET_VEC; + optr->ex_vec = (t_float *) + fts_malloc(sizeof (t_float) * e->exp_vsize); + } + memcpy(optr->ex_vec, res->ex_vec, e->exp_vsize*sizeof(t_float)); + return; + case ET_SYM: + default: + post_error((fts_object_t *) e, + "expr: FUNC_EVAL(%d): bad res type %ld\n", + __LINE__, res->ex_type); + return; + } + +} + +/* + * ex_imodf - extract signed integral value from floating-point number + */ +static double +imodf(double x) +{ + double xx; + + modf(x, &xx); + return (xx); +} +FUNC_DEF_UNARY(ex_imodf, imodf, (double), 1); + +/* + * ex_modf - extract signed fractional value from floating-point number + * + * using fracmodf because fmodf() is alrady defined in a .h file + */ +static double +fracmodf(double x) +{ + double xx; + + return(modf(x, &xx)); +} +FUNC_DEF_UNARY(ex_modf, fracmodf, (double), 1); + +/* + * ex_ldexp - multiply floating-point number by integral power of 2 + */ +FUNC_DEF(ex_ldexp, ldexp, (double), (int), 1); + +#ifndef _WIN32 +/* + * ex_cbrt - cube root + */ +FUNC_DEF_UNARY(ex_cbrt, cbrt, (double), 1); + +/* + * ex_erf - error function + */ +FUNC_DEF_UNARY(ex_erf, erf, (double), 1); + +/* + * ex_erfc - complementary error function + */ +FUNC_DEF_UNARY(ex_erfc, erfc, (double), 1); + +/* + * ex_expm1 - exponential minus 1, + */ +FUNC_DEF_UNARY(ex_expm1, expm1, (double), 1); + +/* + * ex_log1p - logarithm of 1 plus + */ +FUNC_DEF_UNARY(ex_log1p, log1p, (double), 1); + +/* + * ex_isinf - is the value infinite, + */ +FUNC_DEF_UNARY(ex_isinf, isinf, (double), 0); + +/* + * ex_finite - is the value finite + */ +FUNC_DEF_UNARY(ex_finite, finite, (double), 0); + +/* + * ex_isnan -- is the resut a nan (Not a number) + */ +FUNC_DEF_UNARY(ex_isnan, isnan, (double), 0); + +/* + * ex_copysign - copy sign of a number + */ +FUNC_DEF(ex_copysign, copysign, (double), (double), 1); + +/* + * ex_drem - floating-point remainder function + */ +FUNC_DEF(ex_drem, drem, (double), (double), 1); +#endif + +#ifdef notdef +/* the following will be added once they are more popular in math libraries */ +/* + * ex_hypoth - Euclidean distance function + */ +FUNC_DEF(ex_hypoth, hypoth, (double), (double), 1); + +/* + * ex_round - round to nearest integer, away from zero + */ +FUNC_DEF_UNARY(ex_round, round, (double), 1); + +/* + * ex_trunc - round to interger, towards zero + */ +FUNC_DEF_UNARY(ex_trunc, trunc, (double), 1); + +/* + * ex_nearbyint - round to nearest integer + */ +FUNC_DEF_UNARY(ex_nearbyint, nearbyint, (double), 1); +#endif diff --git a/extra/expr~/vexp_if.c b/extra/expr~/vexp_if.c new file mode 100644 index 0000000000000000000000000000000000000000..648aba73235579fbb999b44ca72229f3a2726764 --- /dev/null +++ b/extra/expr~/vexp_if.c @@ -0,0 +1,1225 @@ +/* + * jMax + * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * See file LICENSE for further informations on licensing terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Based on Max/ISPW by Miller Puckette. + * + * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell. + * + */ + +/* "expr" was written by Shahrokh Yadegari c. 1989. -msp */ +/* "expr~" and "fexpr~" conversion by Shahrokh Yadegari c. 1999,2000 */ + +/* + * Feb 2002 - added access to variables + * multiple expression support + * new short hand forms for fexpr~ + * now $y or $y1 = $y1[-1] and $y2 = $y2[-1] + * --sdy + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "vexp.h" + +static char *exp_version = "0.4"; + +extern struct ex_ex *ex_eval(struct expr *expr, struct ex_ex *eptr, + struct ex_ex *optr, int n); + +#ifdef PD +static t_class *expr_class; +static t_class *expr_tilde_class; +static t_class *fexpr_tilde_class; +#else /* MSP */ +void *expr_tilde_class; +#endif + + +/*------------------------- expr class -------------------------------------*/ + +extern int expr_donew(struct expr *expr, int ac, t_atom *av); + +/*#define EXPR_DEBUG*/ + +static void expr_bang(t_expr *x); +t_int *expr_perform(t_int *w); + + +static void +expr_list(t_expr *x, t_symbol *s, int argc, const fts_atom_t *argv) +{ + int i; + + if (argc > MAX_VARS) argc = MAX_VARS; + + for (i = 0; i < argc; i++) + { + if (argv[i].a_type == A_FLOAT) + { + if (x->exp_var[i].ex_type == ET_FI) + x->exp_var[i].ex_flt = argv[i].a_w.w_float; + else if (x->exp_var[i].ex_type == ET_II) + x->exp_var[i].ex_int = argv[i].a_w.w_float; + else if (x->exp_var[i].ex_type) + pd_error(x, "expr: type mismatch"); + } + else if (argv[i].a_type == A_SYMBOL) + { + if (x->exp_var[i].ex_type == ET_SI) + x->exp_var[i].ex_ptr = (char *)argv[i].a_w.w_symbol; + else if (x->exp_var[i].ex_type) + pd_error(x, "expr: type mismatch"); + } + } + expr_bang(x); +} + +static void +expr_flt(t_expr *x, t_float f, int in) +{ + if (in > MAX_VARS) + return; + + if (x->exp_var[in].ex_type == ET_FI) + x->exp_var[in].ex_flt = f; + else if (x->exp_var[in].ex_type == ET_II) + x->exp_var[in].ex_int = f; +} + +static t_class *exprproxy_class; + +typedef struct _exprproxy { + t_pd p_pd; + int p_index; + t_expr *p_owner; + struct _exprproxy *p_next; +} t_exprproxy; + +t_exprproxy *exprproxy_new(t_expr *owner, int indx); +void exprproxy_float(t_exprproxy *p, t_floatarg f); + +t_exprproxy * +exprproxy_new(t_expr *owner, int indx) +{ + t_exprproxy *x = (t_exprproxy *)pd_new(exprproxy_class); + x->p_owner = owner; + x->p_index = indx; + x->p_next = owner->exp_proxy; + owner->exp_proxy = x; + return (x); +} + +void +exprproxy_float(t_exprproxy *p, t_floatarg f) +{ + t_expr *x = p->p_owner; + int in = p->p_index; + + if (in > MAX_VARS) + return; + + if (x->exp_var[in].ex_type == ET_FI) + x->exp_var[in].ex_flt = f; + else if (x->exp_var[in].ex_type == ET_II) + x->exp_var[in].ex_int = f; +} + +/* method definitions */ +static void +expr_ff(t_expr *x) +{ + t_exprproxy *y; + int i; + + y = x->exp_proxy; + while (y) + { + x->exp_proxy = y->p_next; +#ifdef PD + pd_free(&y->p_pd); +#else /*MSP */ + /* SDY find out what needs to be called for MSP */ + +#endif + y = x->exp_proxy; + } + for (i = 0 ; i < x->exp_nexpr; i++); + if (x->exp_stack[i]) + fts_free(x->exp_stack[i]); +/* + * SDY free all the allocated buffers here for expr~ and fexpr~ + * check to see if there are others + */ + for (i = 0; i < MAX_VARS; i++) { + if (x->exp_p_var[i]) + fts_free(x->exp_p_var[i]); + if (x->exp_p_res[i]) + fts_free(x->exp_p_res[i]); + if (x->exp_tmpres[i]) + fts_free(x->exp_tmpres[i]); + } + + +} + +static void +expr_bang(t_expr *x) +{ + int i; + +#ifdef EXPR_DEBUG + { + struct ex_ex *eptr; + + for (i = 0, eptr = x->exp_var; ; eptr++, i++) + { + if (!eptr->ex_type) + break; + switch (eptr->ex_type) + { + case ET_II: + fprintf(stderr,"ET_II: %d \n", eptr->ex_int); + break; + + case ET_FI: + fprintf(stderr,"ET_FT: %f \n", eptr->ex_flt); + break; + + default: + fprintf(stderr,"oups\n"); + } + } + } +#endif + /* banging a signal or filter object means nothing */ + if (!IS_EXPR(x)) + return; + + for (i = x->exp_nexpr - 1; i > -1 ; i--) { + if (!ex_eval(x, x->exp_stack[i], &x->exp_res[i], 0)) { + /*fprintf(stderr,"expr_bang(error evaluation)\n"); */ + /* SDY now that we have mutiple ones, on error we should + * continue + return; + */ + } + switch(x->exp_res[i].ex_type) { + case ET_INT: + outlet_float(x->exp_outlet[i], + (t_float) x->exp_res[i].ex_int); + break; + + case ET_FLT: + outlet_float(x->exp_outlet[i], x->exp_res[i].ex_flt); + break; + + case ET_SYM: + /* CHANGE this will have to be taken care of */ + + default: + post("expr: bang: unrecognized result %ld\n", x->exp_res[i].ex_type); + } + } +} + +static t_expr * +#ifdef PD +expr_new(t_symbol *s, int ac, t_atom *av) +#else /* MSP */ +Nexpr_new(t_symbol *s, int ac, t_atom *av) +#endif +{ + struct expr *x; + int i, ninlet; + struct ex_ex *eptr; + t_atom fakearg; + int dsp_index; /* keeping track of the dsp inlets */ + + +/* + * SDY - we may need to call dsp_setup() in this function + */ + + if (!ac) + { + ac = 1; + av = &fakearg; + SETFLOAT(&fakearg, 0); + } + +#ifdef PD + /* + * figure out if we are expr, expr~, or fexpr~ + */ + if (!strcmp("expr", s->s_name)) { + x = (t_expr *)pd_new(expr_class); + SET_EXPR(x); + } else if (!strcmp("expr~", s->s_name)) { + x = (t_expr *)pd_new(expr_tilde_class); + SET_EXPR_TILDE(x); + } else if (!strcmp("fexpr~", s->s_name)) { + x = (t_expr *)pd_new(fexpr_tilde_class); + SET_FEXPR_TILDE(x); + } else { + post("expr_new: bad object name '%s'"); + /* assume expr */ + x = (t_expr *)pd_new(expr_class); + SET_EXPR(x); + } +#else /* MSP */ + /* for now assume an expr~ */ + x = (t_expr *)pd_new(expr_tilde_class); + SET_EXPR_TILDE(x); +#endif + + /* + * initialize the newly allocated object + */ + x->exp_proxy = 0; + x->exp_nivec = 0; + x->exp_nexpr = 0; + x->exp_error = 0; + for (i = 0; i < MAX_VARS; i++) { + x->exp_stack[i] = (struct ex_ex *)0; + x->exp_outlet[i] = (t_outlet *)0; + x->exp_res[i].ex_type = 0; + x->exp_res[i].ex_int = 0; + x->exp_p_res[i] = (t_float *)0; + x->exp_var[i].ex_type = 0; + x->exp_var[i].ex_int = 0; + x->exp_p_var[i] = (t_float *)0; + x->exp_tmpres[i] = (t_float *)0; + x->exp_vsize = 0; + } + x->exp_f = 0; /* save the control value to be transformed to signal */ + + + if (expr_donew(x, ac, av)) + { + pd_error(x, "expr: syntax error"); +/* +SDY the following coredumps why? + pd_free(&x->exp_ob.ob_pd); +*/ + return (0); + } + + ninlet = 1; + for (i = 0, eptr = x->exp_var; i < MAX_VARS ; i++, eptr++) + if (eptr->ex_type) { + ninlet = i + 1; + } + + /* + * create the new inlets + */ + for (i = 1, eptr = x->exp_var + 1, dsp_index=1; i<ninlet ; i++, eptr++) + { + t_exprproxy *p; + switch (eptr->ex_type) + { + case 0: + /* nothing is using this inlet */ + if (i < ninlet) +#ifdef PD + floatinlet_new(&x->exp_ob, &eptr->ex_flt); +#else /* MSP */ + inlet_new(&x->exp_ob, "float"); +#endif + break; + + case ET_II: + case ET_FI: + p = exprproxy_new(x, i); +#ifdef PD + inlet_new(&x->exp_ob, &p->p_pd, &s_float, &s_float); +#else /* MSP */ + inlet_new(&x->exp_ob, "float"); +#endif + break; + + case ET_SI: +#ifdef PD + symbolinlet_new(&x->exp_ob, (t_symbol **)&eptr->ex_ptr); +#else /* MSP */ + inlet_new(&x->exp_ob, "symbol"); +#endif + break; + + case ET_XI: + case ET_VI: + if (!IS_EXPR(x)) { + dsp_index++; +#ifdef PD + inlet_new(&x->exp_ob, &x->exp_ob.ob_pd, + &s_signal, &s_signal); +#else /* MSP */ + inlet_new(&x->exp_ob, "signal"); +#endif + break; + } else + post("expr: internal error expr_new"); + default: + pd_error(x, "expr: bad type (%lx) inlet = %d\n", + eptr->ex_type, i + 1, 0, 0, 0); + break; + } + } + if (IS_EXPR(x)) { + for (i = 0; i < x->exp_nexpr; i++) + x->exp_outlet[i] = outlet_new(&x->exp_ob, 0); + } else { + for (i = 0; i < x->exp_nexpr; i++) + x->exp_outlet[i] = outlet_new(&x->exp_ob, + gensym("signal")); + x->exp_nivec = dsp_index; + } + /* + * for now assume a 64 sample size block but this may change once + * expr_dsp is called + */ + x->exp_vsize = 64; + for (i = 0; i < x->exp_nexpr; i++) { + x->exp_p_res[i] = fts_calloc(x->exp_vsize, sizeof (t_float)); + x->exp_tmpres[i] = fts_calloc(x->exp_vsize, sizeof (t_float)); + } + for (i = 0; i < MAX_VARS; i++) + x->exp_p_var[i] = fts_calloc(x->exp_vsize, sizeof (t_float)); + + return (x); +} + +t_int * +expr_perform(t_int *w) +{ + int i, j; + t_expr *x = (t_expr *)w[1]; + struct ex_ex res; + int n; + + /* sanity check */ + if (IS_EXPR(x)) { + post("expr_perform: bad x->exp_flags = %d", x->exp_flags); + abort(); + } + + if (x->exp_flags & EF_STOP) { + for (i = 0; i < x->exp_nexpr; i++) + memset(x->exp_res[i].ex_vec, 0, + x->exp_vsize * sizeof (float)); + return (w + 2); + } + + if (IS_EXPR_TILDE(x)) { + /* + * if we have only one expression, we can right on + * on the output directly, otherwise we have to copy + * the data because, outputs could be the same buffer as + * inputs + */ + if ( x->exp_nexpr == 1) + ex_eval(x, x->exp_stack[0], &x->exp_res[0], 0); + else { + res.ex_type = ET_VEC; + for (i = 0; i < x->exp_nexpr; i++) { + res.ex_vec = x->exp_tmpres[i]; + ex_eval(x, x->exp_stack[i], &res, 0); + } + n = x->exp_vsize * sizeof(t_float); + for (i = 0; i < x->exp_nexpr; i++) + memcpy(x->exp_res[i].ex_vec, x->exp_tmpres[i], + n); + } + return (w + 2); + } + + if (!IS_FEXPR_TILDE(x)) { + post("expr_perform: bad x->exp_flags = %d - expecting fexpr", + x->exp_flags); + return (w + 2); + } + /* + * since the output buffer could be the same as one of the inputs + * we need to keep the output in a different buffer + */ + for (i = 0; i < x->exp_vsize; i++) for (j = 0; j < x->exp_nexpr; j++) { + res.ex_type = 0; + res.ex_int = 0; + ex_eval(x, x->exp_stack[j], &res, i); + switch (res.ex_type) { + case ET_INT: + x->exp_tmpres[j][i] = (t_float) res.ex_int; + break; + case ET_FLT: + x->exp_tmpres[j][i] = res.ex_flt; + break; + default: + post("expr_perform: bad result type %d", res.ex_type); + } + } + /* + * copy inputs and results to the save buffers + * inputs need to be copied first as the output buffer can be + * same as an input buffer + */ + n = x->exp_vsize * sizeof(t_float); + for (i = 0; i < MAX_VARS; i++) + if (x->exp_var[i].ex_type == ET_XI) + memcpy(x->exp_p_var[i], x->exp_var[i].ex_vec, n); + for (i = 0; i < x->exp_nexpr; i++) { + memcpy(x->exp_p_res[i], x->exp_tmpres[i], n); + memcpy(x->exp_res[i].ex_vec, x->exp_tmpres[i], n); + } + return (w + 2); +} + +static void +expr_dsp(t_expr *x, t_signal **sp) +{ + int i, nv; + int newsize; + + x->exp_error = 0; /* reset all errors */ + newsize = (x->exp_vsize != sp[0]->s_n); + x->exp_vsize = sp[0]->s_n; /* record the vector size */ + for (i = 0; i < x->exp_nexpr; i++) { + x->exp_res[i].ex_type = ET_VEC; + x->exp_res[i].ex_vec = sp[x->exp_nivec + i]->s_vec; + } + for (i = 0, nv = 0; i < MAX_VARS; i++) + /* + * the first inlet is always a signal + * + * SDY We are warning the user till this limitation + * is taken away from pd + */ + if (!i || x->exp_var[i].ex_type == ET_VI || + x->exp_var[i].ex_type == ET_XI) { + if (nv >= x->exp_nivec) { + post("expr_dsp int. err nv = %d, x->exp_nive = %d", + nv, x->exp_nivec); + abort(); + } + x->exp_var[i].ex_vec = sp[nv]->s_vec; + nv++; + } + /* we always have one inlet but we may not use it */ + if (nv != x->exp_nivec && (nv != 0 || x->exp_nivec != 1)) { + post("expr_dsp internal error 2 nv = %d, x->exp_nive = %d", + nv, x->exp_nivec); + abort(); + } + + dsp_add(expr_perform, 1, (t_int *) x); + + /* + * The buffer are now being allocated for expr~ and fexpr~ + * because if we have more than one expression we need the + * temporary buffers, The save buffers are not really needed + if (!IS_FEXPR_TILDE(x)) + return; + */ + /* + * if we have already allocated the buffers and we have a + * new size free all the buffers + */ + if (x->exp_p_res[0]) { + if (!newsize) + return; + /* + * if new size, reallocate all the previous buffers for fexpr~ + */ + for (i = 0; i < x->exp_nexpr; i++) { + fts_free(x->exp_p_res[i]); + fts_free(x->exp_tmpres[i]); + } + for (i = 0; i < MAX_VARS; i++) + fts_free(x->exp_p_var[i]); + + } + for (i = 0; i < x->exp_nexpr; i++) { + x->exp_p_res[i] = fts_calloc(x->exp_vsize, sizeof (t_float)); + x->exp_tmpres[i] = fts_calloc(x->exp_vsize, sizeof (t_float)); + } + for (i = 0; i < MAX_VARS; i++) + x->exp_p_var[i] = fts_calloc(x->exp_vsize, sizeof (t_float)); +} + +/* + * expr_verbose -- toggle the verbose switch + */ +static void +expr_verbose(t_expr *x) +{ + if (x->exp_flags & EF_VERBOSE) { + x->exp_flags &= ~EF_VERBOSE; + post ("verbose off"); + } else { + x->exp_flags |= EF_VERBOSE; + post ("verbose on"); + } +} + +/* + * expr_start -- turn on expr processing for now only used for fexpr~ + */ +static void +expr_start(t_expr *x) +{ + x->exp_flags &= ~EF_STOP; +} + +/* + * expr_stop -- turn on expr processing for now only used for fexpr~ + */ +static void +expr_stop(t_expr *x) +{ + x->exp_flags |= EF_STOP; +} +static void +fexpr_set_usage(void) +{ + post("fexpr~: set val ..."); + post("fexpr~: set {xy}[#] val ..."); +} + +/* + * fexpr_tilde_set -- set previous values of the buffers + * set val val ... - sets the first elements of output buffers + * set x val ... - sets the elements of the first input buffer + * set x# val ... - sets the elements of the #th input buffers + * set y val ... - sets the elements of the first output buffer + * set y# val ... - sets the elements of the #th output buffers + */ +static void +fexpr_tilde_set(t_expr *x, t_symbol *s, int argc, t_atom *argv) +{ + t_symbol *sx; + int vecno; + int i, nargs; + + if (!argc) + return; + sx = atom_getsymbolarg(0, argc, argv); + switch(sx->s_name[0]) { + case 'x': + if (!sx->s_name[1]) + vecno = 0; + else { + vecno = atoi(sx->s_name + 1); + if (!vecno) { + post("fexpr~.set: bad set x vector number"); + fexpr_set_usage(); + return; + } + if (vecno >= MAX_VARS) { + post("fexpr~.set: no more than %d inlets", + MAX_VARS); + return; + } + vecno--; + } + if (x->exp_var[vecno].ex_type != ET_XI) { + post("fexpr~-set: no signal at inlet %d", vecno + 1); + return; + } + nargs = argc - 1; + if (!nargs) { + post("fexpr~-set: no argument to set"); + return; + } + if (nargs > x->exp_vsize) { + post("fexpr~.set: %d set values larger than vector size(%d)", + nargs, x->exp_vsize); + post("fexpr~.set: only the first %d values will be set", + x->exp_vsize); + nargs = x->exp_vsize; + } + for (i = 0; i < nargs; i++) { + x->exp_p_var[vecno][x->exp_vsize - i - 1] = + atom_getfloatarg(i + 1, argc, argv); + } + return; + case 'y': + if (!sx->s_name[1]) + vecno = 0; + else { + vecno = atoi(sx->s_name + 1); + if (!vecno) { + post("fexpr~.set: bad set y vector number"); + fexpr_set_usage(); + return; + } + vecno--; + } + if (vecno >= x->exp_nexpr) { + post("fexpr~.set: only %d outlets", x->exp_nexpr); + return; + } + nargs = argc - 1; + if (!nargs) { + post("fexpr~-set: no argument to set"); + return; + } + if (nargs > x->exp_vsize) { + post("fexpr~-set: %d set values larger than vector size(%d)", + nargs, x->exp_vsize); + post("fexpr~.set: only the first %d values will be set", + x->exp_vsize); + nargs = x->exp_vsize; + } + for (i = 0; i < nargs; i++) { + x->exp_p_res[vecno][x->exp_vsize - i - 1] = + atom_getfloatarg(i + 1, argc, argv); + } + return; + case 0: + if (argc > x->exp_nexpr) { + post("fexpr~.set: only %d outlets available", + x->exp_nexpr); + post("fexpr~.set: the extra set values are ignored"); + } + for (i = 0; i < x->exp_nexpr && i < argc; i++) + x->exp_p_res[i][x->exp_vsize - 1] = + atom_getfloatarg(i, argc, argv); + return; + default: + fexpr_set_usage(); + return; + } + return; +} + +/* + * fexpr_tilde_clear - clear the past buffers + */ +static void +fexpr_tilde_clear(t_expr *x, t_symbol *s, int argc, t_atom *argv) +{ + t_symbol *sx; + int vecno; + int i, nargs; + + /* + * if no arguement clear all input and output buffers + */ + if (!argc) { + for (i = 0; i < x->exp_nexpr; i++) + memset(x->exp_p_res[i], 0, x->exp_vsize*sizeof(float)); + for (i = 0; i < MAX_VARS; i++) + if (x->exp_var[i].ex_type == ET_XI) + memset(x->exp_p_var[i], 0, + x->exp_vsize*sizeof(float)); + return; + } + if (argc > 1) { + post("fexpr~ usage: 'clear' or 'clear {xy}[#]'"); + return; + } + + sx = atom_getsymbolarg(0, argc, argv); + switch(sx->s_name[0]) { + case 'x': + if (!sx->s_name[1]) + vecno = 0; + else { + vecno = atoi(sx->s_name + 1); + if (!vecno) { + post("fexpr~.clear: bad clear x vector number"); + return; + } + if (vecno >= MAX_VARS) { + post("fexpr~.clear: no more than %d inlets", + MAX_VARS); + return; + } + vecno--; + } + if (x->exp_var[vecno].ex_type != ET_XI) { + post("fexpr~-clear: no signal at inlet %d", vecno + 1); + return; + } + memset(x->exp_p_var[vecno], 0, x->exp_vsize*sizeof(float)); + return; + case 'y': + if (!sx->s_name[1]) + vecno = 0; + else { + vecno = atoi(sx->s_name + 1); + if (!vecno) { + post("fexpr~.clear: bad clear y vector number"); + return; + } + vecno--; + } + if (vecno >= x->exp_nexpr) { + post("fexpr~.clear: only %d outlets", x->exp_nexpr); + return; + } + memset(x->exp_p_res[vecno], 0, x->exp_vsize*sizeof(float)); + return; + return; + default: + post("fexpr~ usage: 'clear' or 'clear {xy}[#]'"); + return; + } + return; +} + +#ifdef PD + +void +expr_setup(void) +{ + /* + * expr initialization + */ + expr_class = class_new(gensym("expr"), (t_newmethod)expr_new, + (t_method)expr_ff, sizeof(t_expr), 0, A_GIMME, 0); + class_addlist(expr_class, expr_list); + exprproxy_class = class_new(gensym("exprproxy"), 0, + 0, sizeof(t_exprproxy), CLASS_PD, 0); + class_addfloat(exprproxy_class, exprproxy_float); + + /* + * expr~ initialization + */ + expr_tilde_class = class_new(gensym("expr~"), (t_newmethod)expr_new, + (t_method)expr_ff, sizeof(t_expr), 0, A_GIMME, 0); + class_addmethod(expr_tilde_class, nullfn, gensym("signal"), 0); + CLASS_MAINSIGNALIN(expr_tilde_class, t_expr, exp_f); + class_addmethod(expr_tilde_class,(t_method)expr_dsp, gensym("dsp"), 0); + class_sethelpsymbol(expr_tilde_class, gensym("expr")); + /* + * fexpr~ initialization + */ + fexpr_tilde_class = class_new(gensym("fexpr~"), (t_newmethod)expr_new, + (t_method)expr_ff, sizeof(t_expr), 0, A_GIMME, 0); + class_addmethod(fexpr_tilde_class, nullfn, gensym("signal"), 0); + class_addmethod(fexpr_tilde_class,(t_method)expr_start, + gensym("start"), 0); + class_addmethod(fexpr_tilde_class,(t_method)expr_stop, + gensym("stop"), 0); + + class_addmethod(fexpr_tilde_class,(t_method)expr_dsp,gensym("dsp"), 0); + class_addmethod(fexpr_tilde_class, (t_method)fexpr_tilde_set, + gensym("set"), A_GIMME, 0); + class_addmethod(fexpr_tilde_class, (t_method)fexpr_tilde_clear, + gensym("clear"), A_GIMME, 0); + class_addmethod(fexpr_tilde_class,(t_method)expr_verbose, + gensym("verbose"), 0); + class_sethelpsymbol(fexpr_tilde_class, gensym("expr")); + + + + post("expr, expr~, fexpr~ version %s under GNU General Public License ", exp_version); + +} + +void +expr_tilde_setup(void) +{ + expr_setup(); +} + +void +fexpr_tilde_setup(void) +{ + expr_setup(); +} +#else /* MSP */ +void +main(void) +{ + setup((t_messlist **)&expr_tilde_class, (method)Nexpr_new, + (method)expr_ff, (short)sizeof(t_expr), 0L, A_GIMME, 0); + addmess((method)expr_dsp, "dsp", A_CANT, 0); // dsp method + dsp_initclass(); +} +#endif + + +/* -- the following functions use Pd internals and so are in the "if" file. */ + + +int +ex_getsym(char *p, fts_symbol_t *s) +{ + *s = gensym(p); + return (0); +} + +const char * +ex_symname(fts_symbol_t s) +{ + return (fts_symbol_name(s)); +} + +/* + * max_ex_tab -- evaluate this table access + * eptr is the name of the table and arg is the index we + * have to put the result in optr + * return 1 on error and 0 otherwise + * + * Arguments: + * the expr object + * table + * the argument + * the result pointer + */ +int +max_ex_tab(struct expr *expr, fts_symbol_t s, struct ex_ex *arg, + struct ex_ex *optr) +{ +#ifdef PD + t_garray *garray; + int size, indx; + t_word *wvec; + + if (!s || !(garray = (t_garray *)pd_findbyclass(s, garray_class)) || + !garray_getfloatwords(garray, &size, &wvec)) + { + optr->ex_type = ET_FLT; + optr->ex_flt = 0; + pd_error(expr, "no such table '%s'", s->s_name); + return (1); + } + optr->ex_type = ET_FLT; + + switch (arg->ex_type) { + case ET_INT: + indx = arg->ex_int; + break; + case ET_FLT: + /* strange interpolation code deleted here -msp */ + indx = arg->ex_flt; + break; + + default: /* do something with strings */ + pd_error(expr, "expr: bad argument for table '%s'\n", fts_symbol_name(s)); + indx = 0; + } + if (indx < 0) indx = 0; + else if (indx >= size) indx = size - 1; + optr->ex_flt = wvec[indx].w_float; +#else /* MSP */ + /* + * table lookup not done for MSP yet + */ + post("max_ex_tab: not complete for MSP yet!"); + optr->ex_type = ET_FLT; + optr->ex_flt = 0; +#endif + return (0); +} + +int +max_ex_var(struct expr *expr, fts_symbol_t var, struct ex_ex *optr) +{ + optr->ex_type = ET_FLT; + if (value_getfloat(var, &(optr->ex_flt))) { + optr->ex_type = ET_FLT; + optr->ex_flt = 0; + pd_error(expr, "no such var '%s'", var->s_name); + return (1); + } + return (0); +} + +#ifdef PD /* this goes to the end of this file as the following functions + * should be defined in the expr object in MSP + */ +#define ISTABLE(sym, garray, size, vec) \ +if (!sym || !(garray = (t_garray *)pd_findbyclass(sym, garray_class)) || \ + !garray_getfloatwords(garray, &size, &vec)) { \ + optr->ex_type = ET_FLT; \ + optr->ex_int = 0; \ + error("no such table '%s'", sym->s_name); \ + return; \ +} + +/* + * ex_size -- find the size of a table + */ +void +ex_size(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + t_symbol *s; + t_garray *garray; + int size; + t_word *wvec; + + if (argv->ex_type != ET_SYM) + { + post("expr: size: need a table name\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + return; + } + + s = (fts_symbol_t ) argv->ex_ptr; + + ISTABLE(s, garray, size, wvec); + + optr->ex_type = ET_INT; + optr->ex_int = size; +} + +/* + * ex_sum -- calculate the sum of all elements of a table + */ + +void +ex_sum(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + t_symbol *s; + t_garray *garray; + int size; + t_word *wvec; + float sum; + int indx; + + if (argv->ex_type != ET_SYM) + { + post("expr: sum: need a table name\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + return; + } + + s = (fts_symbol_t ) argv->ex_ptr; + + ISTABLE(s, garray, size, wvec); + + for (indx = 0, sum = 0; indx < size; indx++) + sum += wvec[indx].w_float; + + optr->ex_type = ET_FLT; + optr->ex_flt = sum; +} + + +/* + * ex_Sum -- calculate the sum of table with the given boundries + */ + +void +ex_Sum(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ + t_symbol *s; + t_garray *garray; + int size; + t_word *wvec; + t_float sum; + int indx, n1, n2; + + if (argv->ex_type != ET_SYM) + { + post("expr: sum: need a table name\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + return; + } + + s = (fts_symbol_t ) argv->ex_ptr; + + ISTABLE(s, garray, size, wvec); + + if (argv->ex_type != ET_INT || argv[1].ex_type != ET_INT) + { + post("expr: Sum: boundries have to be fix values\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + return; + } + n1 = argv->ex_int; + n2 = argv[1].ex_int; + + for (indx = n1, sum = 0; indx < n2; indx++) + if (indx >= 0 && indx < size) + sum += wvec[indx].w_float; + + optr->ex_type = ET_FLT; + optr->ex_flt = sum; +} + +/* + * ex_avg -- calculate the avarage of a table + */ + +void +ex_avg(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ +/* SDY - look into this function */ +#if 0 + fts_symbol_t s; + fts_integer_vector_t *tw = 0; + + if (argv->ex_type != ET_SYM) + { + post("expr: avg: need a table name\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + } + + s = (fts_symbol_t ) argv->ex_ptr; + + tw = table_integer_vector_get_by_name(s); + + if (tw) + { + optr->ex_type = ET_INT; + + if (! fts_integer_vector_get_size(tw)) + optr->ex_int = 0; + else + optr->ex_int = fts_integer_vector_get_sum(tw) / fts_integer_vector_get_size(tw); + } + else + { + optr->ex_type = ET_INT; + optr->ex_int = 0; + post("expr: avg: no such table %s\n", fts_symbol_name(s)); + } +#endif +} + + +/* + * ex_Avg -- calculate the avarage of table with the given boundries + */ + +void +ex_Avg(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ +/* SDY - look into this function */ +#if 0 + fts_symbol_t s; + fts_integer_vector_t *tw = 0; + + if (argv->ex_type != ET_SYM) + { + post("expr: Avg: need a table name\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + } + + s = (fts_symbol_t ) (argv++)->ex_ptr; + + tw = table_integer_vector_get_by_name(s); + + if (! tw) + { + optr->ex_type = ET_INT; + optr->ex_int = 0; + post("expr: Avg: no such table %s\n", fts_symbol_name(s)); + return; + } + + if (argv->ex_type != ET_INT || argv[1].ex_type != ET_INT) + { + post("expr: Avg: boundries have to be fix values\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + return; + } + + optr->ex_type = ET_INT; + + if (argv[1].ex_int - argv->ex_int <= 0) + optr->ex_int = 0; + else + optr->ex_int = (fts_integer_vector_get_sub_sum(tw, argv->ex_int, argv[1].ex_int) / + (argv[1].ex_int - argv->ex_int)); +#endif +} + +/* + * ex_store -- store a value in a table + * if the index is greater the size of the table, + * we will make a modulo the size of the table + */ + +void +ex_store(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr) +{ +/* SDY - look into this function */ +#if 0 + fts_symbol_t s; + fts_integer_vector_t *tw = 0; + + if (argv->ex_type != ET_SYM) + { + post("expr: store: need a table name\n"); + } + + s = (fts_symbol_t ) (argv++)->ex_ptr; + + tw = table_integer_vector_get_by_name(s); + + if (! tw) + { + optr->ex_type = ET_INT; + optr->ex_int = 0; + post("expr: store: no such table %s\n", fts_symbol_name(s)); + return; + } + + if (argv->ex_type != ET_INT || argv[1].ex_type != ET_INT) + { + post("expr: store: arguments have to be integer\n"); + optr->ex_type = ET_INT; + optr->ex_int = 0; + } + + fts_integer_vector_set_element(tw, argv->ex_int < 0 ? 0 : argv->ex_int % fts_integer_vector_get_size(tw), argv[1].ex_int); + *optr = argv[1]; +#endif +} + +#else /* MSP */ + +void +pd_error(void *object, char *fmt, ...) +{ + va_list ap; + t_int arg[8]; + int i; + static int saidit = 0; + va_start(ap, fmt); +/* SDY + vsprintf(error_string, fmt, ap); + */ post(fmt, ap); + va_end(ap); +/* SDY + fprintf(stderr, "error: %s\n", error_string); + error_object = object; +*/ + if (!saidit) + { + post("... you might be able to track this down from the Find menu."); + saidit = 1; + } +} +#endif diff --git a/extra/fiddle~/fiddle~-help.pd b/extra/fiddle~/fiddle~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..f396725a001bc0572fcf09ee54761a31794c38c0 --- /dev/null +++ b/extra/fiddle~/fiddle~-help.pd @@ -0,0 +1,142 @@ +#N canvas 93 26 980 745 10; +#X obj 262 522 phasor~; +#X obj 531 616 unpack; +#X floatatom 531 666 0 0 0 0 - - -; +#X msg 437 449 print; +#X obj 262 500 sig~; +#X floatatom 262 478 0 0 0 0 - - -; +#X obj 262 456 mtof; +#X floatatom 262 434 0 0 0 0 - - -; +#X floatatom 545 643 0 0 0 0 - - -; +#X obj 531 576 route 1 2 3 4; +#X obj 614 616 unpack; +#X floatatom 614 666 0 0 0 0 - - -; +#X floatatom 628 643 0 0 0 0 - - -; +#X obj 698 616 unpack; +#X floatatom 698 666 0 0 0 0 - - -; +#X floatatom 712 643 0 0 0 0 - - -; +#X obj 389 616 unpack; +#X floatatom 389 666 0 0 0 0 - - -; +#X floatatom 403 643 0 0 0 0 - - -; +#X obj 334 545 *~; +#X obj 322 394 loadbang; +#X obj 353 522 sig~; +#X floatatom 353 500 0 0 0 0 - - -; +#X msg 322 478 1; +#X msg 353 478 0; +#X floatatom 466 666 0 0 0 0 - - -; +#X obj 281 666 print attack; +#X obj 190 666 print pitch; +#X msg 555 45 \; pd dsp 1; +#X text 460 39 click here; +#X text 460 61 to start DSP; +#X text 226 4 FIDDLE - pitch estimator and sinusoidal peak finder; +#X text 8 70 The Fiddle object estimates the pitch and amplitude of +an incoming sound \, both continuously and as a stream of discrete +"note" events. Fiddle optionally outputs a list of detected sinusoidal +peaks used to make the pitch determination. Fiddle is described theoretically +in the 1998 ICMC proceedings \, reprinted on http://man104nfs.ucsd.edu/~mpuckett. +; +#X text 8 170 Fiddle's creation arguments specify an analysis window +size \, the maximum polyphony (i.e. \, the number of simultaneous "pitches" +to try to find) \, the number of peaks in the spectrum to consider +\, and the number of peaks \, if any \, to output "raw." The outlets +give discrete pitch (a number) \, detected attacks in the amplitude +envelope (a bang) \, one or more voices of continuous pitch and amplitude +\, overall amplitude \, and optionally a sequence of messages with +the peaks.; +#X text 8 296 The analysis hop size is half the window size so in the +example shown here \, one analysis is done every 512 samples (11.6 +msec at 44K1) \, and the analysis uses the most recent 1024 samples +(23.2 msec at 44K1). The minimum frequency that Fiddle will report +is 2-1/2 cycles per analysis windows \, or about 108 Hz. (just below +MIDI 45.); +#X text 669 535 number of pitch outlets (1-3 \, default 1); +#X text 669 557 number of peaks to find (1-100 \, default 20); +#X text 669 579 number of peaks to output (default 0.); +#X msg 441 107 amp-range 40 50; +#X msg 439 227 reattack 100 10; +#X msg 438 282 npartial 7; +#X msg 438 170 vibrato 50 0.5; +#X text 560 91 a low and high amplitude threshold: if signal amplitude +is below the low threshold \, no pitches or peaks are output. The high +threshold is a minimum at which "cooked" outputs may appear.; +#X text 560 152 A period in milliseconds (50) over which the raw pitch +may not deviate more than an interval in half-tones (0.5) from the +average pitch to report it as a note to the "cooked" pitch outlet. +; +#X text 560 213 A period in milliseconds (100) over which a re-attack +is reported if the amplitude rises more than (1) dB. The re-attack +will result in a "bang" in the attack outlet and may give rise to repeated +notes in the cooked pitch output.; +#X text 142 432 test input pitch; +#X text 330 444 test input; +#X text 330 457 amplitude; +#X obj 410 545 fiddle~ 1024 1 20 3; +#X text 538 690 individual sinusoidal components; +#X text 466 688 amplitude; +#X text 476 703 (dB); +#X text 389 688 raw pitch; +#X text 376 712 and amplitude; +#X text 364 729 (up to 3 outputs); +#X text 287 686 bang on; +#X text 287 708 attack; +#X text 185 686 cooked pitch; +#X text 202 703 output; +#X text 545 545 ------ arguments:; +#X msg 262 412 57; +#X msg 440 331 auto 1; +#X msg 440 353 auto 0; +#X msg 439 418 bang; +#X text 561 416 poll current values --- useful if not in auto mode +\,; +#X text 560 274 Higher partials are weighed less strongly than lower +ones in determining the pitch. This specifies the number of the partial +(7) which will be weighted half as strongly as the fundamental.; +#X text 560 335 start and stop "auto" mode (on by default.) If off +\, output only appears on "bang" (poll mode).; +#X text 561 448 print out all settings; +#X text 669 513 window size (128-2048 \, default 1024); +#X msg 440 375 npoints 2048; +#X text 562 384 number of points in analysis window (power of 2 \, +128-2048); +#X msg 439 396 npoints 1024; +#X connect 0 0 19 0; +#X connect 1 0 2 0; +#X connect 1 1 8 0; +#X connect 3 0 48 0; +#X connect 4 0 0 0; +#X connect 5 0 4 0; +#X connect 6 0 5 0; +#X connect 7 0 6 0; +#X connect 9 0 1 0; +#X connect 9 1 10 0; +#X connect 9 2 13 0; +#X connect 10 0 11 0; +#X connect 10 1 12 0; +#X connect 13 0 14 0; +#X connect 13 1 15 0; +#X connect 16 0 17 0; +#X connect 16 1 18 0; +#X connect 19 0 48 0; +#X connect 20 0 60 0; +#X connect 20 0 23 0; +#X connect 21 0 19 1; +#X connect 22 0 21 0; +#X connect 23 0 22 0; +#X connect 24 0 22 0; +#X connect 38 0 48 0; +#X connect 39 0 48 0; +#X connect 40 0 48 0; +#X connect 41 0 48 0; +#X connect 48 0 27 0; +#X connect 48 1 26 0; +#X connect 48 2 16 0; +#X connect 48 3 25 0; +#X connect 48 4 9 0; +#X connect 60 0 7 0; +#X connect 61 0 48 0; +#X connect 62 0 48 0; +#X connect 63 0 48 0; +#X connect 69 0 48 0; +#X connect 71 0 48 0; diff --git a/extra/fiddle~/fiddle~.c b/extra/fiddle~/fiddle~.c new file mode 100644 index 0000000000000000000000000000000000000000..4633b3c0510fbd72d652ee9a9c54fc0a3f38afba --- /dev/null +++ b/extra/fiddle~/fiddle~.c @@ -0,0 +1,1851 @@ +/* Copyright (c) 1997-1999 Miller Puckette and Ted Apel. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* + * Fiddle is a pitch tracker hardwired to have hop size ("H") equal to + * half its window size ("N"). + * + * This version should compile for Max "0.26," JMAX, Pd, or Max/MSP. + * + * The "lastanalysis" field holds the shifted FT of the previous H + * samples. The buffer contains in effect points 1/2, 3/2, ..., (N-1)/2 + * of the DTFT of a real vector of length N, half of whose points are zero, + * i.e., only the first H points are used. Put another way, we get the + * the odd-numbered points of the FFT of the H points, zero padded to 4*H in + * length. The integer points 0, 1, ..., H-1 + * are found by interpolating these others, using the fact that the + * half-integer points are band-limited (they only have positive frequencies.) + * To facilitate the interpolation the "lastanalysis" buffer contains + * FILTSIZE extra points (1/2-FILTSIZE, ..., -1/2) at the beginning and + * FILTSIZE again at the end ((N+1)/2, ..., FILTSIZE+(N-1)/2). The buffer + * therefore has N+4*FILTSIZE floating-point numbers in it. + * + * after doing this I found out that you can just do a real FFT + * of the H new points, zero-padded to contain N points, and using a similar + * but simpler interpolation scheme you can still get 2N points of the DTFT + * of the N points. Jean Laroche is a big fat hen. + * + */ + + +/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans@at.or.at> */ +#ifdef _MSC_VER +#pragma warning (disable: 4305 4244) +#endif + +/* this #ifdef does nothing, but its there... */ +#ifdef _WIN32 +#define flog log +#define fexp exp +#define fsqrt sqrt +#else +#define flog log +#define fexp exp +#define fsqrt sqrt +#endif + +char fiddle_version[] = "fiddle version 1.1 TEST4"; + +#ifdef JMAX +#include "fts.h" +#include <stdio.h> +#include <stdlib.h> +typedef float t_float; +typedef float t_floatarg; +typedef fts_symbol_t t_symbol; + +static void *getbytes(size_t nbytes) +{ + void *ret; + if (nbytes < 1) nbytes = 1; + ret = (void *)malloc(nbytes); + return (ret); +} + +static void *resizebytes(void *old, size_t oldsize, size_t newsize) +{ + void *ret; + if (newsize < 1) newsize = 1; + ret = (void *)realloc((char *)old, newsize); + return (ret); +} + +static void freebytes(void *fatso, size_t nbytes) +{ + free(fatso); +} + +#define CLASSNAME "fiddle" + +#define OUTLETpower 5 +#define OUTLETmicropitch1 4 +#define OUTLETmicropitch2 3 +#define OUTLETmicropitch3 2 +#define OUTLETattack 1 +#define OUTLETpitch 0 + +static fts_symbol_t *dsp_symbol = 0; +#define error post + +#endif /* FTS */ + +#ifdef MAX26 +#define t_floatarg double +#include "m_extern.h" +#include "d_graph.h" +#include "d_ugen.h" +#endif /* MAX26 */ + +#ifdef PD +#include "m_pd.h" +#endif /* PD */ + +#ifdef MSP +#define flog log +#define fexp exp +#define fsqrt sqrt +#endif /* MSP */ + +#ifdef MSP +#define t_floatarg double +#include "ext.h" +#include "z_dsp.h" +#include "fft_mayer.proto.h" + +#endif /* MSP */ + +#include <math.h> + + +#define MINBIN 3 +#define DEFAMPLO 40 +#define DEFAMPHI 50 +#define DEFATTACKTIME 100 +#define DEFATTACKTHRESH 10 +#define DEFVIBTIME 50 +#define DEFVIBDEPTH 0.5 +#define GLISS 0.7f +#define DBFUDGE 30.8f +#define MINFREQINBINS 5 /* minimum frequency in bins for reliable output */ + +#define MAXNPITCH 3 +#define MAXHIST 3 /* find N hottest peaks in histogram */ + +#define MAXPOINTS 8192 +#define MINPOINTS 128 +#define DEFAULTPOINTS 1024 + +#define HISTORY 20 +#define MAXPEAK 100 /* maximum number of peaks */ +#define DEFNPEAK 20 /* default number of peaks */ + +#define MAXNPEAK (MAXLOWPEAK + MAXSTRONGPEAK) +#define MINBW (0.03f) /* consider BW >= 0.03 FFT bins */ + +#define BINPEROCT 48 /* bins per octave */ +#define BPERO_OVER_LOG2 69.24936196f /* BINSPEROCT/log(2) */ +#define FACTORTOBINS (float)(4/0.0145453) /* 4 / (pow(2.,1/48.) - 1) */ +#define BINGUARD 10 /* extra bins to throw in front */ +#define PARTIALDEVIANCE 0.023f /* acceptable partial detuning in % */ +#define LOGTODB 4.34294481903f /* 20/log(10) */ + +#define KNOCKTHRESH 10.f /* don't know how to describe this */ + + +static float sigfiddle_partialonset[] = +{ +0, +48, +76.0782000346154967102, +96, +111.45254855459339269887, +124.07820003461549671089, +134.75303625876499715823, +144, +152.15640006923099342109, +159.45254855459339269887, +166.05271769459026829915, +172.07820003461549671088, +177.62110647077242370064, +182.75303625876499715892, +187.53074858920888940907, +192, +}; + +#define NPARTIALONSET ((int)(sizeof(sigfiddle_partialonset)/sizeof(float))) + +static int sigfiddle_intpartialonset[] = +{ +0, +48, +76, +96, +111, +124, +135, +144, +152, +159, +166, +172, +178, +183, +188, +192, +}; + +/* these coefficients, which come from the "upsamp" subdirectory, +are a filter kernel for upsampling by a factor of two, assuming +the sound to be upsampled has no energy above half the Nyquist, i.e., +that it's already 2x oversampled compared to the theoretically possible +sample rate. I got these by trial and error. */ + +#define FILT1 ((float)(.5 * 1.227054)) +#define FILT2 ((float)(.5 * -0.302385)) +#define FILT3 ((float)(.5 * 0.095326)) +#define FILT4 ((float)(.5 * -0.022748)) +#define FILT5 ((float)(.5 * 0.002533)) +#define FILTSIZE 5 + +typedef struct peakout /* a peak for output */ +{ + float po_freq; /* frequency in hz */ + float po_amp; /* amplitude */ +} t_peakout; + +typedef struct peak /* a peak for analysis */ +{ + float p_freq; /* frequency in bins */ + float p_width; /* peak width in bins */ + float p_pow; /* peak power */ + float p_loudness; /* 4th root of power */ + float *p_fp; /* pointer back to spectrum */ +} t_peak; + +typedef struct histopeak +{ + float h_pitch; /* estimated pitch */ + float h_value; /* value of peak */ + float h_loud; /* combined strength of found partials */ + int h_index; /* index of bin holding peak */ + int h_used; /* true if an x_hist entry points here */ +} t_histopeak; + +typedef struct pitchhist /* struct for keeping history by pitch */ +{ + float h_pitch; /* pitch to output */ + float h_amps[HISTORY]; /* past amplitudes */ + float h_pitches[HISTORY]; /* past pitches */ + float h_noted; /* last pitch output */ + int h_age; /* number of frames pitch has been there */ + t_histopeak *h_wherefrom; /* new histogram peak to incorporate */ + void *h_outlet; +} t_pitchhist; + +typedef struct sigfiddle /* instance struct */ +{ +#ifdef JMAX + fts_object_t x_h; /* object header */ + fts_alarm_t x_clock; /* callback for timeouts */ +#endif +#ifdef MAX26 + t_head x_h; /* header for tilde objects */ + t_sig *x_io[IN1+OUT0]; /* number of signal inputs and outputs */ + void *x_clock; /* a "clock" object */ +#endif +#ifdef PD + t_object x_ob; /* object header */ + t_clock *x_clock; /* callback for timeouts */ +#endif +#ifdef MSP + t_pxobject x_obj; + void *x_clock; + long x_downsample; /* downsample feature because of + MSP's large sig vector sizes */ +#endif + float *x_inbuf; /* buffer to analyze, npoints/2 elems */ + float *x_lastanalysis; /* FT of last buffer (see main comment) */ + float *x_spiral; /* 1/4-wave complex exponential */ + t_peakout *x_peakbuf; /* spectral peaks for output */ + int x_npeakout; /* number of spectral peaks to output */ + int x_npeakanal; /* number of spectral peaks to analyze */ + int x_phase; /* number of points since last output */ + int x_histphase; /* phase into amplitude history vector */ + int x_hop; /* period of output, npoints/2 */ + float x_sr; /* sample rate */ + t_pitchhist x_hist[MAXNPITCH]; /* history of current pitches */ + int x_nprint; /* how many periods to print */ + int x_npitch; /* number of simultaneous pitches */ + float x_dbs[HISTORY]; /* DB history, indexed by "histphase" */ + float x_peaked; /* peak since last attack */ + int x_dbage; /* number of bins DB has met threshold */ + int x_auto; /* true if generating continuous output */ +/* parameters */ + float x_amplo; + float x_amphi; + int x_attacktime; + int x_attackbins; + float x_attackthresh; + int x_vibtime; + int x_vibbins; + float x_vibdepth; + float x_npartial; +/* outlets & clock */ + void *x_envout; + int x_attackvalue; + void *x_attackout; + void *x_noteout; + void *x_peakout; +} t_sigfiddle; + +#if CHECKER +float fiddle_checker[1024]; +#endif + +#ifdef MSP +/* Mac compiler requires prototypes for everything */ + +int sigfiddle_ilog2(int n); +float fiddle_mtof(float f); +float fiddle_ftom(float f); +void sigfiddle_doit(t_sigfiddle *x); +void sigfiddle_debug(t_sigfiddle *x); +void sigfiddle_print(t_sigfiddle *x); +void sigfiddle_assist(t_sigfiddle *x, void *b, long m, long a, char *s); +void sigfiddle_amprange(t_sigfiddle *x, double amplo, double amphi); +void sigfiddle_reattack(t_sigfiddle *x, t_floatarg attacktime, t_floatarg +attackthresh); +void sigfiddle_vibrato(t_sigfiddle *x, t_floatarg vibtime, t_floatarg +vibdepth); +void sigfiddle_npartial(t_sigfiddle *x, double npartial); +void sigfiddle_auto(t_sigfiddle *x, t_floatarg f); +void sigfiddle_setnpoints(t_sigfiddle *x, t_floatarg f); +int sigfiddle_doinit(t_sigfiddle *x, long npoints, long npitch, long +npeakanal, long npeakout); +static t_int *fiddle_perform(t_int *w); +void sigfiddle_dsp(t_sigfiddle *x, t_signal **sp); +void sigfiddle_tick(t_sigfiddle *x); +void sigfiddle_bang(t_sigfiddle *x); +void sigfiddle_ff(t_sigfiddle *x); +void *sigfiddle_new(long npoints, long npitch, + long npeakanal, long npeakout); +void msp_fft(float *buf, long np, long inv); +float msp_ffttemp[MAXPOINTS*2]; +int errno; +#endif + +int sigfiddle_ilog2(int n) +{ + int ret = -1; + while (n) + { + n >>= 1; + ret++; + } + return (ret); +} + +float fiddle_mtof(float f) +{ + return (8.17579891564 * exp(.0577622650 * f)); +} + +float fiddle_ftom(float f) +{ + return (17.3123405046 * log(.12231220585 * f)); +} +#define ftom fiddle_ftom +#define mtof fiddle_mtof + +void sigfiddle_doit(t_sigfiddle *x) +{ +#ifdef MSP + /* prevents interrupt-level stack overflow crash with Netscape. */ + static float spect1[4*MAXPOINTS]; + static float spect2[MAXPOINTS + 4*FILTSIZE]; +#else + float spect1[4*MAXPOINTS]; + float spect2[MAXPOINTS + 4*FILTSIZE]; +#endif +#if CHECKER + float checker3[4*MAXPOINTS]; +#endif + + t_peak peaklist[MAXPEAK + 1], *pk1; + t_peakout *pk2; + t_histopeak histvec[MAXHIST], *hp1; + int i, j, k, hop = x->x_hop, n = 2*hop, npeak, npitch, + logn = sigfiddle_ilog2(n), newphase, oldphase; + float *fp, *fp1, *fp2, *fp3, total_power, total_loudness, total_db; + float maxbin = BINPEROCT * (logn-2), *histogram = spect2 + BINGUARD; + t_pitchhist *phist; + float hzperbin = x->x_sr / (2.0f * n); + int npeakout = x->x_npeakout, npeakanal = x->x_npeakanal; + int npeaktot = (npeakout > npeakanal ? npeakout : npeakanal); + + oldphase = x->x_histphase; + newphase = x->x_histphase + 1; + if (newphase == HISTORY) newphase = 0; + x->x_histphase = newphase; + + /* + * multiply the H points by a 1/4-wave complex exponential, + * and take FFT of the result. + */ + for (i = 0, fp1 = x->x_inbuf, fp2 = x->x_spiral, fp3 = spect1; + i < hop; i++, fp1++, fp2 += 2, fp3 += 2) + fp3[0] = fp1[0] * fp2[0], fp3[1] = fp1[0] * fp2[1]; + +#ifdef MAX26 + fft(spect1, hop, 0); +#endif +#ifdef PD + pd_fft(spect1, hop, 0); +#endif +#ifdef JMAX + fts_cfft_inplc((complex *)spect1, hop); +#endif +#ifdef MSP + msp_fft(spect1,hop,0); +#endif + /* + * now redistribute the points to get in effect the odd-numbered + * points of the FFT of the H points, zero padded to 4*H in length. + */ + for (i = 0, fp1 = spect1, fp2 = spect2 + (2*FILTSIZE); + i < (hop>>1); i++, fp1 += 2, fp2 += 4) + fp2[0] = fp1[0], fp2[1] = fp1[1]; + for (i = 0, fp1 = spect1 + n - 2, fp2 = spect2 + (2*FILTSIZE+2); + i < (hop>>1); i++, fp1 -= 2, fp2 += 4) + fp2[0] = fp1[0], fp2[1] = -fp1[1]; + for (i = 0, fp1 = spect2 + (2*FILTSIZE), fp2 = spect2 + (2*FILTSIZE-2); + i<FILTSIZE; i++, fp1+=2, fp2-=2) + fp2[0] = fp1[0], fp2[1] = -fp1[1]; + for (i = 0, fp1 = spect2 + (2*FILTSIZE+n-2), fp2 = spect2 + (2*FILTSIZE+n); + i<FILTSIZE; i++, fp1-=2, fp2+=2) + fp2[0] = fp1[0], fp2[1] = -fp1[1]; +#if 0 + { + fp = spect2 + 2*FILTSIZE; + post("x1 re %12.4f %12.4f %12.4f %12.4f %12.4f", + fp[0], fp[2], fp[4], fp[6], fp[8]); + post("x1 im %12.4f %12.4f %12.4f %12.4f %12.4f", + fp[1], fp[3], fp[5], fp[7], fp[9]); + } +#endif + /* spect2 is now prepared; now combine spect2 and lastanalysis into + * spect1. Odd-numbered points of spect1 are the points of "last" + * plus (-i, i, -i, ...) times spect1. Even-numbered points are + * the interpolated points of "last" plus (1, -1, 1, ...) times the + * interpolated points of spect1. + * + * To interpolate, take FILT1 exp(-pi/4) times + * the previous point, FILT2*exp(-3*pi/4) times 3 bins before, + * etc, and FILT1 exp(pi/4), FILT2 exp(3pi/4), etc., to weight + * the +1, +3, etc., points. + * + * In this calculation, we take (1, i, -1, -i, 1) times the + * -9, -7, ..., -1 points, and (i, -1, -i, 1, i) times the 1, 3,..., 9 + * points of the OLD spectrum, alternately adding and subtracting + * the new spectrum to the old; then we multiply the whole thing + * by exp(-i pi/4). + */ + for (i = 0, fp1 = spect1, fp2 = x->x_lastanalysis + 2*FILTSIZE, + fp3 = spect2 + 2*FILTSIZE; + i < (hop>>1); i++) + { + float re, im; + + re= FILT1 * ( fp2[ -2] -fp2[ 1] +fp3[ -2] -fp3[ 1]) + + FILT2 * ( fp2[ -3] -fp2[ 2] +fp3[ -3] -fp3[ 2]) + + FILT3 * (-fp2[ -6] +fp2[ 5] -fp3[ -6] +fp3[ 5]) + + FILT4 * (-fp2[ -7] +fp2[ 6] -fp3[ -7] +fp3[ 6]) + + FILT5 * ( fp2[-10] -fp2[ 9] +fp3[-10] -fp3[ 9]); + + im= FILT1 * ( fp2[ -1] +fp2[ 0] +fp3[ -1] +fp3[ 0]) + + FILT2 * (-fp2[ -4] -fp2[ 3] -fp3[ -4] -fp3[ 3]) + + FILT3 * (-fp2[ -5] -fp2[ 4] -fp3[ -5] -fp3[ 4]) + + FILT4 * ( fp2[ -8] +fp2[ 7] +fp3[ -8] +fp3[ 7]) + + FILT5 * ( fp2[ -9] +fp2[ 8] +fp3[ -9] +fp3[ 8]); + + fp1[0] = 0.7071f * (re + im); + fp1[1] = 0.7071f * (im - re); + fp1[4] = fp2[0] + fp3[1]; + fp1[5] = fp2[1] - fp3[0]; + + fp1 += 8, fp2 += 2, fp3 += 2; + re= FILT1 * ( fp2[ -2] -fp2[ 1] -fp3[ -2] +fp3[ 1]) + + FILT2 * ( fp2[ -3] -fp2[ 2] -fp3[ -3] +fp3[ 2]) + + FILT3 * (-fp2[ -6] +fp2[ 5] +fp3[ -6] -fp3[ 5]) + + FILT4 * (-fp2[ -7] +fp2[ 6] +fp3[ -7] -fp3[ 6]) + + FILT5 * ( fp2[-10] -fp2[ 9] -fp3[-10] +fp3[ 9]); + + im= FILT1 * ( fp2[ -1] +fp2[ 0] -fp3[ -1] -fp3[ 0]) + + FILT2 * (-fp2[ -4] -fp2[ 3] +fp3[ -4] +fp3[ 3]) + + FILT3 * (-fp2[ -5] -fp2[ 4] +fp3[ -5] +fp3[ 4]) + + FILT4 * ( fp2[ -8] +fp2[ 7] -fp3[ -8] -fp3[ 7]) + + FILT5 * ( fp2[ -9] +fp2[ 8] -fp3[ -9] -fp3[ 8]); + + fp1[0] = 0.7071f * (re + im); + fp1[1] = 0.7071f * (im - re); + fp1[4] = fp2[0] - fp3[1]; + fp1[5] = fp2[1] + fp3[0]; + + fp1 += 8, fp2 += 2, fp3 += 2; + } +#if 0 + if (x->x_nprint) + { + for (i = 0, fp = spect1; i < 16; i++, fp+= 4) + post("spect %d %f %f --> %f", i, fp[0], fp[1], + sqrt(fp[0] * fp[0] + fp[1] * fp[1])); + } +#endif + /* copy new spectrum out */ + for (i = 0, fp1 = spect2, fp2 = x->x_lastanalysis; + i < n + 4*FILTSIZE; i++) *fp2++ = *fp1++; + + for (i = 0; i < MINBIN; i++) spect1[4*i + 2] = spect1[4*i + 3] = 0; + /* starting at bin MINBIN, compute hanning windowed power spectrum */ + for (i = MINBIN, fp1 = spect1+4*MINBIN, total_power = 0; + i < n-2; i++, fp1 += 4) + { + float re = fp1[0] - 0.5f * (fp1[-8] + fp1[8]); + float im = fp1[1] - 0.5f * (fp1[-7] + fp1[9]); + fp1[3] = (total_power += (fp1[2] = re * re + im * im)); + } + + if (total_power > 1e-9f) + { + total_db = (100.f - DBFUDGE) + LOGTODB * log(total_power/n); + total_loudness = fsqrt(fsqrt(total_power)); + if (total_db < 0) total_db = 0; + } + else total_db = total_loudness = 0; + /* store new db in history vector */ + x->x_dbs[newphase] = total_db; + if (total_db < x->x_amplo) goto nopow; +#if 1 + if (x->x_nprint) post("power %f", total_power); +#endif + +#if CHECKER + /* verify that our FFT resampling thing is putting out good results */ + for (i = 0; i < hop; i++) + { + checker3[2*i] = fiddle_checker[i]; + checker3[2*i + 1] = 0; + checker3[n + 2*i] = fiddle_checker[i] = x->x_inbuf[i]; + checker3[n + 2*i + 1] = 0; + } + for (i = 2*n; i < 4*n; i++) checker3[i] = 0; + fft(checker3, 2*n, 0); + if (x->x_nprint) + { + for (i = 0, fp = checker3; i < 16; i++, fp += 2) + post("spect %d %f %f --> %f", i, fp[0], fp[1], + sqrt(fp[0] * fp[0] + fp[1] * fp[1])); + } + +#endif + npeak = 0; + + /* search for peaks */ + for (i = MINBIN, fp = spect1+4*MINBIN, pk1 = peaklist; + i < n-2 && npeak < npeaktot; i++, fp += 4) + { + float height = fp[2], h1 = fp[-2], h2 = fp[6]; + float totalfreq, pfreq, f1, f2, m, var, stdev; + + if (height < h1 || height < h2 || + h1 < 0.00001f*total_power || h2 < 0.00001f*total_power) + continue; + + /* use an informal phase vocoder to estimate the frequency. + Do this for the two adjacent bins too. */ + pfreq= ((fp[-8] - fp[8]) * (2.0f * fp[0] - fp[8] - fp[-8]) + + (fp[-7] - fp[9]) * (2.0f * fp[1] - fp[9] - fp[-7])) / + (2.0f * height); + f1= ((fp[-12] - fp[4]) * (2.0f * fp[-4] - fp[4] - fp[-12]) + + (fp[-11] - fp[5]) * (2.0f * fp[-3] - fp[5] - fp[-11])) / + (2.0f * h1) - 1; + f2= ((fp[-4] - fp[12]) * (2.0f * fp[4] - fp[12] - fp[-4]) + + (fp[-3] - fp[13]) * (2.0f * fp[5] - fp[13] - fp[-3])) / + (2.0f * h2) + 1; + + /* get sample mean and variance of the three */ + m = 0.333333f * (pfreq + f1 + f2); + var = 0.5f * ((pfreq-m)*(pfreq-m) + (f1-m)*(f1-m) + (f2-m)*(f2-m)); + + totalfreq = i + m; + if (var * total_power > KNOCKTHRESH * height || var < 1e-30) + { +#if 0 + if (x->x_nprint) + post("cancel: %.2f hz, index %.1f, power %.5f, stdev=%.2f", + totalfreq * hzperbin, BPERO_OVER_LOG2 * log(totalfreq) - 96, + height, sqrt(var)); +#endif + continue; + } + stdev = fsqrt(var); + if (totalfreq < 4) + { + if (x->x_nprint) post("oops: was %d, freq %f, m %f, stdev %f h %f", + i, totalfreq, m, stdev, height); + totalfreq = 4; + } + pk1->p_width = stdev; + + pk1->p_pow = height; + pk1->p_loudness = fsqrt(fsqrt(height)); + pk1->p_fp = fp; + pk1->p_freq = totalfreq; + npeak++; +#if 1 + if (x->x_nprint) + { + post("peak: %.2f hz. index %.1f, power %.5f, stdev=%.2f", + pk1->p_freq * hzperbin, + BPERO_OVER_LOG2 * log(pk1->p_freq) - 96, + height, stdev); + } +#endif + pk1++; + } + + /* prepare the raw peaks for output */ + for (i = 0, pk1 = peaklist, pk2 = x->x_peakbuf; i < npeak; + i++, pk1++, pk2++) + { + float loudness = pk1->p_loudness; + if (i >= npeakout) break; + pk2->po_freq = hzperbin * pk1->p_freq; + pk2->po_amp = (2.f / (float)n) * (loudness * loudness); + } + for (; i < npeakout; i++, pk2++) pk2->po_amp = pk2->po_freq = 0; + + /* now, working back into spect2, make a sort of "liklihood" + * spectrum. Proceeding in 48ths of an octave, from 2 to + * n/2 (in bins), the likelihood of each pitch range is contributed + * to by every peak in peaklist that's an integer multiple of it + * in frequency. + */ + + if (npeak > npeakanal) npeak = npeakanal; /* max # peaks to analyze */ + for (i = 0, fp1 = histogram; i < maxbin; i++) *fp1++ = 0; + for (i = 0, pk1 = peaklist; i < npeak; i++, pk1++) + { + float pit = BPERO_OVER_LOG2 * flog(pk1->p_freq) - 96.0f; + float binbandwidth = FACTORTOBINS * pk1->p_width/pk1->p_freq; + float putbandwidth = (binbandwidth < 2 ? 2 : binbandwidth); + float weightbandwidth = (binbandwidth < 1.0f ? 1.0f : binbandwidth); + /* float weightamp = 1.0f + 3.0f * pk1->p_pow / pow; */ + float weightamp = 4. * pk1->p_loudness / total_loudness; + for (j = 0, fp2 = sigfiddle_partialonset; j < NPARTIALONSET; j++, fp2++) + { + float bin = pit - *fp2; + if (bin < maxbin) + { + float para, pphase, score = 30.0f * weightamp / + ((j+x->x_npartial) * weightbandwidth); + int firstbin = bin + 0.5f - 0.5f * putbandwidth; + int lastbin = bin + 0.5f + 0.5f * putbandwidth; + int ibw = lastbin - firstbin; + if (firstbin < -BINGUARD) break; + para = 1.0f / (putbandwidth * putbandwidth); + for (k = 0, fp3 = histogram + firstbin, + pphase = firstbin-bin; k <= ibw; + k++, fp3++, pphase += 1.0f) + { + *fp3 += score * (1.0f - para * pphase * pphase); + } + } + } + } +#if 1 + if (x->x_nprint) + { + for (i = 0; i < 6*5; i++) + { + float fhz = hzperbin * exp ((8*i + 96) * (1./BPERO_OVER_LOG2)); + if (!(i % 6)) post("-- bin %d pitch %f freq %f----", 8*i, + ftom(fhz), fhz);; + post("%3d %3d %3d %3d %3d %3d %3d %3d", + (int)(histogram[8*i]), + (int)(histogram[8*i+1]), + (int)(histogram[8*i+2]), + (int)(histogram[8*i+3]), + (int)(histogram[8*i+4]), + (int)(histogram[8*i+5]), + (int)(histogram[8*i+6]), + (int)(histogram[8*i+7])); + } + } + +#endif + + /* + * Next we find up to NPITCH strongest peaks in the histogram. + * if a peak is related to a stronger one via an interval in + * the sigfiddle_partialonset array, we suppress it. + */ + + for (npitch = 0; npitch < x->x_npitch; npitch++) + { + int indx; + float best; + if (npitch) + { + for (best = 0, indx = -1, j=1; j < maxbin-1; j++) + { + if (histogram[j] > best && histogram[j] > histogram[j-1] && + histogram[j] > histogram[j+1]) + { + for (k = 0; k < npitch; k++) + if (histvec[k].h_index == j) + goto peaknogood; + for (k = 0; k < NPARTIALONSET; k++) + { + if (j - sigfiddle_intpartialonset[k] < 0) break; + if (histogram[j - sigfiddle_intpartialonset[k]] + > histogram[j]) goto peaknogood; + } + for (k = 0; k < NPARTIALONSET; k++) + { + if (j + sigfiddle_intpartialonset[k] >= maxbin) break; + if (histogram[j + sigfiddle_intpartialonset[k]] + > histogram[j]) goto peaknogood; + } + indx = j; + best = histogram[j]; + } + peaknogood: ; + } + } + else + { + for (best = 0, indx = -1, j=0; j < maxbin; j++) + if (histogram[j] > best) + indx = j, best = histogram[j]; + } + if (indx < 0) break; + histvec[npitch].h_value = best; + histvec[npitch].h_index = indx; + } +#if 1 + if (x->x_nprint) + { + for (i = 0; i < npitch; i++) + { + post("index %d freq %f --> value %f", histvec[i].h_index, + exp((1./BPERO_OVER_LOG2) * (histvec[i].h_index + 96)), + histvec[i].h_value); + post("next %f , prev %f", + exp((1./BPERO_OVER_LOG2) * (histvec[i].h_index + 97)), + exp((1./BPERO_OVER_LOG2) * (histvec[i].h_index + 95)) ); + } + } +#endif + + /* for each histogram peak, we now search back through the + * FFT peaks. A peak is a pitch if either there are several + * harmonics that match it, or else if (a) the fundamental is + * present, and (b) the sum of the powers of the contributing peaks + * is at least 1/100 of the total power. + * + * A peak is a contributor if its frequency is within 25 cents of + * a partial from 1 to 16. + * + * Finally, we have to be at least 5 bins in frequency, which + * corresponds to 2-1/5 periods fitting in the analysis window. + */ + + for (i = 0; i < npitch; i++) + { + float cumpow = 0, cumstrength = 0, freqnum = 0, freqden = 0; + int npartials = 0, nbelow8 = 0; + /* guessed-at frequency in bins */ + float putfreq = fexp((1.0f / BPERO_OVER_LOG2) * + (histvec[i].h_index + 96.0f)); + for (j = 0; j < npeak; j++) + { + float fpnum = peaklist[j].p_freq/putfreq; + int pnum = fpnum + 0.5f; + float fipnum = pnum; + float deviation; + if (pnum > 16 || pnum < 1) continue; + deviation = 1.0f - fpnum/fipnum; + if (deviation > -PARTIALDEVIANCE && deviation < PARTIALDEVIANCE) + { + /* + * we figure this is a partial since it's within 1/4 of + * a halftone of a multiple of the putative frequency. + */ + + float stdev, weight; + npartials++; + if (pnum < 8) nbelow8++; + cumpow += peaklist[j].p_pow; + cumstrength += fsqrt(fsqrt(peaklist[j].p_pow)); + stdev = (peaklist[j].p_width > MINBW ? + peaklist[j].p_width : MINBW); + weight = 1.0f / ((stdev*fipnum) * (stdev*fipnum)); + freqden += weight; + freqnum += weight * peaklist[j].p_freq/fipnum; +#if 1 + if (x->x_nprint) + { + post("peak %d partial %d f=%f w=%f", + j, pnum, peaklist[j].p_freq/fipnum, weight); + } +#endif + } +#if 1 + else if (x->x_nprint) post("peak %d partial %d dev %f", + j, pnum, deviation); +#endif + } + if ((nbelow8 < 4 || npartials < 7) && cumpow < 0.01f * total_power) + histvec[i].h_value = 0; + else + { + float pitchpow = (cumstrength * cumstrength) * + (cumstrength * cumstrength); + float freqinbins = freqnum/freqden; + /* check for minimum output frequency */ + + if (freqinbins < MINFREQINBINS) + histvec[i].h_value = 0; + else + { + /* we passed all tests... save the values we got */ + histvec[i].h_pitch = ftom(hzperbin * freqnum/freqden); + histvec[i].h_loud = (100.0f -DBFUDGE) + + (LOGTODB) * log(pitchpow/n); + } + } + } +#if 1 + if (x->x_nprint) + { + for (i = 0; i < npitch; i++) + { + if (histvec[i].h_value > 0) + post("index %d pit %f loud %f", histvec[i].h_index, + histvec[i].h_pitch, histvec[i].h_loud); + else post("-- cancelled --"); + } + } +#endif + + /* now try to find continuous pitch tracks that match the new + * pitches. First mark each peak unmatched. + */ + for (i = 0, hp1 = histvec; i < npitch; i++, hp1++) + hp1->h_used = 0; + + /* for each old pitch, try to match a new one to it. */ + for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++) + { + float thispitch = phist->h_pitches[oldphase]; + phist->h_pitch = 0; /* no output, thanks */ + phist->h_wherefrom = 0; + if (thispitch == 0.0f) continue; + for (j = 0, hp1 = histvec; j < npitch; j++, hp1++) + if ((hp1->h_value > 0) && hp1->h_pitch > thispitch - GLISS + && hp1->h_pitch < thispitch + GLISS) + { + phist->h_wherefrom = hp1; + hp1->h_used = 1; + } + } + for (i = 0, hp1 = histvec; i < npitch; i++, hp1++) + if ((hp1->h_value > 0) && !hp1->h_used) + { + for (j = 0, phist = x->x_hist; j < x->x_npitch; j++, phist++) + if (!phist->h_wherefrom) + { + phist->h_wherefrom = hp1; + phist->h_age = 0; + phist->h_noted = 0; + hp1->h_used = 1; + goto happy; + } + break; + happy: ; + } + /* copy the pitch info into the history vector */ + for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++) + { + if (phist->h_wherefrom) + { + phist->h_amps[newphase] = phist->h_wherefrom->h_loud; + phist->h_pitches[newphase] = + phist->h_wherefrom->h_pitch; + (phist->h_age)++; + } + else + { + phist->h_age = 0; + phist->h_amps[newphase] = phist->h_pitches[newphase] = 0; + } + } +#if 1 + if (x->x_nprint) + { + post("vibrato %d %f", x->x_vibbins, x->x_vibdepth); + for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++) + { + post("noted %f, age %d", phist->h_noted, phist->h_age); +#ifndef I860 + post("values %f %f %f %f %f", + phist->h_pitches[newphase], + phist->h_pitches[(newphase + HISTORY-1)%HISTORY], + phist->h_pitches[(newphase + HISTORY-2)%HISTORY], + phist->h_pitches[(newphase + HISTORY-3)%HISTORY], + phist->h_pitches[(newphase + HISTORY-4)%HISTORY]); +#endif + } + } +#endif + /* look for envelope attacks */ + + x->x_attackvalue = 0; + + if (x->x_peaked) + { + if (total_db > x->x_amphi) + { + int binlook = newphase - x->x_attackbins; + if (binlook < 0) binlook += HISTORY; + if (total_db > x->x_dbs[binlook] + x->x_attackthresh) + { + x->x_attackvalue = 1; + x->x_peaked = 0; + } + } + } + else + { + int binlook = newphase - x->x_attackbins; + if (binlook < 0) binlook += HISTORY; + if (x->x_dbs[binlook] > x->x_amphi && x->x_dbs[binlook] > total_db) + x->x_peaked = 1; + } + + /* for each current frequency track, test for a new note using a + * stability criterion. Later perhaps we should also do as in + * pitch~ and check for unstable notes a posteriori when + * there's a new attack with no note found since the last onset; + * but what's an attack &/or onset when we're polyphonic? + */ + + for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++) + { + /* + * if we've found a pitch but we've now strayed from it turn + * it off. + */ + if (phist->h_noted) + { + if (phist->h_pitches[newphase] > phist->h_noted + x->x_vibdepth + || phist->h_pitches[newphase] < phist->h_noted - x->x_vibdepth) + phist->h_noted = 0; + } + else + { + if (phist->h_wherefrom && phist->h_age >= x->x_vibbins) + { + float centroid = 0; + int not = 0; + for (j = 0, k = newphase; j < x->x_vibbins; j++) + { + centroid += phist->h_pitches[k]; + k--; + if (k < 0) k = HISTORY-1; + } + centroid /= x->x_vibbins; + for (j = 0, k = newphase; j < x->x_vibbins; j++) + { + /* calculate deviation from norm */ + float dev = centroid - phist->h_pitches[k]; + k--; + if (k < 0) k = HISTORY-1; + if (dev > x->x_vibdepth || + -dev > x->x_vibdepth) not = 1; + } + if (!not) + { + phist->h_pitch = phist->h_noted = centroid; + } + } + } + } + return; + +nopow: + for (i = 0; i < x->x_npitch; i++) + { + x->x_hist[i].h_pitch = x->x_hist[i].h_noted = + x->x_hist[i].h_pitches[newphase] = + x->x_hist[i].h_amps[newphase] = 0; + x->x_hist[i].h_age = 0; + } + x->x_peaked = 1; + x->x_dbage = 0; +} + +void sigfiddle_debug(t_sigfiddle *x) +{ + x->x_nprint = 1; +} + +void sigfiddle_print(t_sigfiddle *x) +{ + post("npoints %d,", 2 * x->x_hop); + post("amp-range %f %f,", x->x_amplo, x->x_amphi); + post("reattack %d %f,", x->x_attacktime, x->x_attackthresh); + post("vibrato %d %f", x->x_vibtime, x->x_vibdepth); + post("npartial %f", x->x_npartial); + post("auto %d", x->x_auto); +} + +void sigfiddle_amprange(t_sigfiddle *x, t_floatarg amplo, t_floatarg amphi) +{ + if (amplo < 0) amplo = 0; + if (amphi < amplo) amphi = amplo + 1; + x->x_amplo = amplo; + x->x_amphi = amphi; +} + +void sigfiddle_reattack(t_sigfiddle *x, + t_floatarg attacktime, t_floatarg attackthresh) +{ + if (attacktime < 0) attacktime = 0; + if (attackthresh <= 0) attackthresh = 1000; + x->x_attacktime = attacktime; + x->x_attackthresh = attackthresh; + x->x_attackbins = (x->x_sr * 0.001 * attacktime) / x->x_hop; + if (x->x_attackbins >= HISTORY) x->x_attackbins = HISTORY - 1; +} + +void sigfiddle_vibrato(t_sigfiddle *x, t_floatarg vibtime, t_floatarg vibdepth) +{ + if (vibtime < 0) vibtime = 0; + if (vibdepth <= 0) vibdepth = 1000; + x->x_vibtime = vibtime; + x->x_vibdepth = vibdepth; + x->x_vibbins = (x->x_sr * 0.001 * vibtime) / x->x_hop; + if (x->x_vibbins >= HISTORY) x->x_vibbins = HISTORY - 1; + if (x->x_vibbins < 1) x->x_vibbins = 1; +} + +void sigfiddle_npartial(t_sigfiddle *x, t_floatarg npartial) +{ + if (npartial < 0.1) npartial = 0.1; + x->x_npartial = npartial; +} + +void sigfiddle_auto(t_sigfiddle *x, t_floatarg f) +{ + x->x_auto = (f != 0); +} + +static void sigfiddle_freebird(t_sigfiddle *x) +{ + if (x->x_inbuf) + { + freebytes(x->x_inbuf, sizeof(float) * x->x_hop); + x->x_inbuf = 0; + } + if (x->x_lastanalysis) + { + freebytes(x->x_lastanalysis, + sizeof(float) * (2 * x->x_hop + 4 * FILTSIZE)); + x->x_lastanalysis = 0; + } + if (x->x_spiral) + { + freebytes(x->x_spiral, sizeof(float) * 2 * x->x_hop); + x->x_spiral = 0; + } + x->x_hop = 0; +} + +int sigfiddle_setnpoints(t_sigfiddle *x, t_floatarg fnpoints) +{ + int i, npoints = fnpoints; + sigfiddle_freebird(x); + if (npoints < MINPOINTS || npoints > MAXPOINTS) + { + error("fiddle~: npoints out of range; using %d", + npoints = DEFAULTPOINTS); + } + if (npoints != (1 << sigfiddle_ilog2(npoints))) + { + error("fiddle~: npoints not a power of 2; using %d", + npoints = (1 << sigfiddle_ilog2(npoints))); + } + x->x_hop = npoints >> 1; + if (!(x->x_inbuf = (float *)getbytes(sizeof(float) * x->x_hop))) + goto fail; + if (!(x->x_lastanalysis = (float *)getbytes( + sizeof(float) * (2 * x->x_hop + 4 * FILTSIZE)))) + goto fail; + if (!(x->x_spiral = (float *)getbytes(sizeof(float) * 2 * x->x_hop))) + goto fail; + for (i = 0; i < x->x_hop; i++) + x->x_inbuf[i] = 0; + for (i = 0; i < npoints + 4 * FILTSIZE; i++) + x->x_lastanalysis[i] = 0; + for (i = 0; i < x->x_hop; i++) + x->x_spiral[2*i] = cos((3.14159*i)/(npoints)), + x->x_spiral[2*i+1] = -sin((3.14159*i)/(npoints)); + x->x_phase = 0; + return (1); +fail: + sigfiddle_freebird(x); + return (0); +} + +int sigfiddle_doinit(t_sigfiddle *x, long npoints, long npitch, + long npeakanal, long npeakout) +{ + float *buf1, *buf2, *buf3; + t_peakout *buf4; + int i; + + if (!npeakanal && !npeakout) npeakanal = DEFNPEAK, npeakout = 0; + if (!npeakanal < 0) npeakanal = 0; + else if (npeakanal > MAXPEAK) npeakanal = MAXPEAK; + if (!npeakout < 0) npeakout = 0; + else if (npeakout > MAXPEAK) npeakout = MAXPEAK; + if (npitch <= 0) npitch = 0; + else if (npitch > MAXNPITCH) npitch = MAXNPITCH; + if (npeakanal && !npitch) npitch = 1; + if (!npoints) + npoints = DEFAULTPOINTS; + if (!sigfiddle_setnpoints(x, npoints)) + { + error("fiddle~: out of memory"); + return (0); + } + if (!(buf4 = (t_peakout *)getbytes(sizeof(*buf4) * npeakout))) + { + sigfiddle_freebird(x); + error("fiddle~: out of memory"); + return (0); + } + for (i = 0; i < npeakout; i++) + buf4[i].po_freq = buf4[i].po_amp = 0; + x->x_peakbuf = buf4; + + x->x_npeakout = npeakout; + x->x_npeakanal = npeakanal; + x->x_phase = 0; + x->x_histphase = 0; + x->x_sr = 44100; /* this and the next are filled in later */ + for (i = 0; i < MAXNPITCH; i++) + { + int j; + x->x_hist[i].h_pitch = x->x_hist[i].h_noted = 0; + x->x_hist[i].h_age = 0; + x->x_hist[i].h_wherefrom = 0; + x->x_hist[i].h_outlet = 0; + for (j = 0; j < HISTORY; j++) + x->x_hist[i].h_amps[j] = x->x_hist[i].h_pitches[j] = 0; + } + x->x_nprint = 0; + x->x_npitch = npitch; + for (i = 0; i < HISTORY; i++) x->x_dbs[i] = 0; + x->x_dbage = 0; + x->x_peaked = 0; + x->x_auto = 1; + x->x_amplo = DEFAMPLO; + x->x_amphi = DEFAMPHI; + x->x_attacktime = DEFATTACKTIME; + x->x_attackbins = 1; /* real value calculated afterward */ + x->x_attackthresh = DEFATTACKTHRESH; + x->x_vibtime = DEFVIBTIME; + x->x_vibbins = 1; /* real value calculated afterward */ + x->x_vibdepth = DEFVIBDEPTH; + x->x_npartial = 7; + x->x_attackvalue = 0; + return (1); +} + + /* formalities for JMAX */ + +#ifdef JMAX + +void sigfiddle_debug13(fts_object_t *o, int winlet, fts_symbol_t s, int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + sigfiddle_debug(x); +} + +void sigfiddle_print13(fts_object_t *o, int winlet, fts_symbol_t s, + int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + sigfiddle_print(x); +} + +void sigfiddle_amprange13(fts_object_t *o, int winlet, fts_symbol_t s, + int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + float lo = (float) fts_get_float_arg(ac, at, 0, 0); + float hi = (float) fts_get_float_arg(ac, at, 1, 0); + sigfiddle_amprange(x, lo, hi); +} + +void sigfiddle_reattack13(fts_object_t *o, int winlet, fts_symbol_t s, + int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + long msec = fts_get_float_arg(ac, at, 0, 0); + float db = (float) fts_get_float_arg(ac, at, 1, 0); + sigfiddle_reattack(x, msec, db); +} + +void sigfiddle_vibrato13(fts_object_t *o, int winlet, fts_symbol_t s, + int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + long msec = fts_get_float_arg(ac, at, 0, 0); + float halftones = (float) fts_get_float_arg(ac, at, 1, 0); + sigfiddle_vibrato(x, msec, halftones); +} + +void sigfiddle_npartial13(fts_object_t *o, int winlet, fts_symbol_t s, + int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + float npartial = (float) fts_get_float_arg(ac, at, 0, 0); + sigfiddle_npartial(x, npartial); +} + + +void ftl_sigfiddle(fts_word_t *a) +{ + t_sigfiddle *x = (t_sigfiddle *)fts_word_get_long(a); + float *in = (float *)fts_word_get_long(a + 1); + long n_tick = fts_word_get_long(a + 2); + + int count; + float *fp, *fp2; + for (count = 0, fp = x->x_inbuf + x->x_phase; + count < n_tick; count++) *fp++ = *in++; + if (fp == x->x_inbuf + x->x_hop) + { + sigfiddle_doit(x); + x->x_phase = 0; + fts_alarm_set_delay(&x->x_clock, 0L); /* output bang */ + fts_alarm_arm(&x->x_clock); + + if (x->x_nprint) x->x_nprint--; + } + else x->x_phase += n_tick; +} + +void sigfiddle_put(fts_object_t *o, int winlet, fts_symbol_t *s, int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + fts_dsp_descr_t *dsp = (fts_dsp_descr_t *)fts_get_long_arg(ac, at, 0, 0); + fts_atom_t a[3]; + + x->x_sr = fts_dsp_get_input_srate(dsp, 0); + sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh); + sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth); + + fts_set_long(a, (long)x); + fts_set_symbol(a+1, fts_dsp_get_input_name(dsp, 0)); + fts_set_long(a+2, fts_dsp_get_input_size(dsp, 0)); + dsp_add_funcall(dsp_symbol, 3, a); +} + +void sigfiddle_tick(fts_alarm_t *alarm, void *p) +{ + fts_object_t *o = (fts_object_t *)p; + t_sigfiddle *x = (t_sigfiddle *)p; + + int i; + t_pitchhist *ph; + fts_outlet_float(o, OUTLETpower, x->x_dbs[x->x_histphase]); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + { + fts_atom_t at[2]; + fts_set_float(at, ph->h_pitches[x->x_histphase]); + fts_set_float(at+1, ph->h_amps[x->x_histphase]); + fts_outlet_list(o, OUTLETmicropitch3 - i, 2, at); + } + if (x->x_attackvalue) fts_outlet_bang(o, OUTLETattack); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + if (ph->h_pitch) fts_outlet_float(o, OUTLETpitch, ph->h_pitch); +} + +static void sigfiddle_delete(fts_object_t *o, int winlet, fts_symbol_t *s, int ac, + const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + + fts_free(x->x_inbuf); + fts_free(x->x_lastanalysis); + fts_free(x->x_spiral); + dsp_list_remove(o); +} + +static void sigfiddle_init(fts_object_t *o, int winlet, fts_symbol_t *s, int ac, const fts_atom_t *at) +{ + t_sigfiddle *x = (t_sigfiddle *)o; + float *buf1, *buf2, *buf3; + int i, hop; + long npoints = fts_get_long_arg(ac, at, 1, 0); + long npitch = fts_get_long_arg(ac, at, 2, 0); + long npeakanal = fts_get_long_arg(ac, at, 3, 0); + long npeakout = fts_get_long_arg(ac, at, 4, 0); + + if (!sigfiddle_doinit(x, npoints, npitch, npeakanal, npeakout)) + { + post("fiddle~: initialization failed"); + return; + } + hop = npoints>>1; + if (fts_fft_declaresize(hop) != fts_Success) + post("fiddle~: bad FFT size"); + + fts_alarm_init(&(x->x_clock), 0, sigfiddle_tick, x); + dsp_list_insert(o); +} + +static fts_status_t sigfiddle_instantiate(fts_class_t *cl, int ac, + const fts_atom_t *at) +{ + int i; + fts_type_t a[5]; + + fts_class_init(cl, sizeof(t_sigfiddle), 1, 6, 0); /* 1 inlet + 6 outlets */ + + /* the system methods */ + + a[0] = fts_Symbol; + a[1] = fts_Long | fts_OptArg; + a[2] = fts_Long | fts_OptArg; + fts_method_define(cl, fts_SystemInlet, fts_s_init, sigfiddle_init, 3, a); + + fts_method_define(cl, fts_SystemInlet, fts_s_delete, sigfiddle_delete, 0, a); + a[0] = fts_Object; + fts_method_define(cl, fts_SystemInlet, fts_s_put, sigfiddle_put, 1, a); + + /* class' own methods */ + fts_method_define(cl, 0, fts_new_symbol("print"), sigfiddle_print13, 0, a); + fts_method_define(cl, 0, fts_new_symbol("debug"), sigfiddle_debug13, 0, a); + fts_method_define(cl, 0, fts_new_symbol("amp-range"), sigfiddle_amprange13, + 0, a); + fts_method_define(cl, 0, fts_new_symbol("reattack"), sigfiddle_reattack13, + 0, a); + fts_method_define(cl, 0, fts_new_symbol("vibrato"), sigfiddle_vibrato13, + 0, a); + fts_method_define(cl, 0, fts_new_symbol("npartial"), sigfiddle_npartial13, + 0, a); + + /* classes signal inlets */ + dsp_sig_inlet(cl, 0); /* declare signal input #0 */ + + /* classes outlets */ + a[0] = fts_Float; + fts_outlet_type_define(cl, OUTLETpitch, fts_s_float, 1, a); /* declare outlet #0 */ + fts_outlet_type_define(cl, OUTLETattack, fts_s_bang, 0, a); /* declare outlet #1 */ + a[0] = fts_VarArgs; + fts_outlet_type_define(cl, OUTLETmicropitch1, fts_s_list, 1, a); /* declare outlet #2 */ + fts_outlet_type_define(cl, OUTLETmicropitch2, fts_s_list, 1, a); /* declare outlet #3 */ + fts_outlet_type_define(cl, OUTLETmicropitch3, fts_s_list, 1, a); /* declare outlet #4 */ + a[0] = fts_Float; + fts_outlet_type_define(cl, OUTLETpower, fts_s_float, 1, a); /* declare outlet #5 */ + + dsp_symbol = fts_new_symbol("fiddle"); + dsp_declare_function(dsp_symbol, ftl_sigfiddle); + + /* DSP properties */ + + fts_class_put_prop(cl, fts_s_dsp_is_sink, fts_true); + + return(fts_Success); +} + +void fiddle_config(void) +{ + sys_log(fiddle_version); + fts_metaclass_create(fts_new_symbol(CLASSNAME), sigfiddle_instantiate, fts_always_equiv); +} + +fts_module_t fiddle_module = + {"fiddle", "sonic meat fiddle", fiddle_config, 0}; + +#endif /* JMAX */ + +#ifdef PD + +static t_int *fiddle_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_sigfiddle *x = (t_sigfiddle *)(w[2]); + int n = (int)(w[3]); + int count; + float *fp; + if (!x->x_hop) + goto nono; + for (count = 0, fp = x->x_inbuf + x->x_phase; count < n; count++) + *fp++ = *in++; + if (fp == x->x_inbuf + x->x_hop) + { + sigfiddle_doit(x); + x->x_phase = 0; + if (x->x_auto) clock_delay(x->x_clock, 0L); + if (x->x_nprint) x->x_nprint--; + } + else x->x_phase += n; +nono: + return (w+4); +} + +void sigfiddle_dsp(t_sigfiddle *x, t_signal **sp) +{ + x->x_sr = sp[0]->s_sr; + sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh); + sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth); + dsp_add(fiddle_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + + /* This is the callback function for the clock, but also acts as + the "bang" method; you can leave "auto" on to get this called + automatically (the default) or turn auto off and bang it yourself. */ + +void sigfiddle_bang(t_sigfiddle *x) +{ + int i; + t_pitchhist *ph; + if (x->x_npeakout) + { + int npeakout = x->x_npeakout; + t_peakout *po; + for (i = 0, po = x->x_peakbuf; i < npeakout; i++, po++) + { + t_atom at[3]; + SETFLOAT(at, i+1); + SETFLOAT(at+1, po->po_freq); + SETFLOAT(at+2, po->po_amp); + outlet_list(x->x_peakout, 0, 3, at); + } + } + outlet_float(x->x_envout, x->x_dbs[x->x_histphase]); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + { + t_atom at[2]; + SETFLOAT(at, ph->h_pitches[x->x_histphase]); + SETFLOAT(at+1, ph->h_amps[x->x_histphase]); + outlet_list(ph->h_outlet, 0, 2, at); + } + if (x->x_attackvalue) outlet_bang(x->x_attackout); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch); +} + +void sigfiddle_ff(t_sigfiddle *x) /* cleanup on free */ +{ + if (x->x_inbuf) + { + freebytes(x->x_inbuf, sizeof(float) * x->x_hop); + freebytes(x->x_lastanalysis, sizeof(float) * (2*x->x_hop + 4 * FILTSIZE)); + freebytes(x->x_spiral, sizeof(float) * 2*x->x_hop); + freebytes(x->x_peakbuf, sizeof(*x->x_peakbuf) * x->x_npeakout); + clock_free(x->x_clock); + } +} + +static t_class *sigfiddle_class; + +void *sigfiddle_new(t_floatarg npoints, t_floatarg npitch, + t_floatarg fnpeakanal, t_floatarg fnpeakout) +{ + t_sigfiddle *x = (t_sigfiddle *)pd_new(sigfiddle_class); + int i; + int npeakanal = fnpeakanal, npeakout = fnpeakout; + + + if (!sigfiddle_doinit(x, npoints, npitch, + npeakanal, npeakout)) + { + x->x_inbuf = 0; /* prevent the free routine from cleaning up */ + pd_free(&x->x_ob.ob_pd); + return (0); + } + x->x_noteout = outlet_new(&x->x_ob, gensym("float")); + x->x_attackout = outlet_new(&x->x_ob, gensym("bang")); + for (i = 0; i < x->x_npitch; i++) + x->x_hist[i].h_outlet = outlet_new(&x->x_ob, gensym("list")); + x->x_envout = outlet_new(&x->x_ob, gensym("float")); + if (x->x_npeakout) + x->x_peakout = outlet_new(&x->x_ob, gensym("list")); + else x->x_peakout = 0; + x->x_clock = clock_new(&x->x_ob.ob_pd, (t_method)sigfiddle_bang); + return (x); +} + +void fiddle_tilde_setup(void) +{ + sigfiddle_class = class_new(gensym("fiddle~"), (t_newmethod)sigfiddle_new, + (t_method)sigfiddle_ff, sizeof(t_sigfiddle), 0, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_dsp, + gensym("dsp"), 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_debug, + gensym("debug"), 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_setnpoints, + gensym("npoints"), A_FLOAT, 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_amprange, + gensym("amp-range"), A_FLOAT, A_FLOAT, 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_reattack, + gensym("reattack"), A_FLOAT, A_FLOAT, 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_vibrato, + gensym("vibrato"), A_FLOAT, A_FLOAT, 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_npartial, + gensym("npartial"), A_FLOAT, 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_auto, + gensym("auto"), A_FLOAT, 0); + class_addmethod(sigfiddle_class, (t_method)sigfiddle_print, + gensym("print"), 0); + class_addmethod(sigfiddle_class, nullfn, gensym("signal"), 0); + class_addbang(sigfiddle_class, sigfiddle_bang); + class_addcreator((t_newmethod)sigfiddle_new, gensym("fiddle"), + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + post(fiddle_version); +} + +void fiddle_setup(void) +{ + fiddle_tilde_setup(); +} +#endif /* PD */ + +#ifdef MAX26 + +void cu_fiddle(float *in1, t_sigfiddle *x, int n) +{ + int count; + float *fp, *fp2; + for (count = 0, fp = x->x_inbuf + x->x_phase; + count < n; count++) *fp++ = *in1++; + if (fp == x->x_inbuf + x->x_hop) + { + sigfiddle_doit(x); + x->x_phase = 0; + if (x->x_auto) clock_delay(x->x_clock, 0L); + if (x->x_nprint) x->x_nprint--; + } + else x->x_phase += n; +} + +void sigfiddle_put(t_sigfiddle *x, long whether) +{ + if (whether) + { + u_stdout(x); + x->x_sr = x->x_io[0]->s_sr; + sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh); + sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth); + dspchain_addc(cu_fiddle, 3, + x->x_io[0]->s_shit, x, x->x_io[0]->s_n); + } +} + +void sigfiddle_tick(t_sigfiddle *x) /* callback function for the clock */ +{ + int i; + t_pitchhist *ph; + outlet_float(x->x_envout, x->x_dbs[x->x_histphase]); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + { + t_atom at[2]; + SETFLOAT(at, ph->h_pitches[x->x_histphase]); + SETFLOAT(at+1, ph->h_amps[x->x_histphase]); + outlet_list(ph->h_outlet, NIL, 2, at); + } + if (x->x_attackvalue) outlet_bang(x->x_attackout); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch); +} + +void sigfiddle_ff(t_sigfiddle *x) /* cleanup on free */ +{ + if (x->x_inbuf) + { + freebytes(x->x_inbuf, sizeof(float) * x->x_hop); + freebytes(x->x_lastanalysis, sizeof(float) * (2*x->x_hop + 4 * FILTSIZE)); + freebytes(x->x_spiral, sizeof(float) * 2*x->x_hop); + clock_free(x->x_clock); + u_clean(x); + } +} + +t_externclass *sigfiddle_class; + +void *sigfiddle_new(long npoints, long npitch, + long npeakanal, long npeakout) +{ + t_sigfiddle *x = (t_sigfiddle *)obj_new(&sigfiddle_class, 0); + int i; + + if (!sigfiddle_doinit(x, npoints, npitch, npeakanal, npeakout)) + { + x->x_inbuf = 0; /* prevent the free routine from cleaning up */ + obj_free(x); + return (0); + } + u_setup(x, IN1, OUT0); + x->x_envout = outlet_new(x, gensym("float")); + for (i = 0; i < x->x_npitch; i++) + x->x_hist[i].h_outlet = outlet_new(x, gensym("list")); + x->x_attackout = outlet_new(x, gensym("bang")); + x->x_noteout = outlet_new(x, gensym("float")); + x->x_clock = clock_new(x, sigfiddle_tick); + return (x); +} + +void fiddle_setup() +{ + c_extern(&sigfiddle_class, sigfiddle_new, sigfiddle_ff, + gensym("fiddle"), sizeof(t_sigfiddle), 0, A_DEFLONG, A_DEFLONG, + A_DEFLONG, A_DEFLONG, 0); + c_addmess(sigfiddle_put, gensym("put"), A_CANT, 0); + c_addmess(sigfiddle_debug, gensym("debug"), 0); + c_addmess(sigfiddle_amprange, gensym("amp-range"), A_FLOAT, A_FLOAT, 0); + c_addmess(sigfiddle_reattack, gensym("reattack"), A_FLOAT, A_FLOAT, 0); + c_addmess(sigfiddle_vibrato, gensym("vibrato"), A_LONG, A_FLOAT, 0); + c_addmess(sigfiddle_npartial, gensym("npartial"), A_FLOAT, 0); + c_addmess(sigfiddle_print, gensym("print"), 0); + u_inletmethod(0); /* one signal input */ +#ifdef MAX + post(fiddle_version); +#endif +} + +#endif /* MAX26 */ + +/************* Beginning of MSP Code ******************************/ + +#ifdef MSP + +static t_int *fiddle_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_sigfiddle *x = (t_sigfiddle *)(w[2]); + int n = (int)(w[3]); + int count,inc = x->x_downsample; + float *fp; + + if (x->x_obj.z_disabled) + goto skip; + for (count = 0, fp = x->x_inbuf + x->x_phase; count < n; count+=inc) { + *fp++ = *in; + in += inc; + } + if (fp == x->x_inbuf + x->x_hop) + { + sigfiddle_doit(x); + x->x_phase = 0; + if (x->x_auto) clock_delay(x->x_clock, 0L); + if (x->x_nprint) x->x_nprint--; + } + else x->x_phase += n; +skip: + return (w+4); +} + +void sigfiddle_dsp(t_sigfiddle *x, t_signal **sp) +{ + if (sp[0]->s_n > x->x_hop) { + x->x_downsample = sp[0]->s_n / x->x_hop; + post("* warning: fiddle~: will downsample input by %ld",x->x_downsample); + x->x_sr = sp[0]->s_sr / x->x_downsample; + } else { + x->x_downsample = 1; + x->x_sr = sp[0]->s_sr; + } + sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh); + sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth); + dsp_add(fiddle_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + +void sigfiddle_tick(t_sigfiddle *x) /* callback function for the clock MSP*/ +{ + int i; + t_pitchhist *ph; + if (x->x_npeakout) + { + int npeakout = x->x_npeakout; + t_peakout *po; + for (i = 0, po = x->x_peakbuf; i < npeakout; i++, po++) + { + t_atom at[3]; + SETINT(at, i+1); + SETFLOAT(at+1, po->po_freq); + SETFLOAT(at+2, po->po_amp); + outlet_list(x->x_peakout, 0, 3, at); + } + } + outlet_float(x->x_envout, x->x_dbs[x->x_histphase]); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + { + t_atom at[2]; + SETFLOAT(at, ph->h_pitches[x->x_histphase]); + SETFLOAT(at+1, ph->h_amps[x->x_histphase]); + outlet_list(ph->h_outlet, 0, 2, at); + } + if (x->x_attackvalue) outlet_bang(x->x_attackout); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch); +} + +void sigfiddle_bang(t_sigfiddle *x) +{ + int i; + t_pitchhist *ph; + if (x->x_npeakout) + { + int npeakout = x->x_npeakout; + t_peakout *po; + for (i = 0, po = x->x_peakbuf; i < npeakout; i++, po++) + { + t_atom at[3]; + SETLONG(at, i+1); + SETFLOAT(at+1, po->po_freq); + SETFLOAT(at+2, po->po_amp); + outlet_list(x->x_peakout, 0, 3, at); + } + } + outlet_float(x->x_envout, x->x_dbs[x->x_histphase]); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + { + t_atom at[2]; + SETFLOAT(at, ph->h_pitches[x->x_histphase]); + SETFLOAT(at+1, ph->h_amps[x->x_histphase]); + outlet_list(ph->h_outlet, 0, 2, at); + } + if (x->x_attackvalue) outlet_bang(x->x_attackout); + for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++) + if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch); +} + + +void sigfiddle_ff(t_sigfiddle *x) /* cleanup on free MSP */ +{ + + if (x->x_inbuf) + { + t_freebytes(x->x_inbuf, sizeof(float) * x->x_hop); + t_freebytes(x->x_lastanalysis, sizeof(float) * (2*x->x_hop + 4 * +FILTSIZE)); + t_freebytes(x->x_spiral, sizeof(float) * 2*x->x_hop); + t_freebytes(x->x_peakbuf, sizeof(*x->x_peakbuf) * x->x_npeakout); + } + dsp_free((t_pxobject *)x); +} + +void *sigfiddle_class; + +void *sigfiddle_new(long npoints, long npitch, + long npeakanal, long npeakout) +{ + t_sigfiddle *x = (t_sigfiddle *)newobject(sigfiddle_class); + int i; + + if (!sigfiddle_doinit(x, npoints, npitch, npeakanal, npeakout)) + { + x->x_inbuf = 0; /* prevent the free routine from cleaning up */ + return (0); + } + dsp_setup((t_pxobject *)x,1); + + x->x_clock = clock_new(x, (method)sigfiddle_tick); + if (x->x_npeakout) + x->x_peakout = listout((t_object *)x); + else x->x_peakout = 0; + x->x_envout = floatout((t_object *)x); + for (i = 0; i < x->x_npitch; i++) + x->x_hist[i].h_outlet = listout((t_object *)x); + x->x_attackout = bangout((t_object *)x); + x->x_noteout = floatout((t_object *)x); + return (x); + + +} + +void main() +{ + setup(&sigfiddle_class, sigfiddle_new, (method)sigfiddle_ff, + (short)sizeof(t_sigfiddle), 0L, A_DEFLONG, A_DEFLONG, +A_DEFLONG, A_DEFLONG, 0); + addmess((method)sigfiddle_dsp, "dsp", + A_CANT, 0); + addmess((method)sigfiddle_debug, "debug", 0); + addmess((method)sigfiddle_setnpoints, "npoints", A_FLOAT, 0); + addmess((method)sigfiddle_amprange, "amp-range", A_FLOAT, A_FLOAT, 0); + addmess((method)sigfiddle_reattack, "reattack", A_FLOAT, A_FLOAT, 0); + addmess((method)sigfiddle_vibrato, "vibrato", A_FLOAT, +A_FLOAT, 0); + addmess((method)sigfiddle_npartial, "npartial", A_FLOAT, 0); + addmess((method)sigfiddle_auto, "auto", + A_FLOAT, 0); + addmess((method)sigfiddle_print, "print", 0); + addmess((method)sigfiddle_assist, "assist", + A_CANT, 0); + addbang((method)sigfiddle_bang); + dsp_initclass(); + rescopy('STR#',3748); + post(fiddle_version); +} + +void sigfiddle_assist(t_sigfiddle *x, void *b, long m, long a, char *s) +{ + assist_string(3748,m,a,1,2,s); +} + +void msp_fft(float *buf, long np, long inv) +{ + float *src,*real,*rp,*imag,*ip; + long i; + + /* + // because this fft algorithm uses separate real and imaginary + // buffers + // we must split the real and imaginary parts into two buffers, + // then do the opposite on output + // a more ambitious person would either do an in-place conversion + // or rewrite the fft algorithm + */ + + real = rp = msp_ffttemp; + imag = ip = real + MAXPOINTS; + src = buf; + for (i = 0; i < np; i++) { + *rp++ = *src++; + *ip++ = *src++; + } + if (inv) + ifft(np,real,imag); + else + fft(np,real,imag); + rp = real; + ip = imag; + src = buf; + for (i = 0; i < np; i++) { + *src++ = *rp++; + *src++ = *ip++; + } +} + +#endif /* MSP */ diff --git a/extra/fiddle~/makefile b/extra/fiddle~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..247c905e63949ca49cce3985834625af1e2e7aad --- /dev/null +++ b/extra/fiddle~/makefile @@ -0,0 +1,4 @@ +NAME=fiddle~ +CSYM=fiddle_tilde + +include ../makefile diff --git a/extra/loop~/loop~-help.pd b/extra/loop~/loop~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..a445b805eb55fa768f99352caf438b150650d248 --- /dev/null +++ b/extra/loop~/loop~-help.pd @@ -0,0 +1,74 @@ +#N canvas 33 0 647 662 12; +#X floatatom 41 204 0 0 0 0 - - -; +#X obj 254 382 print~; +#X msg 254 347 bang; +#X obj 41 338 loop~; +#X floatatom 66 279 0 0 0 0 - - -; +#X msg 55 252 bang; +#X obj 183 382 print~; +#X msg 183 347 bang; +#N canvas 0 0 450 300 graph1 0; +#X array array2 150000 float 0; +#X coords 0 1 150000 -1 200 150 1; +#X restore 393 464 graph; +#X msg 393 622 \; array2 resize 150000; +#X obj 25 613 soundfiler; +#X obj 16 453 tabread4~ array2; +#X obj 16 407 *~; +#X obj 16 522 dac~; +#X obj 16 499 hip~ 5; +#X obj 62 411 samphold~; +#X obj 16 430 +~; +#X floatatom 96 303 0 0 0 0 - - -; +#X obj 96 326 *~ 1000; +#X msg 43 568 read ../doc/sound/bell.aiff array2; +#X msg 43 591 read ../doc/sound/vocal.aiff array2; +#X msg 47 229 set 0.5; +#X text 95 196 left signal input is transposition (1 is normal \, 2 +is up an octave \, etc); +#X text 82 4 loop~ - phase generator for looping samplers; +#X text 116 228 set phase (0 to 1); +#X text 104 253 reset phase to 0; +#X text 104 278 right signal input is window size in samples; +#X text 134 302 here's how to handle onsets; +#X obj 16 476 *~; +#X floatatom 167 432 0 0 0 0 - - -; +#X obj 167 501 line~; +#X obj 167 455 dbtorms; +#X obj 167 478 pack 0 50; +#X text 201 431 output level 0-100; +#X text 187 326 print outputs; +#X text 33 32 loop~ takes input signals to set a window size and transposition +\, and outputs a phase and a sampled window size. The window size only +changes at phase zero crossings and the phase output is adjusted so +that changing window size doesn't change the transposition.; +#X text 33 112 You can send "bang" or "set" message to force the phase +to zero--you should mute the output before doing so. This may be desirable +if you've set a large window size but then want to decrease it without +waiting for the next phase crossing.; +#X connect 0 0 3 0; +#X connect 2 0 1 0; +#X connect 3 0 6 0; +#X connect 3 0 12 0; +#X connect 3 0 15 1; +#X connect 3 1 1 0; +#X connect 3 1 12 1; +#X connect 4 0 3 1; +#X connect 5 0 3 0; +#X connect 7 0 6 0; +#X connect 11 0 28 0; +#X connect 12 0 16 0; +#X connect 14 0 13 0; +#X connect 14 0 13 1; +#X connect 15 0 16 1; +#X connect 16 0 11 0; +#X connect 17 0 18 0; +#X connect 18 0 15 0; +#X connect 19 0 10 0; +#X connect 20 0 10 0; +#X connect 21 0 3 0; +#X connect 28 0 14 0; +#X connect 29 0 31 0; +#X connect 30 0 28 1; +#X connect 31 0 32 0; +#X connect 32 0 30 0; diff --git a/extra/loop~/loop~.c b/extra/loop~/loop~.c new file mode 100644 index 0000000000000000000000000000000000000000..2f440030750209ae2e9f0df0b852da79258e0a5b --- /dev/null +++ b/extra/loop~/loop~.c @@ -0,0 +1,164 @@ +/* loop~ -- loop generator for sampling */ + +/* Copyright 1997-1999 Miller Puckette. +Permission is granted to use this software for any purpose provided you +keep this copyright notice intact. + +THE AUTHOR AND HIS EMPLOYERS MAKE NO WARRANTY, EXPRESS OR IMPLIED, +IN CONNECTION WITH THIS SOFTWARE. + +This file is downloadable from http://www.crca.ucsd.edu/~msp . + +*/ + +#ifdef PD +#include "m_pd.h" +#endif + +typedef struct _loopctl +{ + double l_phase; + float l_invwindow; + float l_window; + int l_resync; +} t_loopctl; + +static void loopctl_run(t_loopctl *x, float *transposein, + float *windowin, float *rawout, float *windowout, int n) +{ + float window, invwindow; + double phase = x->l_phase; + if (x->l_resync) + { + window = *windowin; + if (window < 0) + { + if (window > -1) + window = -1; + invwindow = -1/window; + } + else + { + if (window < 1) + window = 1; + invwindow = 1/window; + } + x->l_resync = 0; + } + else + { + window = x->l_window; + phase = x->l_phase; + invwindow = x->l_invwindow; + } + while (n--) + { + double phaseinc = invwindow * *transposein++; + double newphase; + float nwind = *windowin++; + if (phaseinc >= 1 || phaseinc < 0) + phaseinc = 0; + newphase = phase + phaseinc; + if (newphase >= 1) + { + window = nwind; + if (window < 0) + { + if (window > -1) + window = -1; + invwindow = -1/window; + } + else + { + if (window < 1) + window = 1; + invwindow = 1/window; + } + newphase -= 1.; + } + phase = newphase; + *rawout++ = (float)phase; + *windowout++ = window; + } + x->l_invwindow = invwindow; + x->l_window = window; + x->l_phase = phase; +} + +static void loopctl_init(t_loopctl *x) +{ + x->l_window = 1; + x->l_invwindow = 1; + x->l_phase = 0; +} + +static void loopctl_set(t_loopctl *x, float val) +{ + if (val < 0 || val > 1) + val = 0; + x->l_phase = val; + x->l_resync = 1; +} + +#ifdef PD + +typedef struct _loop +{ + t_object x_obj; + t_float x_f; + t_loopctl x_loopctl; +} t_loop; + +static t_class *loop_class; + +static void *loop_new(void) +{ + t_loop *x = (t_loop *)pd_new(loop_class); + loopctl_init(&x->x_loopctl); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, gensym("signal")); + outlet_new(&x->x_obj, gensym("signal")); + return (x); +} + +static t_int *loop_perform(t_int *w) +{ + t_loopctl *ctl = (t_loopctl *)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out1 = (t_float *)(w[4]); + t_float *out2 = (t_float *)(w[5]); + int n = (int)(w[6]); + loopctl_run(ctl, in1, in2, out1, out2, n); + return (w+7); +} + +static void loop_dsp(t_loop *x, t_signal **sp) +{ + dsp_add(loop_perform, 6, + &x->x_loopctl, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, + sp[0]->s_n); +} + +static void loop_set(t_loop *x, t_floatarg val) +{ + loopctl_set(&x->x_loopctl, val); +} + +static void loop_bang(t_loop *x) +{ + loopctl_set(&x->x_loopctl, 0); +} + +void loop_tilde_setup(void) +{ + loop_class = class_new(gensym("loop~"), (t_newmethod)loop_new, 0, + sizeof(t_loop), 0, 0); + class_addmethod(loop_class, (t_method)loop_dsp, gensym("dsp"), A_CANT, 0); + CLASS_MAINSIGNALIN(loop_class, t_loop, x_f); + class_addmethod(loop_class, (t_method)loop_set, gensym("set"), + A_DEFFLOAT, 0); + class_addbang(loop_class, loop_bang); +} + +#endif /* PD */ diff --git a/extra/loop~/makefile b/extra/loop~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..fd21f2b4cfb50667614d0c44b672bb200b57a0d3 --- /dev/null +++ b/extra/loop~/makefile @@ -0,0 +1,4 @@ +NAME=loop~ +CSYM=loop_tilde + +include ../makefile diff --git a/extra/loop~/test-loop~.pd b/extra/loop~/test-loop~.pd new file mode 100644 index 0000000000000000000000000000000000000000..9966483dfc683c1e504c9f1e9fec01aee09dc50e --- /dev/null +++ b/extra/loop~/test-loop~.pd @@ -0,0 +1,58 @@ +#N canvas 33 0 680 609 12; +#X floatatom 52 262 0 0 0 0 - - -; +#X obj 261 346 print~; +#X msg 47 373 bang; +#X msg 274 313 bang; +#X obj 52 306 loop~; +#X floatatom 102 245 0 0 0 0 - - -; +#N canvas 0 0 450 300 graph1 0; +#X array array1 44100 float 0; +#X coords 0 10 44100 0 200 150 1; +#X restore 65 17 graph; +#X msg 43 204 \; array1 resize 44100; +#X obj 25 401 tabwrite~ array1; +#X msg 208 371 bang; +#X obj 176 402 tabwrite~ array1; +#X msg 194 261 bang; +#X obj 204 347 print~; +#X msg 217 314 bang; +#N canvas 0 0 450 300 graph1 0; +#X array array2 150000 float 0; +#X coords 0 1 150000 -1 200 150 1; +#X restore 332 398 graph; +#X msg 326 274 \; array2 resize 150000; +#X obj 103 529 tabread4~ array2; +#X obj 64 481 *~; +#X obj 107 581 dac~; +#X obj 105 552 hip~ 5; +#X obj 123 482 samphold~; +#X obj 102 506 +~; +#X floatatom 106 430 0 0 0 0 - - -; +#X obj 108 453 *~ 1000; +#X obj 312 215 soundfiler; +#X msg 330 170 read ../doc/sound/bell.aiff array2; +#X msg 330 193 read ../doc/sound/vocal.aiff array2; +#X connect 0 0 4 0; +#X connect 2 0 8 0; +#X connect 3 0 1 0; +#X connect 4 0 12 0; +#X connect 4 0 17 0; +#X connect 4 0 8 0; +#X connect 4 0 20 1; +#X connect 4 1 10 0; +#X connect 4 1 1 0; +#X connect 4 1 17 1; +#X connect 5 0 4 1; +#X connect 9 0 10 0; +#X connect 11 0 4 0; +#X connect 13 0 12 0; +#X connect 16 0 19 0; +#X connect 17 0 21 0; +#X connect 19 0 18 0; +#X connect 19 0 18 1; +#X connect 20 0 21 1; +#X connect 21 0 16 0; +#X connect 22 0 23 0; +#X connect 23 0 20 0; +#X connect 25 0 24 0; +#X connect 26 0 24 0; diff --git a/extra/lrshift~/lrshift~-help.pd b/extra/lrshift~/lrshift~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..fdf7b0c53f0d22f20bb55d26e089c70b71c3b9de --- /dev/null +++ b/extra/lrshift~/lrshift~-help.pd @@ -0,0 +1,33 @@ +#N canvas 143 0 673 325 12; +#X msg 268 277 bang; +#X obj 244 303 print~; +#X msg 185 278 bang; +#X obj 161 304 print~; +#X text 53 117 click here first; +#X msg 72 270 bang; +#X obj 48 296 print~; +#X text 162 222 shift left; +#X text 243 224 shift right; +#X obj 161 252 lrshift~ 1; +#X obj 244 251 lrshift~ -1; +#X text 39 37 Acting at whatever vector size the window is running +at \, lrshift~ shifts samples to the left (toward the beginning sample) +or to the right. The argument gives the direction and the amount of +the shift. The rightmost (or leftmost) samples are set to zero.; +#N canvas 0 0 450 300 (subpatch) 0; +#X array shiftin 64 float 0; +#X coords 0 1 63 0 200 140 1; +#X restore 448 118 graph; +#X text 115 11 -- shift signal vector elements left or right; +#X msg 54 138 \; pd dsp 1 \; shiftin 1 1; +#X obj 48 204 tabreceive~ shiftin; +#X text 525 308 Updated for Pd 0.31.; +#X obj 47 11 lrshift~; +#X connect 0 0 1 0; +#X connect 2 0 3 0; +#X connect 5 0 6 0; +#X connect 9 0 3 0; +#X connect 10 0 1 0; +#X connect 15 0 6 0; +#X connect 15 0 9 0; +#X connect 15 0 10 0; diff --git a/extra/lrshift~/lrshift~.c b/extra/lrshift~/lrshift~.c new file mode 100644 index 0000000000000000000000000000000000000000..166facc161ae686d8a12498054ff9b5dc3c8daf6 --- /dev/null +++ b/extra/lrshift~/lrshift~.c @@ -0,0 +1,76 @@ +#include "m_pd.h" + +/* ------------------------ lrshift~ ----------------------------- */ + +static t_class *lrshift_tilde_class; + +typedef struct _lrshift_tilde +{ + t_object x_obj; + int x_n; + float x_f; +} t_lrshift_tilde; + +static t_int *leftshift_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out= (t_float *)(w[2]); + int n = (int)(w[3]); + int shift = (int)(w[4]); + in += shift; + n -= shift; + while (n--) + *out++ = *in++; + while (shift--) + *out++ = 0; + return (w+5); +} + +static t_int *rightshift_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out= (t_float *)(w[2]); + int n = (int)(w[3]); + int shift = (int)(w[4]); + n -= shift; + in -= shift; + while (n--) + *--out = *--in; + while (shift--) + *--out = 0; + return (w+5); +} + +static void lrshift_tilde_dsp(t_lrshift_tilde *x, t_signal **sp) +{ + int n = sp[0]->s_n; + int shift = x->x_n; + if (shift > n) + shift = n; + if (shift < -n) + shift = -n; + if (shift < 0) + dsp_add(rightshift_perform, 4, + sp[0]->s_vec + n, sp[1]->s_vec + n, n, -shift); + else dsp_add(leftshift_perform, 4, + sp[0]->s_vec, sp[1]->s_vec, n, shift); +} + +static void *lrshift_tilde_new(t_floatarg f) +{ + t_lrshift_tilde *x = (t_lrshift_tilde *)pd_new(lrshift_tilde_class); + x->x_n = f; + x->x_f = 0; + outlet_new(&x->x_obj, gensym("signal")); + return (x); +} + +void lrshift_tilde_setup(void) +{ + lrshift_tilde_class = class_new(gensym("lrshift~"), + (t_newmethod)lrshift_tilde_new, 0, sizeof(t_lrshift_tilde), 0, + A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(lrshift_tilde_class, t_lrshift_tilde, x_f); + class_addmethod(lrshift_tilde_class, (t_method)lrshift_tilde_dsp, + gensym("dsp"), 0); +} diff --git a/extra/lrshift~/makefile b/extra/lrshift~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..d6a24cfe3ccdffb1dd822d1ea65cacccaf54bafb --- /dev/null +++ b/extra/lrshift~/makefile @@ -0,0 +1,4 @@ +NAME=lrshift~ +CSYM=lrshift_tilde + +include ../makefile diff --git a/extra/pd~/makefile b/extra/pd~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..d069c73dc5ae6db2521c25df751ff5c21b04cec8 --- /dev/null +++ b/extra/pd~/makefile @@ -0,0 +1,15 @@ +NAME=pd~ +CSYM=pd_tilde + +include ../makefile + +pd_linux: pdsched.pd_linux + +d_fat: pdsched.d_fat +d_ppc: pdsched.d_ppc + +pdsched.pd_linux: pdsched.c + $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c + $(CC) -shared -o $*.pd_linux $*.o -lc -lm + strip --strip-unneeded $*.pd_linux + rm -f $*.o diff --git a/extra/pd~/notes.txt b/extra/pd~/notes.txt new file mode 100644 index 0000000000000000000000000000000000000000..59129d5abb0f5830b7e9b575a9a880817d7e7f15 --- /dev/null +++ b/extra/pd~/notes.txt @@ -0,0 +1,8 @@ +pd -schedlib `pwd`/pdsched + +dolist: +pd~ to delay starting subproc until asked +figure out about setting nchannels from command line +fix maximum nchannels in and out + + diff --git a/extra/pd~/pdsched.c b/extra/pd~/pdsched.c new file mode 100644 index 0000000000000000000000000000000000000000..7efe49a959607e17c86387de6ae8a2abe258fef5 --- /dev/null +++ b/extra/pd~/pdsched.c @@ -0,0 +1,85 @@ +/* Copyright 2008 Miller Puckette. Berkeley license; see the +file LICENSE.txt in this distribution. */ + +/* A plug-in scheduler that turns Pd into a filter that inputs and +outputs audio and messages. */ + +/* todo: + fix schedlib code to use extent2 + figure out about if (sys_externalschedlib) { return; } in s_audio.c + make buffer size ynamically growable + +*/ +#include "m_pd.h" +#include "s_stuff.h" +#include <stdio.h> + +#define BUFSIZE 65536 +static char inbuf[BUFSIZE]; + +int pd_extern_sched(char *flags) +{ + int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; + int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; + int i, j, rate, advance, callback, chin, chout, fill = 0, c; + t_binbuf *b = binbuf_new(); + + sys_get_audio_params(&naudioindev, audioindev, chindev, + &naudiooutdev, audiooutdev, choutdev, &rate, &advance, &callback); + + chin = (naudioindev < 1 ? 0 : chindev[0]); + chout = (naudiooutdev < 1 ? 0 : choutdev[0]); + + fprintf(stderr, "Pd plug-in scheduler called, chans %d %d, sr %d\n", + chin, chout, (int)rate); + sys_setchsr(chin, chout, rate); + sys_audioapi = API_NONE; + while ((c = getchar()) != EOF) + { + if (c == ';') + { + int n; + t_atom *ap; + binbuf_text(b, inbuf, fill); + n = binbuf_getnatom(b); + ap = binbuf_getvec(b); + fill = 0; + if (n > 0 && ap[0].a_type == A_FLOAT) + { + /* a list -- take it as incoming signals. */ + int chan, nchan = n/DEFDACBLKSIZE; + t_sample *fp; + for (i = chan = 0, fp = sys_soundin; chan < nchan; chan++) + for (j = 0; j < DEFDACBLKSIZE; j++) + *fp++ = atom_getfloat(ap++); + for (; chan < chin; chan++) + for (j = 0; j < DEFDACBLKSIZE; j++) + *fp++ = 0; + sched_tick(sys_time+sys_time_per_dsp_tick); + sys_pollgui(); + printf(";\n"); + for (i = chout*DEFDACBLKSIZE, fp = sys_soundout; i--; fp++) + { + printf("%g\n", *fp); + *fp = 0; + } + printf(";\n"); + fflush(stdout); + } + else if (n > 1 && ap[0].a_type == A_SYMBOL) + { + t_pd *whom = ap[0].a_w.w_symbol->s_thing; + if (!whom) + error("%s: no such object", ap[0].a_w.w_symbol->s_name); + else if (ap[1].a_type == A_SYMBOL) + typedmess(whom, ap[1].a_w.w_symbol, n-2, ap+2); + else pd_list(whom, 0, n-1, ap+1); + } + } + else if (fill < BUFSIZE) + inbuf[fill++] = c; + else if (fill == BUFSIZE) + fprintf(stderr, "pd-extern: input buffer overflow\n"); + } + return (0); +} diff --git a/extra/pd~/pd~-help.pd b/extra/pd~/pd~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..8bc357e0c7b62b9809a578b0cd0751825bc89efb --- /dev/null +++ b/extra/pd~/pd~-help.pd @@ -0,0 +1,75 @@ +#N canvas 12 0 566 872 12; +#X msg 31 406 foo bar baz; +#X obj 189 466 osc~ 440; +#X obj 127 645 env~ 8192; +#X floatatom 127 694 5 0 0 0 - - -; +#X msg 434 807 \; pd dsp 1; +#X msg 24 332 pd~ stop; +#X obj 127 670 i; +#X obj 241 643 env~ 8192; +#X floatatom 241 693 5 0 0 0 - - -; +#X obj 241 669 i; +#X obj 123 489 *~; +#X obj 158 490 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 189 490 *~; +#X obj 224 491 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 434 781 loadbang; +#X obj 14 691 print x; +#X msg 15 309 pd~ start pd~-subprocess.pd; +#X obj 14 532 pd~ -ninsig 2 -noutsig 2 -fifo 20; +#X obj 37 20 pd~; +#X text 69 22 - run a pd sub-process; +#X text 27 57 The pd~ object starts and manages a Pd sub-process that +can communicate with the super-process (this one) via audio channels +and/or Pd messages. In this way you can take advantage of multi-core +CPUs \, and/or use Pd features from within Max (if you're using the +Max version of pd~).; +#X text 24 251 Sending a new "start" message will stop the sub-process +and start a new one. If you just want to stop the sub-process \, send +"stop".; +#X text 33 353 Any message besides "pd~" is sent to the sub-process. +For instance \, the message below sends "bar baz" to any object in +the sub-process named "foo" \, such as a "receive" object.; +#X text 43 430 Audio signals appear in adc~ objects in the sub-process. +The sub-process doesn't open real audio devices.; +#X text 281 473 Creation args:; +#X text 265 490 -insig <n> sets input audio channels; +#X text 266 508 -outsig <n> sets output channels; +#X text 269 542 -fifo <n> sets round-trip delay in blocks; +#X text 272 559 -pddir <s> sets Pd directory \, e.g. \,; +#X text 299 574 .../Pd-0.42.app/Contents/Resources; +#X text 272 590 -scheddir <s> sets scheduler dir \, e.g. \,; +#X text 297 607 .../.../Resources/extra/pd~; +#X text 267 524 -sr <n> sets sample rate; +#X text 20 716 The first outlet reports messages the sub-process sends +us via "stdout" objects. Any other outlets are signals corresponding +to "dac~" objects in the sub-process.; +#X text 10 784 ATTENTION: DSP must be running in this process for the +sub-process to run. This is because its clock is slaved to audio I/O +it gets from us!; +#X text 359 849 Updated for Pd version 0.42.; +#X text 24 138 Messages with "pd~" selector control the sub-process. +"pd~ start" takes as arguments any startup arguments you wish to send +the sub-process. For example \, specify "-nogui" to stop the sub-process's +GUI from appearing. You don't have to specify the number of channels +in and out \, since that's set by creation arguments below. Audio config +arguments arguments (-audiobuf \, -audiodev \, etc.) are ignored.; +#X connect 0 0 17 0; +#X connect 1 0 10 0; +#X connect 1 0 12 0; +#X connect 2 0 6 0; +#X connect 5 0 17 0; +#X connect 6 0 3 0; +#X connect 7 0 9 0; +#X connect 9 0 8 0; +#X connect 10 0 17 0; +#X connect 11 0 10 1; +#X connect 12 0 17 1; +#X connect 13 0 12 1; +#X connect 14 0 4 0; +#X connect 16 0 17 0; +#X connect 17 0 15 0; +#X connect 17 1 2 0; +#X connect 17 2 7 0; diff --git a/extra/pd~/pd~-subprocess.pd b/extra/pd~/pd~-subprocess.pd new file mode 100644 index 0000000000000000000000000000000000000000..1d883ab18862f32895c2aafeb63910822fdbf9cf --- /dev/null +++ b/extra/pd~/pd~-subprocess.pd @@ -0,0 +1,60 @@ +#N canvas 577 21 563 559 12; +#X obj 202 395 r foo; +#X obj 202 423 print foo; +#X obj 87 174 adc~; +#X obj 72 442 stdout; +#X msg 72 364 a b c; +#X msg 455 441 \; pd dsp 1; +#X obj 87 201 env~ 8192; +#X floatatom 87 250 5 0 0 0 - - -; +#X obj 87 226 i; +#X obj 263 253 dac~; +#X obj 262 185 osc~ 440; +#X obj 262 219 *~; +#X obj 297 220 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 332 186 osc~ 440; +#X obj 332 220 *~; +#X obj 367 221 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X msg 86 411 bang; +#X obj 455 417 loadbang; +#X obj 160 201 env~ 8192; +#X floatatom 160 250 5 0 0 0 - - -; +#X obj 160 226 i; +#X msg 86 388 4; +#X text 62 8 This is a test patch to demonstrate the Pd~ object. It's +intended as the patch to run in the sub-process. The sub-process (which +is a separate instance of Pd) can be called from a Max or Pd super-process. +; +#X text 63 73 Audio inlets and outlets on the Pd~ object (in the super-process) +talk to adc~ and dac~ objects here - so \, for instance \, the first +adc~ here is the first inlet of the pd~ object \, and the first chanel +of dac~ goes to the second outlet of pd~ (because the first one is +for messages \, as shown further below.); +#X text 58 283 Any message sent to a stdout object in this sub-process +(below) appears on the first \, message outlet of the pd~ object in +the super-process. The super-process can send messages to any "receive" +object in this sub-process.; +#X text 137 478 We turn DSP on at load for convenience - control objects +in this patch will still work without it (unlike in the super-process +\, where DSP must be on for time to move forward in the sub-process.) +; +#X text 351 538 Updated for Pd version 0.42.; +#X connect 0 0 1 0; +#X connect 2 0 6 0; +#X connect 2 1 18 0; +#X connect 4 0 3 0; +#X connect 6 0 8 0; +#X connect 8 0 7 0; +#X connect 10 0 11 0; +#X connect 11 0 9 0; +#X connect 12 0 11 1; +#X connect 13 0 14 0; +#X connect 14 0 9 1; +#X connect 15 0 14 1; +#X connect 16 0 3 0; +#X connect 17 0 5 0; +#X connect 18 0 20 0; +#X connect 20 0 19 0; +#X connect 21 0 3 0; diff --git a/extra/pd~/pd~.c b/extra/pd~/pd~.c new file mode 100644 index 0000000000000000000000000000000000000000..165065f8a90e2a64d6c4b80a90355b0a569b3207 --- /dev/null +++ b/extra/pd~/pd~.c @@ -0,0 +1,765 @@ +/* + pd~.c - embed a Pd process within Pd or Max. + + Copyright 2008 Miller Puckette + BSD license; see README.txt in this distribution for details. +*/ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#ifdef NT +#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; +#define w_symbol w_sym +#define A_SYMBOL A_SYM +#define getbytes t_getbytes +#define freebytes t_freebytes +#define ERROR error( +void *pd_tilde_class; +#define MAXPDSTRING 4096 +#define DEFDACBLKSIZE 64 +#endif /* MSP */ + +#ifdef PD +#include "m_pd.h" +#include "s_stuff.h" +static t_class *pd_tilde_class; +char *class_gethelpdir(t_class *c); +#define ERROR pd_error(x, + +#endif + +#ifdef __linux__ +#ifdef __x86_64__ +static char pd_tilde_dllextent[] = ".l_ia64", + pd_tilde_dllextent2[] = ".pd_linux"; +#else +static char pd_tilde_dllextent[] = ".l_i386", + pd_tilde_dllextent2[] = ".pd_linux"; +#endif +#endif +#ifdef __APPLE__ +static char pd_tilde_dllextent[] = ".d_fat", + pd_tilde_dllextent2[] = ".pd_darwin"; +#endif + +/* ------------------------ pd_tilde~ ----------------------------- */ + +#define MSGBUFSIZE 65536 + +typedef struct _pd_tilde +{ +#ifdef PD + t_object x_obj; + t_clock *x_clock; + t_outlet *x_outlet1; /* for messages back from subproc */ + t_canvas *x_canvas; +#endif /* PD */ +#ifdef MSP + t_pxobject x_obj; + void *x_outlet1; + void *x_clock; +#endif /* MSP */ + FILE *x_infd; + FILE *x_outfd; + char *x_msgbuf; + int x_msgbufsize; + int x_infill; + int x_childpid; + int x_ninsig; + int x_noutsig; + int x_fifo; + float x_sr; + t_symbol *x_pddir; + t_symbol *x_schedlibdir; + t_sample **x_insig; + t_sample **x_outsig; +} t_pd_tilde; + +#ifdef MSP +static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av); +static void pd_tilde_tick(t_pd_tilde *x); +static t_int *pd_tilde_perform(t_int *w); +static void pd_tilde_dsp(t_pd_tilde *x, t_signal **sp); +void pd_tilde_assist(t_pd_tilde *x, void *b, long m, long a, char *s); +static void pd_tilde_free(t_pd_tilde *x); +void pd_tilde_setup(void); +int main(); +void pd_tilde_minvel_set(t_pd_tilde *x, void *attr, long ac, t_atom *av); +char *strcpy(char *s1, const char *s2); +#endif + +static void pd_tilde_tick(t_pd_tilde *x); +static void pd_tilde_close(t_pd_tilde *x) +{ + if (x->x_outfd) + fclose(x->x_outfd); + if (x->x_infd) + fclose(x->x_infd); + if (x->x_childpid > 0) + waitpid(x->x_childpid, 0, 0); + if (x->x_msgbuf) + free(x->x_msgbuf); + x->x_infd = x->x_outfd = 0; + x->x_childpid = -1; + x->x_msgbuf = 0; + x->x_msgbufsize = 0; +} + +static void pd_tilde_readmessages(t_pd_tilde *x) +{ + int gotsomething = 0, setclock = 0, wasempty = (x->x_infill == 0); + FILE *infd = x->x_infd; + while (1) + { + int c = getc(infd); + if (c == EOF) + { + ERROR "pd~: %s", strerror(errno)); + pd_tilde_close(x); + break; + } + if (x->x_infill >= x->x_msgbufsize) + { + char *z = realloc(x->x_msgbuf, x->x_msgbufsize+MSGBUFSIZE); + if (!z) + { + ERROR "pd~: failed to grow input buffer"); + pd_tilde_close(x); + break; + } + x->x_msgbuf = z; + x->x_msgbufsize += MSGBUFSIZE; + } + x->x_msgbuf[x->x_infill++] = c; + if (c == ';') + { + if (!gotsomething) + break; + gotsomething = 0; + } + else if (!isspace(c)) + gotsomething = setclock = 1; + } + if (setclock) + clock_delay(x->x_clock, 0); + else if (wasempty) + x->x_infill = 0; +} + +static void pd_tilde_donew(t_pd_tilde *x, char *pddir, char *schedlibdir, + char *patchdir, char *pdargs, int ninsig, int noutsig, int fifo, + float samplerate) +{ + int i, pid, pipe1[2], pipe2[2]; + char cmdbuf[MAXPDSTRING], pdexecbuf[MAXPDSTRING], schedbuf[MAXPDSTRING]; + struct stat statbuf; + x->x_infd = x->x_outfd = 0; + x->x_childpid = -1; + snprintf(pdexecbuf, MAXPDSTRING, "%s/bin/pd", pddir); + if (stat(pdexecbuf, &statbuf) < 0) + { + snprintf(pdexecbuf, MAXPDSTRING, "%s/../../../bin/pd", pddir); + if (stat(pdexecbuf, &statbuf) < 0) + { + snprintf(pdexecbuf, MAXPDSTRING, "%s/pd", pddir); + if (stat(pdexecbuf, &statbuf) < 0) + { + ERROR "pd~: can't stat %s", pdexecbuf); + goto fail1; + } + } + } + snprintf(schedbuf, MAXPDSTRING, "%s/pdsched%s", schedlibdir, + pd_tilde_dllextent); + if (stat(schedbuf, &statbuf) < 0) + { + snprintf(schedbuf, MAXPDSTRING, "%s/pdsched%s", schedlibdir, + pd_tilde_dllextent2); + if (stat(schedbuf, &statbuf) < 0) + { + ERROR "pd~: can't stat %s", schedbuf); + goto fail1; + } + } + snprintf(cmdbuf, MAXPDSTRING, +"%s -schedlib %s/pdsched -path %s -inchannels %d -outchannels %d -r %g %s\n", + pdexecbuf, schedlibdir, patchdir, ninsig, noutsig, samplerate, pdargs); +#if 0 +#ifdef PD + fprintf(stderr, "%s", cmdbuf); +#endif + post("cmd: %s", cmdbuf); +#endif + if (pipe(pipe1) < 0) + { + ERROR "pd~: can't create pipe"); + goto fail1; + } + if (pipe(pipe2) < 0) + { + ERROR "pd~: can't create pipe"); + goto fail2; + } + if ((pid = fork()) < 0) + { + ERROR "pd~: can't fork"); + goto fail3; + } + else if (pid == 0) + { + /* child process */ + if (pipe2[1] == 0) + { + dup2(pipe2[1], 20); + close(pipe2[1]); + pipe2[1] = 20; + } + dup2(pipe1[0], 0); + dup2(pipe2[1], 1); + if (pipe1[0] >= 2) + close(pipe1[0]); + if (pipe1[1] >= 2) + close(pipe1[1]); + if (pipe2[0] >= 2) + close(pipe2[0]); + if (pipe2[1] >= 2) + close(pipe2[1]); + execl("/bin/sh", "sh", "-c", cmdbuf, (char*)0); + _exit(1); + } + /* OK, we're parent */ + close(pipe1[0]); + close(pipe2[1]); + x->x_outfd = fdopen(pipe1[1], "w"); + x->x_infd = fdopen(pipe2[0], "r"); + x->x_childpid = pid; + for (i = 0; i < fifo; i++) + fprintf(x->x_outfd, "%s", ";\n0;\n"); + fflush(x->x_outfd); + if (!(x->x_msgbuf = calloc(MSGBUFSIZE, 1))) + { + ERROR "pd~: can't allocate message buffer"); + goto fail3; + } + x->x_msgbufsize = MSGBUFSIZE; + x->x_infill = 0; + /* fprintf(stderr, "read...\n"); */ + pd_tilde_readmessages(x); + /* fprintf(stderr, "... done.\n"); */ + return; +fail3: + close(pipe2[0]); + close(pipe2[1]); + if (x->x_childpid > 0) + waitpid(x->x_childpid, 0, 0); +fail2: + close(pipe1[0]); + close(pipe1[1]); +fail1: + x->x_infd = x->x_outfd = 0; + x->x_childpid = -1; + return; +} + +static t_int *pd_tilde_perform(t_int *w) +{ + t_pd_tilde *x = (t_pd_tilde *)(w[1]); + int n = (int)(w[2]), i, j, numbuffill = 0, c; + char numbuf[80]; + FILE *infd = x->x_infd; + if (!infd) + goto zeroit; + fprintf(x->x_outfd, ";\n"); + if (!x->x_ninsig) + fprintf(x->x_outfd, "0\n"); + else for (i = 0; i < x->x_ninsig; i++) + { + t_sample *fp = x->x_insig[i]; + for (j = 0; j < n; j++) + fprintf(x->x_outfd, "%g\n", *fp++); + for (; j < DEFDACBLKSIZE; j++) + fprintf(x->x_outfd, "0\n"); + } + fprintf(x->x_outfd, ";\n"); + fflush(x->x_outfd); + i = j = 0; + while (1) + { + while (1) + { + c = getc(infd); + if (c == EOF) + { + if (errno) + ERROR "pd~: %s", strerror(errno)); + else ERROR "pd~: subprocess exited"); + pd_tilde_close(x); + goto zeroit; + } + else if (!isspace(c) && c != ';') + { + if (numbuffill < (80-1)) + numbuf[numbuffill++] = c; + } + else + { + t_sample z; + if (numbuffill) + { + numbuf[numbuffill] = 0; + if (sscanf(numbuf, "%f", &z) < 1) + continue; + if (i < x->x_noutsig) + x->x_outsig[i][j] = z; + if (++j >= DEFDACBLKSIZE) + j = 0, i++; + } + numbuffill = 0; + break; + } + } + /* message terminated */ + if (c == ';') + break; + } + for (; i < x->x_noutsig; i++, j = 0) + { + for (; j < DEFDACBLKSIZE; j++) + x->x_outsig[i][j] = 0; + } + pd_tilde_readmessages(x); + return (w+3); +zeroit: + for (i = 0; i < x->x_noutsig; i++) + { + for (j = 0; j < DEFDACBLKSIZE; j++) + x->x_outsig[i][j] = 0; + } + return (w+3); +} + +static void pd_tilde_dsp(t_pd_tilde *x, t_signal **sp) +{ + int i, n = (x->x_ninsig || x->x_noutsig ? sp[0]->s_n : 1); + t_sample **g; + + for (i = 0, g = x->x_insig; i < x->x_ninsig; i++, g++) + *g = (*(sp++))->s_vec; + + for (i = 0, g = x->x_outsig; i < x->x_noutsig; i++, g++) + *g = (*(sp++))->s_vec; + + dsp_add(pd_tilde_perform, 2, x, n); +} + +static void pd_tilde_pdtilde(t_pd_tilde *x, t_symbol *s, + int argc, t_atom *argv) +{ + t_symbol *sel = ((argc > 0 && argv->a_type == A_SYMBOL) ? + argv->a_w.w_symbol : gensym("?")), *schedlibdir; + char *patchdir; + if (sel == gensym("start")) + { + char pdargstring[MAXPDSTRING]; + if (x->x_infd) + pd_tilde_close(x); + pdargstring[0] = 0; + argc--; argv++; +#ifdef PD + while (argc--) + { + atom_string(argv++, pdargstring + strlen(pdargstring), + MAXPDSTRING - strlen(pdargstring)); + if (strlen(pdargstring) < MAXPDSTRING-1) + strcat(pdargstring, " "); + } + patchdir = canvas_getdir(x->x_canvas)->s_name; +#endif +#ifdef MSP + while (argc--) + { + /* because Mac pathnames sometimes have an evil preceeding + colon character, we test for and silently eat them */ + if (argv->a_type == A_SYM) + strncat(pdargstring, (*argv->a_w.w_sym->s_name == ':'? + argv->a_w.w_sym->s_name+1 : argv->a_w.w_sym->s_name), + MAXPDSTRING - strlen(pdargstring)-3); + else if (argv->a_type == A_LONG) + snprintf(pdargstring+strlen(pdargstring), + MAXPDSTRING - strlen(pdargstring)-3, "%ld", + argv->a_w.w_long); + else if (argv->a_type == A_FLOAT) + snprintf(pdargstring+strlen(pdargstring), + MAXPDSTRING - strlen(pdargstring)-3, "%f", + argv->a_w.w_float); + strcat(pdargstring, " "); + argv++; + } + patchdir = "."; +#endif + schedlibdir = x->x_schedlibdir; + if (schedlibdir == gensym(".") && x->x_pddir != gensym(".")) + { + char *pds = x->x_pddir->s_name, scheddirstring[MAXPDSTRING]; + int l = strlen(pds); + if (l >= 4 && (!strcmp(pds+l-3, "bin") || !strcmp(pds+l-4, "bin/"))) + snprintf(scheddirstring, MAXPDSTRING, "%s/../extra/pd~", pds); + else snprintf(scheddirstring, MAXPDSTRING, "%s/extra/pd~", pds); + schedlibdir = gensym(scheddirstring); + } + pd_tilde_donew(x, x->x_pddir->s_name, schedlibdir->s_name, + patchdir, pdargstring, x->x_ninsig, x->x_noutsig, x->x_fifo, + x->x_sr); + } + else if (sel == gensym("stop")) + { + if (x->x_infd) + pd_tilde_close(x); + } + else if (sel == gensym("pddir")) + { + if ((argc > 1) && argv[1].a_type == A_SYMBOL) + { + t_symbol *sym = argv[1].a_w.w_symbol; +#ifdef MSP + if (sym->s_name[0] == ':') + sym = gensym(s->s_name+1); +#endif + x->x_pddir = sym; + } + else ERROR "pd~ pddir: needs symbol argument"); + } + else ERROR "pd~: unknown control message: %s", sel->s_name); +} + +static void pd_tilde_free(t_pd_tilde *x) +{ +#ifdef MSP + dsp_free((t_pxobject *)x); +#endif + pd_tilde_close(x); + clock_free(x->x_clock); +} + +/* -------------------------- Pd glue ------------------------- */ +#ifdef PD + +static void pd_tilde_tick(t_pd_tilde *x) +{ + int messstart = 0, i, n; + t_atom *vec; + t_binbuf *b; + if (!x->x_msgbuf) + return; + b = binbuf_new(); + binbuf_text(b, x->x_msgbuf, x->x_infill); + /* binbuf_print(b); */ + n = binbuf_getnatom(b); + vec = binbuf_getvec(b); + for (i = 0; i < n; i++) + { + if (vec[i].a_type == A_SEMI) + { + if (i > messstart && vec[messstart].a_type == A_SYMBOL) + outlet_anything(x->x_outlet1, vec[messstart].a_w.w_symbol, + i-(messstart+1), vec+(messstart+1)); + else if (i > messstart) + outlet_list(x->x_outlet1, 0, i-messstart, vec+messstart); + messstart = i+1; + } + } + binbuf_free(b); + x->x_infill = 0; +} + +static void pd_tilde_anything(t_pd_tilde *x, t_symbol *s, + int argc, t_atom *argv) +{ + char msgbuf[MAXPDSTRING]; + if (!x->x_outfd) + return; + fprintf(x->x_outfd, "%s ", s->s_name); + while (argc--) + { + atom_string(argv++, msgbuf, MAXPDSTRING); + fprintf(x->x_outfd, "%s ", msgbuf); + } + fprintf(x->x_outfd, ";\n"); +} + +static void *pd_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_pd_tilde *x = (t_pd_tilde *)pd_new(pd_tilde_class); + int ninsig = 2, noutsig = 2, j, fifo = 5; + float sr = sys_getsr(); + t_sample **g; + t_symbol *pddir = sys_guidir, + *scheddir = gensym(class_gethelpdir(pd_tilde_class)); + /* fprintf(stderr, "pd %s, sched %s\n", pddir->s_name, scheddir->s_name); */ + while (argc > 0) + { + t_symbol *firstarg = atom_getsymbolarg(0, argc, argv); + if (!strcmp(firstarg->s_name, "-sr") && argc > 1) + { + sr = atom_getfloatarg(1, argc, argv); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-ninsig") && argc > 1) + { + ninsig = atom_getfloatarg(1, argc, argv); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-noutsig") && argc > 1) + { + noutsig = atom_getfloatarg(1, argc, argv); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-fifo") && argc > 1) + { + fifo = atom_getfloatarg(1, argc, argv); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-pddir") && argc > 1) + { + pddir = atom_getsymbolarg(1, argc, argv); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-scheddir") && argc > 1) + { + scheddir = atom_getsymbolarg(1, argc, argv); + argc -= 2; argv += 2; + } + else break; + } + + if (argc) + { + pd_error(x, +"usage: pd~ [-sr #] [-ninsig #] [-noutsig #] [-fifo #] [-pddir <>]"); + post( +"... [-scheddir <>]"); + } + + x->x_clock = clock_new(x, (t_method)pd_tilde_tick); + x->x_insig = (t_sample **)getbytes(ninsig * sizeof(*x->x_insig)); + x->x_outsig = (t_sample **)getbytes(noutsig * sizeof(*x->x_outsig)); + x->x_ninsig = ninsig; + x->x_noutsig = noutsig; + x->x_fifo = fifo; + x->x_sr = sr; + x->x_pddir = pddir; + x->x_schedlibdir = scheddir; + x->x_infd = 0; + x->x_outfd = 0; + x->x_outfd = 0; + x->x_childpid = -1; + x->x_msgbuf = 0; + x->x_canvas = canvas_getcurrent(); + for (j = 1, g = x->x_insig; j < ninsig; j++, g++) + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + x->x_outlet1 = outlet_new(&x->x_obj, 0); + for (j = 0, g = x->x_outsig; j < noutsig; j++, g++) + outlet_new(&x->x_obj, &s_signal); + signal(SIGPIPE, SIG_IGN); + + return (x); +} + +void pd_tilde_setup(void) +{ + pd_tilde_class = class_new(gensym("pd~"), (t_newmethod)pd_tilde_new, + (t_method)pd_tilde_free, sizeof(t_pd_tilde), 0, A_GIMME, 0); + class_addmethod(pd_tilde_class, nullfn, gensym("signal"), 0); + class_addmethod(pd_tilde_class, (t_method)pd_tilde_dsp, gensym("dsp"), 0); + class_addmethod(pd_tilde_class, (t_method)pd_tilde_pdtilde, gensym("pd~"), A_GIMME, 0); + class_addanything(pd_tilde_class, pd_tilde_anything); + post("pd~ version 0.2"); +} +#endif + +/* -------------------------- MSP glue ------------------------- */ +#ifdef MSP + +#define LOTS 10000 + +static void pd_tilde_tick(t_pd_tilde *x) +{ + int messstart = 0, i, n = 0; + t_atom vec[LOTS]; + long z1 = 0, z2 = 0; + void *b; + if (!x->x_msgbuf) + return; + b = binbuf_new(); + binbuf_text(b, &x->x_msgbuf, x->x_infill); + /* binbuf_print(b); */ + while (!binbuf_getatom(b, &z1, &z2, vec+n)) + if (++n >= LOTS) + break; + for (i = 0; i < n; i++) + { + if (vec[i].a_type == A_SEMI) + { + if (i > messstart + 1) + { + void *whom; + if (vec[messstart].a_type == A_SYM) + outlet_anything(x->x_outlet1, vec[messstart].a_w.w_sym, + i-messstart-1, vec+(messstart+1)); + else if (vec[messstart].a_type == A_FLOAT && i == messstart+1) + outlet_float(x->x_outlet1, vec[messstart].a_w.w_float); + else if (vec[messstart].a_type == A_LONG && i == messstart+1) + outlet_int(x->x_outlet1, vec[messstart].a_w.w_long); + else outlet_list(x->x_outlet1, gensym("list"), + i-messstart, vec+(messstart)); + } + messstart = i+1; + } + } + binbuf_free(b); + x->x_infill = 0; +} + +static void pd_tilde_anything(t_pd_tilde *x, t_symbol *s, + long ac, t_atom *av) +{ + char msgbuf[MAXPDSTRING], *sp, *ep = msgbuf+MAXPDSTRING; + if (!x->x_outfd) + return; + msgbuf[0] = 0; + strncpy(msgbuf, s->s_name, MAXPDSTRING); + msgbuf[MAXPDSTRING-1] = 0; + sp = msgbuf + strlen(msgbuf); + while (ac--) + { + if (sp < ep-1) + sp[0] = ' ', sp[1] = 0, sp++; + if (sp < ep - 80) + { + if (av->a_type == A_SYM && strlen(av->a_w.w_sym->s_name) < ep - sp-20) + strcpy(sp, av->a_w.w_sym->s_name); + else if (av->a_type == A_LONG) + sprintf(sp, "%ld" ,av->a_w.w_long); + else if (av->a_type == A_FLOAT) + sprintf(sp, "%g" ,av->a_w.w_float); + } + sp += strlen(sp); + av++; + } + fprintf(x->x_outfd, "%s;\n", msgbuf); +} + +int main() +{ + t_class *c; + + c = class_new("pd_tilde~", (method)pd_tilde_new, (method)pd_tilde_free, sizeof(t_pd_tilde), (method)0L, A_GIMME, 0); + + class_addmethod(c, (method)pd_tilde_dsp, "dsp", A_CANT, 0); + class_addmethod(c, (method)pd_tilde_assist, "assist", A_CANT, 0); + class_addmethod(c, (method)pd_tilde_pdtilde, "pd~", A_GIMME, 0); + class_addmethod(c, (method)pd_tilde_anything, "anything", A_GIMME, 0); + class_dspinit(c); + + class_register(CLASS_BOX, c); + pd_tilde_class = c; + post("pd~ version 0.2"); + return (0); +} + +static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av) +{ + int ninsig = 2, noutsig = 2, fifo = 5, j; + float sr = sys_getsr(); + t_symbol *pddir = gensym("."), *scheddir = gensym("."); + t_pd_tilde *x; + + if (x = (t_pd_tilde *)object_alloc(pd_tilde_class)) + { + while (ac > 0 && av[0].a_type == A_SYM) + { + char *flag = av[0].a_w.w_sym->s_name; + if (!strcmp(flag, "-sr") && ac > 1) + { + sr = (av[1].a_type == A_FLOAT ? av[1].a_w.w_float : + (av[1].a_type == A_LONG ? av[1].a_w.w_long : 0)); + ac -= 2; av += 2; + } + else if (!strcmp(flag, "-ninsig") && ac > 1) + { + ninsig = (av[1].a_type == A_FLOAT ? av[1].a_w.w_float : + (av[1].a_type == A_LONG ? av[1].a_w.w_long : 0)); + ac -= 2; av += 2; + } + else if (!strcmp(flag, "-noutsig") && ac > 1) + { + noutsig = (av[1].a_type == A_FLOAT ? av[1].a_w.w_float : + (av[1].a_type == A_LONG ? av[1].a_w.w_long : 0)); + ac -= 2; av += 2; + } + else if (!strcmp(flag, "-fifo") && ac > 1) + { + fifo = (av[1].a_type == A_FLOAT ? av[1].a_w.w_float : + (av[1].a_type == A_LONG ? av[1].a_w.w_long : 0)); + ac -= 2; av += 2; + } + else if (!strcmp(flag, "-pddir") && ac > 1) + { + pddir = (av[1].a_type == A_SYM ? av[1].a_w.w_sym : gensym(".")); + ac -= 2; av += 2; + } + else if (!strcmp(flag, "-scheddir") && ac > 1) + { + scheddir = (av[1].a_type == A_SYM ? av[1].a_w.w_sym : gensym(".")); + ac -= 2; av += 2; + } + else break; + } + if (ac) + post("pd~: warning: ignoring extra arguments"); + dsp_setup((t_pxobject *)x, ninsig); + x->x_outlet1 = outlet_new(&x->x_obj, 0); + for (j = 0; j < noutsig; j++) + outlet_new((t_pxobject *)x, "signal"); + x->x_clock = clock_new(x, (method)pd_tilde_tick); + x->x_insig = (t_sample **)getbytes(ninsig * sizeof(*x->x_insig)); + x->x_outsig = (t_sample **)getbytes(noutsig * sizeof(*x->x_outsig)); + x->x_ninsig = ninsig; + x->x_noutsig = noutsig; + x->x_fifo = fifo; + x->x_sr = sr; + x->x_pddir = pddir; + x->x_schedlibdir = scheddir; + x->x_infd = 0; + x->x_outfd = 0; + x->x_outfd = 0; + x->x_childpid = -1; + x->x_msgbuf = 0; + } + return (x); +} + +void pd_tilde_assist(t_pd_tilde *x, void *b, long m, long a, char *s) +{ +} + +#endif /* MSP */ diff --git a/extra/pd~/z.pd b/extra/pd~/z.pd new file mode 100644 index 0000000000000000000000000000000000000000..373201dae810491301d0a2b2208c4b069a2be81c --- /dev/null +++ b/extra/pd~/z.pd @@ -0,0 +1,15 @@ +#N canvas 686 241 450 300 10; +#X obj 65 58 r foo; +#X obj 62 100 print foo; +#X obj 244 59 adc~; +#X obj 238 102 env~ 8192; +#X floatatom 236 140 5 0 0 0 - - -; +#X obj 155 234 dac~; +#X obj 155 191 osc~ 440; +#X obj 287 204 stdout; +#X msg 307 153 a b c; +#X connect 0 0 1 0; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 6 0 5 0; +#X connect 8 0 7 0; diff --git a/extra/pique/pique.pd_linux b/extra/pique/pique.pd_linux deleted file mode 100755 index 1cb271dd65076c394b61ecc35604fe678fd0bdb4..0000000000000000000000000000000000000000 Binary files a/extra/pique/pique.pd_linux and /dev/null differ diff --git a/extra/sigmund~/makefile b/extra/sigmund~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..3dc176b3b4e7509e2a93b2813ad17554e513ab99 --- /dev/null +++ b/extra/sigmund~/makefile @@ -0,0 +1,4 @@ +NAME=sigmund~ +CSYM=sigmund_tilde + +include ../makefile diff --git a/extra/sigmund~/sigmund~-help.pd b/extra/sigmund~/sigmund~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..5ddbf6d1b21243b161fa27db053ba83f206f373d --- /dev/null +++ b/extra/sigmund~/sigmund~-help.pd @@ -0,0 +1,194 @@ +#N canvas 167 -7 580 617 12; +#X text 42 4 sigmund~ - sinusoidal analysis and pitch tracking; +#N canvas 432 117 573 597 using-with-tables 0; +#X obj 29 368 print peak; +#N canvas 0 0 450 300 (subpatch) 0; +#X array insignal 1024 float 2; +#X coords 0 1 1023 -1 200 140 1; +#X restore 83 426 graph; +#X obj 314 513 phasor~; +#X obj 294 429 loadbang; +#X obj 314 461 440; +#X floatatom 313 488 5 0 0 0 - - -; +#X obj 305 544 tabwrite~ insignal; +#X obj 290 516 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X text 114 11 Using sigmund~ on arrays; +#X text 42 33 If invoked with the "-t" flag (as a creation argument) +\, sigmund~ analyzes waveforms stored in arrays. Instead of an incoming +signal \, feed it "list" messages with the following arguments:; +#X text 37 118 table name (a symbol); +#X text 38 137 number of points; +#X obj 29 342 sigmund~ -t -npeak 10 -maxfreq 5000 peaks; +#X msg 29 316 list insignal 1024 0 44100 0; +#X text 37 158 index of first point; +#X text 39 179 sample rate; +#X text 38 200 debug flag (print debugging info if nonzero); +#X text 23 232 In this mode \, only the "env" \, "pitch" \, and "peaks" +outputs are meaningful.; +#X text 31 294 click here to test:; +#X connect 2 0 6 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 5 0 2 0; +#X connect 5 0 7 0; +#X connect 7 0 6 0; +#X connect 12 0 0 0; +#X connect 13 0 12 0; +#X restore 330 553 pd using-with-tables; +#X obj 40 512 phasor~; +#X obj 40 425 loadbang; +#X floatatom 40 471 5 0 120 0 - - -; +#X floatatom 39 561 5 0 0 0 - - -; +#X floatatom 245 563 5 0 0 0 - - -; +#X obj 40 490 mtof; +#X obj 40 448 69; +#X text 38 579 pitch; +#X text 222 582 envelope; +#X text 13 28 Sigmund~ analyzes an incoming sound into sinusoidal components +\, which may be reported individually or combined to form a pitch estimate. +Possible outputs are specified as creation arguments:; +#X text 56 95 pitch - output pitch continuously; +#N canvas 518 74 588 728 setting-parameters 0; +#X msg 182 66 print; +#X floatatom 192 92 5 0 0 0 - - -; +#X msg 192 113 minpower \$1; +#X obj 182 139 sigmund~ -minpower 40; +#X text 39 14 You can set parameters either by creation arguments \, +or else using messages. The "print" message gives you the current values +of all the parameters:; +#X text 28 169 npts: number of points used in an analysis. Must be +a power of two \, at least 128 The minimum frequency that can be tracked +is about 2(sample_rate)/npts.; +#X text 26 219 hop: number of points between analyses. Must be a power +of two \, at least the DSP vector size (usually 64). This regulates +the number of analyses done per unit of time.; +#X text 28 271 npeak: maximum number of sinusoidal peaks to look for. +The computation time is quadratic in the number of peaks actually found +(this number only sets an upper limit). Use it to balance CPU time +with quality of results.; +#X text 30 336 maxfreq: maximum frequency of sinusoidal peaks to look +for. This can be useful in situations where background noise creates +high-frequency \, spurious peaks..; +#X text 37 388 vibrato: maximum deviation from "pitch" to accept as +normal vibrato (affects "notes" output only). If the value is too small. +vibratos will appear as trills. If too large \, very small melodic +intervals may not be reported as new notes.; +#X text 33 457 stabletime: time period to wait before reporting a note +(affects "notes" output only). The "pitch" must be present and must +not vary more than "vibrato" for this entire period to report a note. +If too large \, the "notes" will be unnecessarily delayed. If too small +\, spurious notes get output.; +#X text 31 551 minpower: minimum measured RMS level to report a pitch +(affects "pitch" and "notes" output only). Signals quieter than this +will be assumed to be crosstalk and ignored.; +#X text 32 602 growth: minimum measured RMS growth to report a new +note (affects "notes" output only). The RMS level must rise by this +many dB (within a time period given by "stabletime") to report a repetition +of a note at or near the previously output pitch.; +#X connect 0 0 3 0; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X restore 330 531 pd setting-parameters; +#N canvas 67 29 641 815 sinusoid-tracking 0; +#X obj 124 267 sigmund~ -npeak 10 peaks; +#X obj 124 214 phasor~; +#X obj 124 144 loadbang; +#X floatatom 124 190 5 0 120 0 - - -; +#X obj 124 295 route 0 1 2 3 4 5 6 7 8 9; +#X obj 82 339 unpack 0 0 0 0; +#X floatatom 82 461 5 0 0 0 - - -; +#X floatatom 122 431 5 0 0 0 - - -; +#X floatatom 162 406 5 0 0 0 - - -; +#X obj 124 167 440; +#X floatatom 203 380 5 0 0 0 - - -; +#X obj 322 349 unpack 0 0 0 0; +#X floatatom 322 471 5 0 0 0 - - -; +#X floatatom 362 441 5 0 0 0 - - -; +#X floatatom 402 416 5 0 0 0 - - -; +#X floatatom 443 390 5 0 0 0 - - -; +#X text 385 475 frequency (Hz.); +#X text 419 442 peak amplitude (linear); +#X text 464 416 cosine component; +#X text 499 390 sine component; +#X text 79 505 loudest partial; +#X text 332 508 quietest partial; +#X text 36 4 You can ask for sinusoidal peaks in decreasing order of +amplitude or arranged into maximally continuous tracks for resynthesis. +(Or you can ask for both.) If you ask for peaks \, out come lists of +five numbers \, one for each sinusoid at each analysis period. The +first is the index number of the sinusoid (so you can use "route" to +claw them apart). The other four are as shown:; +#X obj 204 611 osc~ 440; +#X obj 204 635 *~; +#X obj 205 689 unpack 0 0 0 0; +#X floatatom 205 782 5 0 0 0 - - -; +#X floatatom 245 760 5 0 0 0 - - -; +#X floatatom 285 737 5 0 0 0 - - -; +#X floatatom 326 713 5 0 0 0 - - -; +#X obj 246 638 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X text 43 535 If you ask for "tracks" \, the output is four numbers: +index \, frequency \, and amplitude as before \, and finally a flag +which is one for a new track \, zero for a continuation \, minus one +for an empty track.; +#X obj 205 662 sigmund~ -npts 16384 -hop 8192 -npeak 1 tracks; +#X connect 0 0 4 0; +#X connect 1 0 0 0; +#X connect 2 0 9 0; +#X connect 3 0 1 0; +#X connect 4 0 5 0; +#X connect 4 9 11 0; +#X connect 5 0 6 0; +#X connect 5 1 7 0; +#X connect 5 2 8 0; +#X connect 5 3 10 0; +#X connect 9 0 3 0; +#X connect 11 0 12 0; +#X connect 11 1 13 0; +#X connect 11 2 14 0; +#X connect 11 3 15 0; +#X connect 23 0 24 0; +#X connect 24 0 32 0; +#X connect 25 0 26 0; +#X connect 25 1 27 0; +#X connect 25 2 28 0; +#X connect 25 3 29 0; +#X connect 30 0 24 1; +#X connect 32 0 25 0; +#X restore 330 508 pd sinusoid-tracking; +#X text 52 165 tracks - output sinusoidal peaks organized into tracks +; +#X text 56 111 notes - output pitch at the beginning of notes; +#X text 339 485 more details:; +#X text 10 184 Parameters you may set (in creation arguments or messages): +; +#X text 60 207 npts - number of points in each analysis window (1024) +; +#X text 60 225 hop - number of points between each analysis (512); +#X text 60 242 npeak - number of sinusoidal peaks (20); +#X text 61 279 vibrato - depth of vibrato to expect in 1/2-tones (1) +; +#X text 60 298 stabletime - time (msec) to wait to report notes (50) +; +#X obj 39 535 sigmund~ -hop 4096 pitch env; +#X text 62 316 minpower - minimum power (dB) to report a pitch (50) +; +#X text 62 335 growth - growth (dB) to report a new note (7); +#X text 54 147 peaks - output all sinusoidal peaks in order of amplitude +; +#X text 11 356 The npts and hop parameters are in samples \, and are +powers of two. The example below specifies a huge hop of 4096 (to slow +the output down) and to output "pitch" and "env". (Those are the default +outputs.); +#X text 61 260 maxfreq - maximum sinusoid frequency in Hz. (1000000) +; +#X text 55 128 env - output amplitude continuously; +#X text 380 596 updated for Pd v0.41; +#X connect 2 0 24 0; +#X connect 3 0 8 0; +#X connect 4 0 7 0; +#X connect 7 0 2 0; +#X connect 8 0 4 0; +#X connect 24 0 5 0; +#X connect 24 1 6 0; diff --git a/extra/sigmund~/sigmund~.c b/extra/sigmund~/sigmund~.c new file mode 100644 index 0000000000000000000000000000000000000000..92604b7ea2ed54d203f0307c9e34406da709edf5 --- /dev/null +++ b/extra/sigmund~/sigmund~.c @@ -0,0 +1,1656 @@ +/* Copyright (c) 2005 Miller Puckette. BSD licensed. No warranties. */ + +/* + fix parameter settings + not to report pitch if evidence too scanty? + note-on detection triggered by falling envelope (a posteriori) + reentrancy bug setting loud flag (other parameters too?) + tweaked freqs still not stable enough + implement block ("-b") mode +*/ + +/* 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: */ + +#ifdef NT +__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 _WIN32 +#include <malloc.h> +#else +#include <alloca.h> +#endif +#include <stdlib.h> +#ifdef _MSC_VER +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +typedef struct peak +{ + float p_freq; + float p_amp; + float p_ampreal; + float p_ampimag; + float p_pit; + float p_db; + float p_salience; + float p_tmp; +} t_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; + while (n) + { + n >>= 1; + ret++; + } + 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 +#define NEGBINS 4 /* number of bins of negative frequency we'll need */ + +#define PI 3.14159265 +#define LOG2 0.69314718 +#define LOG10 2.30258509 + +static float sinx(float theta, float sintheta) +{ + if (theta > -0.003 && theta < 0.003) + return (1); + else return (sintheta/theta); +} + +static float window_hann_mag(float pidetune, float sinpidetune) +{ + return (W_ALPHA * sinx(pidetune, sinpidetune) + - 0.5 * W_BETA * + (sinx(pidetune+PI, sinpidetune) + sinx(pidetune-PI, sinpidetune))); +} + +static float window_mag(float pidetune, float cospidetune) +{ + return (sinx(pidetune + (PI/2), cospidetune) + + sinx(pidetune - (PI/2), -cospidetune)); +} + +/*********** Routines to analyze a window into sinusoidal peaks *************/ + +static int sigmund_cmp_freq(const void *p1, const void *p2) +{ + if ((*(t_peak **)p1)->p_freq > (*(t_peak **)p2)->p_freq) + return (1); + else if ((*(t_peak **)p1)->p_freq < (*(t_peak **)p2)->p_freq) + return (-1); + else return (0); +} + +static void sigmund_tweak(int npts, float *ftreal, float *ftimag, + int npeak, t_peak *peaks, float fperbin, int loud) +{ + t_peak **peakptrs = (t_peak **)alloca(sizeof (*peakptrs) * (npeak+1)); + t_peak negpeak; + int peaki, j, k; + float ampreal[3], ampimag[3]; + float binperf = 1./fperbin; + float phaseperbin = (npts-0.5)/npts, oneovern = 1./npts; + if (npeak < 1) + return; + for (peaki = 0; peaki < npeak; peaki++) + peakptrs[peaki+1] = &peaks[peaki]; + qsort(peakptrs+1, npeak, sizeof (*peakptrs), sigmund_cmp_freq); + peakptrs[0] = &negpeak; + negpeak.p_ampreal = peakptrs[1]->p_ampreal; + negpeak.p_ampimag = -peakptrs[1]->p_ampimag; + negpeak.p_freq = -peakptrs[1]->p_freq; + for (peaki = 1; peaki <= npeak; peaki++) + { + int cbin = peakptrs[peaki]->p_freq*binperf + 0.5; + int nsub = (peaki == npeak ? 1:2); + float windreal, windimag, windpower, detune, pidetune, sinpidetune, + cospidetune, ampcorrect, ampout, ampoutreal, ampoutimag, freqout; + /* post("3 nsub %d amp %f freq %f", nsub, + peakptrs[peaki]->p_amp, peakptrs[peaki]->p_freq); */ + if (cbin < 0 || cbin > 2*npts - 3) + continue; + for (j = 0; j < 3; j++) + ampreal[j] = ftreal[cbin+2*j-2], ampimag[j] = ftimag[cbin+2*j-2]; + /* post("a %f %f", ampreal[1], ampimag[1]); */ + for (j = 0; j < nsub; j++) + { + t_peak *neighbor = peakptrs[(peaki-1) + 2*j]; + float neighborreal = npts * neighbor->p_ampreal; + float neighborimag = npts * neighbor->p_ampimag; + for (k = 0; k < 3; k++) + { + float freqdiff = (0.5*PI) * ((cbin + 2*k-2) + -binperf * neighbor->p_freq); + float sx = sinx(freqdiff, sin(freqdiff)); + float phasere = cos(freqdiff * phaseperbin); + float phaseim = sin(freqdiff * phaseperbin); + ampreal[k] -= + sx * (phasere * neighborreal - phaseim * neighborimag); + ampimag[k] -= + sx * (phaseim * neighborreal + phasere * neighborimag); + } + /* post("b %f %f", ampreal[1], ampimag[1]); */ + } + + windreal = W_ALPHA * ampreal[1] - + (0.5 * W_BETA) * (ampreal[0] + ampreal[2]); + windimag = W_ALPHA * ampimag[1] - + (0.5 * W_BETA) * (ampimag[0] + ampimag[2]); + windpower = windreal * windreal + windimag * windimag; + detune = ( + W_BETA*(ampreal[0] - ampreal[2]) * + (2.0*W_ALPHA * ampreal[1] - W_BETA * (ampreal[0] + ampreal[2])) + + + W_BETA*(ampimag[0] - ampimag[2]) * + (2.0*W_ALPHA * ampimag[1] - W_BETA * (ampimag[0] + ampimag[2])) + ) / (4.0 * windpower); + if (detune > 0.5) + detune = 0.5; + else if (detune < -0.5) + detune = -0.5; + /* if (loud > 0) + post("tweak: windpower %f, bin %d, detune %f", + windpower, cbin, detune); */ + pidetune = PI * detune; + sinpidetune = sin(pidetune); + cospidetune = cos(pidetune); + + ampcorrect = 1.0 / window_hann_mag(pidetune, sinpidetune); + + ampout = oneovern * ampcorrect *sqrt(windpower); + ampoutreal = oneovern * ampcorrect * + (windreal * cospidetune - windimag * sinpidetune); + ampoutimag = oneovern * ampcorrect * + (windreal * sinpidetune + windimag * cospidetune); + freqout = (cbin + 2*detune) * fperbin; + /* if (loud > 1) + post("amp %f, freq %f", ampout, freqout); */ + + peakptrs[peaki]->p_freq = freqout; + peakptrs[peaki]->p_amp = ampout; + peakptrs[peaki]->p_ampreal = ampoutreal; + peakptrs[peaki]->p_ampimag = ampoutimag; + } +} + +static void sigmund_remask(int maxbin, int bestindex, float powmask, + float maxpower, float *maskbuf) +{ + int bin; + int bin1 = (bestindex > 52 ? bestindex-50:2); + int bin2 = (maxbin < bestindex + 50 ? bestindex + 50 : maxbin); + for (bin = bin1; bin < bin2; bin++) + { + float bindiff = bin - bestindex; + float mymask; + mymask = powmask/ (1. + bindiff * bindiff * bindiff * bindiff); + if (bindiff < 2 && bindiff > -2) + mymask = 2*maxpower; + if (mymask > maskbuf[bin]) + maskbuf[bin] = mymask; + } +} + +static void sigmund_getrawpeaks(int npts, float *insamps, + int npeak, t_peak *peakv, int *nfound, float *power, float srate, int loud, + float param1, float param2, float param3, float hifreq) +{ + float oneovern = 1.0/ (float)npts; + float fperbin = 0.5 * srate * oneovern, totalpower = 0; + int npts2 = 2*npts, i, bin; + int peakcount = 0; + float *fp1, *fp2; + 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); */ + maskbuf = bigbuf + npts2; + powbuf = maskbuf + npts; + rawreal = powbuf + npts+NEGBINS; + rawimag = rawreal+npts+NEGBINS; + for (i = 0; i < npts; i++) + maskbuf[i] = 0; + + for (i = 0; i < npts; i++) + bigbuf[i] = insamps[i]; + for (i = npts; i < 2*npts; i++) + bigbuf[i] = 0; + mayer_realfft(npts2, bigbuf); + for (i = 0; i < npts; i++) + rawreal[i] = bigbuf[i]; + for (i = 1; i < npts-1; i++) + rawimag[i] = bigbuf[npts2-i]; + rawreal[-1] = rawreal[1]; + rawreal[-2] = rawreal[2]; + rawreal[-3] = rawreal[3]; + rawreal[-4] = rawreal[4]; + rawimag[0] = rawimag[npts-1] = 0; + rawimag[-1] = -rawimag[1]; + rawimag[-2] = -rawimag[2]; + rawimag[-3] = -rawimag[3]; + rawimag[-4] = -rawimag[4]; +#if 1 + for (i = 0, fp1 = rawreal, fp2 = rawimag; i < maxbin; i++, fp1++, fp2++) + { + float x1 = fp1[1] - fp1[-1], x2 = fp2[1] - fp2[-1], p = powbuf[i] = x1*x1+x2*x2; + if (i >= 2) + totalpower += p; + } + powbuf[maxbin] = powbuf[maxbin+1] = 0; + *power = 0.5 * totalpower *oneovern * oneovern; +#endif + for (peakcount = 0; peakcount < npeak; peakcount++) + { + float pow1, maxpower = 0, windreal, windimag, windpower, + detune, pidetune, sinpidetune, cospidetune, ampcorrect, ampout, + ampoutreal, ampoutimag, freqout, powmask; + int bestindex = -1; + + for (bin = 2, fp1 = rawreal+2, fp2 = rawimag+2; + bin < maxbin; bin++, fp1++, fp2++) + { + pow1 = powbuf[bin]; + if (pow1 > maxpower && pow1 > maskbuf[bin]) + { + float thresh = param2 * (powbuf[bin-2]+powbuf[bin+2]); + if (pow1 > thresh) + maxpower = pow1, bestindex = bin; + } + } + + if (totalpower <= 0 || maxpower < 1e-10*totalpower || bestindex < 0) + break; + fp1 = rawreal+bestindex; + fp2 = rawimag+bestindex; + powmask = maxpower * exp(-param1 * log(10.) / 10.); + /* if (loud > 2) + post("maxpower %f, powmask %f, param1 %f", + maxpower, powmask, param1); */ + sigmund_remask(maxbin, bestindex, powmask, maxpower, maskbuf); + + /* 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 (detune > 0.5) + detune = 0.5; + else if (detune < -0.5) + detune = -0.5; + /* if (loud > 1) + post("windpower %f, index %d, detune %f", + windpower, bestindex, detune); */ + pidetune = PI * detune; + sinpidetune = sin(pidetune); + cospidetune = cos(pidetune); + ampcorrect = 1.0 / window_mag(pidetune, cospidetune); + + ampout = ampcorrect *sqrt(windpower); + ampoutreal = ampcorrect * + (windreal * cospidetune - windimag * sinpidetune); + ampoutimag = ampcorrect * + (windreal * sinpidetune + windimag * cospidetune); + + /* the frequency is the sum of the bin frequency and detuning */ + + peakv[peakcount].p_freq = (freqout = (bestindex + 2*detune)) * fperbin; + peakv[peakcount].p_amp = oneovern * ampout; + peakv[peakcount].p_ampreal = oneovern * ampoutreal; + peakv[peakcount].p_ampimag = oneovern * ampoutimag; + } + if (tweak) + { + sigmund_tweak(npts, rawreal, rawimag, peakcount, peakv, fperbin, loud); + sigmund_tweak(npts, rawreal, rawimag, peakcount, peakv, fperbin, loud); + } + for (i = 0; i < peakcount; i++) + { + peakv[i].p_pit = sigmund_ftom(peakv[i].p_freq); + peakv[i].p_db = sigmund_powtodb(peakv[i].p_amp); + } + *nfound = peakcount; +} + +/*************** Routines for finding fundamental pitch *************/ + +#define PITCHNPEAK 12 +#define PITCHUNCERTAINTY 0.3 +#define HALFTONEINC 0.059 +#define SUBHARMONICS 16 +#define DBPERHALFTONE 0.0 + +static void sigmund_getpitch(int npeak, t_peak *peakv, float *freqp, + float npts, float srate, int loud) +{ + float fperbin = 0.5 * srate / npts; + int npit = 48 * sigmund_ilog2(npts), i, j, k, nsalient; + float bestbin, bestweight, sumamp, sumweight, sumfreq, freq; + float *weights = (float *)alloca(sizeof(float) * npit); + t_peak *bigpeaks[PITCHNPEAK]; + if (npeak < 1) + { + freq = 0; + goto done; + } + for (i = 0; i < npit; i++) + weights[i] = 0; + for (i = 0; i < npeak; i++) + { + peakv[i].p_tmp = 0; + peakv[i].p_salience = peakv[i].p_db - DBPERHALFTONE * peakv[i].p_pit; + } + for (nsalient = 0; nsalient < PITCHNPEAK; nsalient++) + { + t_peak *bestpeak = 0; + float bestsalience = -1e20; + for (j = 0; j < npeak; j++) + if (peakv[j].p_tmp == 0 && peakv[j].p_salience > bestsalience) + { + bestsalience = peakv[j].p_salience; + bestpeak = &peakv[j]; + } + if (!bestpeak) + break; + bigpeaks[nsalient] = bestpeak; + bestpeak->p_tmp = 1; + /* post("peak f=%f a=%f", bestpeak->p_freq, bestpeak->p_amp); */ + } + sumweight = 0; + for (i = 0; i < nsalient; i++) + { + t_peak *thispeak = bigpeaks[i]; + float weightindex = (48./LOG2) * + log(thispeak->p_freq/(2.*fperbin)); + float loudness = sqrt(thispeak->p_amp); + /* post("index %f, uncertainty %f", weightindex, pitchuncertainty); */ + for (j = 0; j < SUBHARMONICS; j++) + { + float subindex = weightindex - + (48./LOG2) * log(j + 1.); + int loindex = subindex - 0.5; + int hiindex = loindex+2; + if (hiindex < 0) + break; + if (hiindex >= npit) + continue; + if (loindex < 0) + loindex = 0; + for (k = loindex; k <= hiindex; k++) + weights[k] += loudness * 6. / (6. + j); + } + sumweight += loudness; + } + bestbin = -1; + bestweight = -1e20; + for (i = 0; i < npit; i++) + if (weights[i] > bestweight) + bestweight = weights[i], bestbin = i; + if (bestweight < sumweight * 0.4) + bestbin = -1; + + if (bestbin < 0) + { + freq = 0; + goto done; + } + if (bestbin > 0 && bestbin < npit-1) + { + int ibest = bestbin; + bestbin += (weights[ibest+1] - weights[ibest-1]) / + (weights[ibest+1] + weights[ibest] + weights[ibest-1]); + } + freq = 2*fperbin * exp((LOG2/48.)*bestbin); + for (sumamp = sumweight = sumfreq = 0, i = 0; i < nsalient; i++) + { + t_peak *thispeak = bigpeaks[i]; + float thisloudness = thispeak->p_amp; + float thisfreq = thispeak->p_freq; + float harmonic = thisfreq/freq; + float intpart = (int)(0.5 + harmonic); + float inharm = harmonic - intpart; +#if 0 + if (loud) + post("freq %f intpart %f inharm %f", freq, intpart, inharm); +#endif + if (intpart >= 1 && intpart <= 16 && + inharm < 0.015 * intpart && inharm > - (0.015 * intpart)) + { + float weight = thisloudness * intpart; + sumweight += weight; + sumfreq += weight*thisfreq/intpart; +#if 0 + if (loud) + post("weight %f freq %f", weight, thisfreq); +#endif + } + } + if (sumweight > 0) + freq = sumfreq / sumweight; +done: + if (!(freq >= 0 || freq <= 0)) + { + /* post("freq nan cancelled"); */ + freq = 0; + } + *freqp = freq; +} + +/*************** gather peak lists into sinusoidal tracks *************/ + +static void sigmund_peaktrack(int ninpeak, t_peak *inpeakv, + int noutpeak, t_peak *outpeakv, int loud) +{ + int incnt, outcnt; + for (outcnt = 0; outcnt < noutpeak; outcnt++) + outpeakv[outcnt].p_tmp = -1; + + /* first pass. Match each "in" peak with the closest previous + "out" peak, but no two to the same one. */ + for (incnt = 0; incnt < ninpeak; incnt++) + { + float besterror = 1e20; + int bestcnt = -1; + inpeakv[incnt].p_tmp = -1; + for (outcnt = 0; outcnt < noutpeak; outcnt++) + { + float thiserror = + inpeakv[incnt].p_freq - outpeakv[outcnt].p_freq; + if (thiserror < 0) + thiserror = -thiserror; + if (thiserror < besterror) + { + besterror = thiserror; + bestcnt = outcnt; + } + } + if (outpeakv[bestcnt].p_tmp < 0) + { + outpeakv[bestcnt] = inpeakv[incnt]; + inpeakv[incnt].p_tmp = 0; + outpeakv[bestcnt].p_tmp = 0; + } + } + /* second pass. Unmatched "in" peaks assigned to free "out" + peaks */ + for (incnt = 0; incnt < ninpeak; incnt++) + if (inpeakv[incnt].p_tmp < 0) + { + for (outcnt = 0; outcnt < noutpeak; outcnt++) + if (outpeakv[outcnt].p_tmp < 0) + { + outpeakv[outcnt] = inpeakv[incnt]; + inpeakv[incnt].p_tmp = 0; + outpeakv[outcnt].p_tmp = 1; + break; + } + } + for (outcnt = 0; outcnt < noutpeak; outcnt++) + if (outpeakv[outcnt].p_tmp == -1) + outpeakv[outcnt].p_amp = 0; +} + +/**************** parse continuous pitch into note starts ***************/ + +#define NHISTPOINT 100 + +typedef struct _histpoint +{ + float h_freq; + float h_power; +} t_histpoint; + +typedef struct _notefinder +{ + float n_age; + float n_hifreq; + float n_lofreq; + int n_peaked; + t_histpoint n_hist[NHISTPOINT]; + int n_histphase; +} t_notefinder; + + +static void notefinder_init(t_notefinder *x) +{ + int i; + x->n_peaked = x->n_age = 0; + x->n_hifreq = x->n_lofreq = 0; + x->n_histphase = 0; + for (i = 0; i < NHISTPOINT; i++) + x->n_hist[i].h_freq =x->n_hist[i].h_power = 0; +} + +static void notefinder_doit(t_notefinder *x, float freq, float power, + float *note, float vibrato, int stableperiod, float powerthresh, + float growththresh, int loud) +{ + /* calculate frequency ratio between allowable vibrato extremes + (equal to twice the vibrato deviation from center) */ + float vibmultiple = exp((2*LOG2/12) * vibrato); + int oldhistphase, i, k; + if (stableperiod > NHISTPOINT - 1) + stableperiod = NHISTPOINT - 1; + else if (stableperiod < 1) + stableperiod = 1; + if (++x->n_histphase == NHISTPOINT) + x->n_histphase = 0; + x->n_hist[x->n_histphase].h_freq = freq; + 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", + stableperiod, (int)x->n_age ,vibmultiple, powerthresh, x->n_hifreq); + post("histfreq %f %f %f %f", + x->n_hist[x->n_histphase].h_freq, + x->n_hist[(x->n_histphase+NHISTPOINT-1)%NHISTPOINT].h_freq, + x->n_hist[(x->n_histphase+NHISTPOINT-2)%NHISTPOINT].h_freq, + x->n_hist[(x->n_histphase+NHISTPOINT-3)%NHISTPOINT].h_freq); + post("power %f %f %f %f", + x->n_hist[x->n_histphase].h_power, + x->n_hist[(x->n_histphase+NHISTPOINT-1)%NHISTPOINT].h_power, + x->n_hist[(x->n_histphase+NHISTPOINT-2)%NHISTPOINT].h_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", 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. */ + if (x->n_hifreq <= 0 && x->n_age > stableperiod) + { + float maxpow = 0, freqatmaxpow = 0, + localhifreq = -1e20, locallofreq = 1e20; + int startphase = x->n_histphase - stableperiod + 1; + if (startphase < 0) + startphase += NHISTPOINT; + for (i = 0, k = startphase; i < stableperiod; i++) + { + if (x->n_hist[k].h_freq <= 0) + break; + if (x->n_hist[k].h_power > maxpow) + maxpow = x->n_hist[k].h_power, + freqatmaxpow = x->n_hist[k].h_freq; + if (x->n_hist[k].h_freq > localhifreq) + localhifreq = x->n_hist[k].h_freq; + if (x->n_hist[k].h_freq < locallofreq) + locallofreq = x->n_hist[k].h_freq; + if (localhifreq > locallofreq * vibmultiple) + break; + if (maxpow > power * growththresh && + maxpow > x->n_hist[startphase].h_power * growththresh && + localhifreq < vibmultiple * locallofreq + && freqatmaxpow > 0 && maxpow > powerthresh) + { + x->n_hifreq = x->n_lofreq = *note = freqatmaxpow; + x->n_age = 0; + x->n_peaked = 0; + /* post("got short note"); */ + return; + } + if (++k >= NHISTPOINT) + k = 0; + } + + } + if (x->n_hifreq > 0) + { + /* test if we're within "vibrato" range, and if so update range */ + if (freq * vibmultiple >= x->n_hifreq && + x->n_lofreq * vibmultiple >= freq) + { + if (freq > x->n_hifreq) + x->n_hifreq = freq; + if (freq < x->n_lofreq) + x->n_lofreq = freq; + } + else if (x->n_hifreq > 0 && x->n_age > stableperiod) + { + /* if we've been out of range at least 1/2 the + last "stableperiod+1" analyses, clear the note */ + int nbad = 0; + for (i = 0, k = x->n_histphase; i < stableperiod + 1; i++) + { + if (--k < 0) + k = NHISTPOINT - 1; + if (x->n_hist[k].h_freq * vibmultiple <= x->n_hifreq || + x->n_lofreq * vibmultiple <= x->n_hist[k].h_freq) + nbad++; + } + if (2 * nbad >= stableperiod + 1) + { + x->n_hifreq = x->n_lofreq = 0; + x->n_age = 0; + } + } + } + + oldhistphase = x->n_histphase - stableperiod; + if (oldhistphase < 0) + oldhistphase += NHISTPOINT; + + /* look for envelope attacks */ + + if (x->n_hifreq > 0 && x->n_peaked) + { + if (freq > 0 && power > powerthresh && + power > x->n_hist[oldhistphase].h_power * + exp((LOG10*0.1)*growththresh)) + { + /* clear it and fall through for new stable-note test */ + x->n_peaked = 0; + x->n_hifreq = x->n_lofreq = 0; + x->n_age = 0; + } + } + else if (!x->n_peaked) + { + if (x->n_hist[oldhistphase].h_power > powerthresh && + x->n_hist[oldhistphase].h_power > power) + x->n_peaked = 1; + } + + /* test for a new note using a stability criterion. */ + + if (freq >= 0 && + (x->n_hifreq <= 0 || freq > x->n_hifreq || freq < x->n_lofreq)) + { + float testfhi = freq, testflo = freq, + maxpow = x->n_hist[x->n_histphase].h_freq; + for (i = 0, k = x->n_histphase; i < stableperiod-1; i++) + { + if (--k < 0) + k = NHISTPOINT - 1; + if (x->n_hist[k].h_freq > testfhi) + testfhi = x->n_hist[k].h_freq; + if (x->n_hist[k].h_freq < testflo) + testflo = x->n_hist[k].h_freq; + if (x->n_hist[k].h_power > maxpow) + maxpow = x->n_hist[k].h_power; + } +#if 0 + if (loud) + post("freq %.2g testfhi %.2g testflo %.2g maxpow %.2g", + freq, testfhi, testflo, maxpow); +#endif + if (testflo > 0 && testfhi <= vibmultiple * testflo + && maxpow > powerthresh) + { + /* report new note */ + float sumf = 0, sumw = 0, thisw; + for (i = 0, k = x->n_histphase; i < stableperiod; i++) + { + thisw = x->n_hist[k].h_power; + sumw += thisw; + sumf += thisw*x->n_hist[k].h_freq; + if (--k < 0) + k = NHISTPOINT - 1; + } + x->n_hifreq = x->n_lofreq = *note = (sumw > 0 ? sumf/sumw : 0); +#if 0 + /* debugging printout */ + for (i = 0; i < stableperiod; i++) + { + int k3 = x->n_histphase - i; + if (k3 < 0) + k3 += NHISTPOINT; + startpost("%5.1f ", sigmund_ftom(x->n_hist[k3].h_freq)); + } + post(""); +#endif + x->n_age = 0; + x->n_peaked = 0; + return; + } + } + *note = 0; + return; +} + +/**************** 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)) + +#define NHIST 100 + +#define MODE_STREAM 1 +#define MODE_BLOCK 2 /* unimplemented */ +#define MODE_TABLE 3 + +#define NPOINTS_DEF 1024 +#define NPOINTS_MIN 128 + +#define HOP_DEF 512 +#define NPEAK_DEF 20 + +#define VIBRATO_DEF 1 +#define STABLETIME_DEF 50 +#define MINPOWER_DEF 50 +#define GROWTH_DEF 7 + +#define OUT_PITCH 0 +#define OUT_ENV 1 +#define OUT_NOTE 2 +#define OUT_PEAKS 3 +#define OUT_TRACKS 4 +#define OUT_SMSPITCH 5 +#define OUT_SMSNONPITCH 6 + +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_clock *x_clock; + float x_f; /* for main signal inlet */ +#endif /* PD */ +#ifdef MSP + t_pxobject x_obj; + void *obex; + void *x_clock; + t_sample *x_inbuf2; /* extra input buffer to eat clock/DSP jitter */ +#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 */ + int x_npeak; /* number of peaks to find */ + int x_loud; /* debug level */ + t_sample *x_inbuf; /* input buffer */ + int x_infill; /* number of points filled */ + int x_countdown; /* countdown to start filling buffer */ + int x_hop; /* samples between analyses */ + float x_maxfreq; /* highest-frequency peak to report */ + float x_vibrato; /* vibrato depth in half tones */ + 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; /* three parameters for temporary use */ + float x_param2; + float x_param3; + 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_preinit(t_sigmund *x) +{ + x->x_npts = NPOINTS_DEF; + x->x_param1 = 0; + x->x_param2 = 0.6; + x->x_param3 = 0; + x->x_hop = HOP_DEF; + x->x_mode = MODE_STREAM; + x->x_npeak = NPEAK_DEF; + x->x_vibrato = VIBRATO_DEF; + x->x_stabletime = STABLETIME_DEF; + x->x_growth = GROWTH_DEF; + x->x_minpower = MINPOWER_DEF; + x->x_maxfreq = 1000000; + x->x_loud = 0; + x->x_sr = 1; + x->x_nvarout = 0; + x->x_varoutv = (t_varout *)getbytes(0); + x->x_trackv = 0; + x->x_ntrack = 0; + x->x_dopitch = x->x_donote = x->x_dotracks = 0; + x->x_inbuf = 0; +#ifdef MSP + x->x_inbuf2 = 0; +#endif +} + +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); +#ifdef MSP + x->x_inbuf2 = (t_sample *)t_resizebytes(x->x_inbuf2, + sizeof(*x->x_inbuf2) * nwas, sizeof(*x->x_inbuf2) * npts); +#endif + } + else + { + x->x_inbuf = (t_sample *)getbytes(sizeof(*x->x_inbuf) * npts); + memset((char *)(x->x_inbuf), 0, sizeof(*x->x_inbuf) * npts); +#ifdef MSP + x->x_inbuf2 = (t_sample *)getbytes(sizeof(*x->x_inbuf2) * npts); + memset((char *)(x->x_inbuf2), 0, sizeof(*x->x_inbuf2) * npts); +#endif + } + } + 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, ¬e, x->x_vibrato, + 1 + 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 t_int *sigmund_perform(t_int *w); +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); + x->x_loud = 1; +} + +static void sigmund_free(t_sigmund *x) +{ + if (x->x_inbuf) + { + freebytes(x->x_inbuf, x->x_npts * sizeof(*x->x_inbuf)); +#ifdef MSP + freebytes(x->x_inbuf2, x->x_npts * sizeof(*x->x_inbuf2)); +#endif + } + 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_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; + } + if (x->x_loud) + x->x_loud--; + } +} + +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_new(t_symbol *s, int argc, t_atom *argv) +{ + t_sigmund *x = (t_sigmund *)pd_new(sigmund_class); + sigmund_preinit(x); + + while (argc > 0) + { + t_symbol *firstarg = atom_getsymbolarg(0, argc, argv); + if (!strcmp(firstarg->s_name, "-t")) + { + x->x_mode = MODE_TABLE; + argc--, argv++; + } + else if (!strcmp(firstarg->s_name, "-s")) + { + x->x_mode = MODE_STREAM; + argc--, argv++; + } +#if 0 + else if (!strcmp(firstarg->s_name, "-b")) + { + x->x_mode = MODE_BLOCK; + argc--, argv++; + } +#endif + else if (!strcmp(firstarg->s_name, "-npts") && argc > 1) + { + x->x_npts = atom_getfloatarg(1, argc, argv); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-hop") && argc > 1) + { + sigmund_hop(x, atom_getfloatarg(1, argc, argv)); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-npeak") && argc > 1) + { + sigmund_npeak(x, atom_getfloatarg(1, argc, argv)); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-maxfreq") && argc > 1) + { + sigmund_maxfreq(x, atom_getfloatarg(1, argc, argv)); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-vibrato") && argc > 1) + { + sigmund_vibrato(x, atom_getfloatarg(1, argc, argv)); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-stabletime") && argc > 1) + { + sigmund_stabletime(x, atom_getfloatarg(1, argc, argv)); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-growth") && argc > 1) + { + sigmund_growth(x, atom_getfloatarg(1, argc, argv)); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "-minpower") && argc > 1) + { + sigmund_minpower(x, atom_getfloatarg(1, argc, argv)); + argc -= 2; argv += 2; + } + else if (!strcmp(firstarg->s_name, "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_outlet = + outlet_new(&x->x_obj, &s_float); + x->x_varoutv[x->x_nvarout].v_what = OUT_PITCH; + x->x_nvarout = n2; + x->x_dopitch = 1; + argc--, argv++; + } + else if (!strcmp(firstarg->s_name, "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_outlet = + outlet_new(&x->x_obj, &s_float); + x->x_varoutv[x->x_nvarout].v_what = OUT_ENV; + x->x_nvarout = n2; + argc--, argv++; + } + else if (!strcmp(firstarg->s_name, "note") + || !strcmp(firstarg->s_name, "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_outlet = + outlet_new(&x->x_obj, &s_float); + x->x_varoutv[x->x_nvarout].v_what = OUT_NOTE; + x->x_nvarout = n2; + x->x_dopitch = x->x_donote = 1; + argc--, argv++; + } + else if (!strcmp(firstarg->s_name, "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_outlet = + outlet_new(&x->x_obj, &s_list); + x->x_varoutv[x->x_nvarout].v_what = OUT_PEAKS; + x->x_nvarout = n2; + argc--, argv++; + } + else if (!strcmp(firstarg->s_name, "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_outlet = + outlet_new(&x->x_obj, &s_list); + x->x_varoutv[x->x_nvarout].v_what = OUT_TRACKS; + x->x_nvarout = n2; + x->x_dotracks = 1; + argc--, argv++; + } + else + { + pd_error(x, "sigmund: %s: unknown flag or argument missing", + firstarg->s_name); + argc--, argv++; + } + } + if (!x->x_nvarout) + { + x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv, + 0, 2*sizeof(t_varout)); + x->x_varoutv[0].v_outlet = outlet_new(&x->x_obj, &s_float); + x->x_varoutv[0].v_what = OUT_PITCH; + x->x_varoutv[1].v_outlet = outlet_new(&x->x_obj, &s_float); + x->x_varoutv[1].v_what = OUT_ENV; + x->x_nvarout = 2; + x->x_dopitch = 1; + } + 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->x_obj.ob_pd, (t_method)sigmund_tick); + + x->x_infill = 0; + x->x_countdown = 0; + sigmund_npts(x, x->x_npts); + notefinder_init(&x->x_notefinder); + sigmund_clear(x); + return (x); +} + +static void sigmund_list(t_sigmund *x, t_symbol *s, int argc, t_atom *argv) +{ + t_symbol *syminput = atom_getsymbolarg(0, argc, argv); + int npts = atom_getintarg(1, argc, argv); + int onset = atom_getintarg(2, argc, argv); + float srate = atom_getfloatarg(3, argc, argv); + int loud = atom_getfloatarg(4, argc, argv); + int arraysize, totstorage, nfound, i; + t_garray *a; + float *arraypoints, pit; + t_word *wordarray = 0; + if (argc < 5) + { + post( + "sigmund: array-name, npts, array-onset, samplerate, loud"); + return; + } + if (npts < 64 || npts != (1 << ilog2(npts))) + { + error("sigmund: bad npoints"); + return; + } + if (onset < 0) + { + error("sigmund: negative onset"); + return; + } + arraypoints = alloca(sizeof(float)*npts); + if (!(a = (t_garray *)pd_findbyclass(syminput, garray_class)) || + !garray_getfloatwords(a, &arraysize, &wordarray) || + arraysize < onset + npts) + { + error("%s: array missing or too small", syminput->s_name); + return; + } + if (arraysize < npts) + { + error("sigmund~: too few points in array"); + return; + } + for (i = 0; i < npts; i++) + arraypoints[i] = wordarray[i+onset].w_float; + sigmund_doit(x, npts, arraypoints, loud, srate); +} + +static void sigmund_clear(t_sigmund *x) +{ + if (x->x_trackv) + memset(x->x_trackv, 0, x->x_ntrack * sizeof(*x->x_trackv)); + x->x_infill = x->x_countdown = 0; +} + + /* these are for testing; their meanings vary... */ +static void sigmund_param1(t_sigmund *x, t_floatarg f) +{ + x->x_param1 = f; +} + +static void sigmund_param2(t_sigmund *x, t_floatarg f) +{ + x->x_param2 = f; +} + +static void sigmund_param3(t_sigmund *x, t_floatarg f) +{ + x->x_param3 = f; +} + +static void sigmund_printnext(t_sigmund *x, t_float f) +{ + x->x_loud = f; +} + +void sigmund_tilde_setup(void) +{ + sigmund_class = class_new(gensym("sigmund~"), (t_newmethod)sigmund_new, + (t_method)sigmund_free, sizeof(t_sigmund), 0, A_GIMME, 0); + class_addlist(sigmund_class, sigmund_list); + class_addmethod(sigmund_class, (t_method)sigmund_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(sigmund_class, t_sigmund, x_f); + class_addmethod(sigmund_class, (t_method)sigmund_param1, + gensym("param1"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_param2, + gensym("param2"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_param3, + gensym("param3"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_npts, + gensym("npts"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_hop, + gensym("hop"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_maxfreq, + gensym("maxfreq"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_npeak, + gensym("npeak"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_vibrato, + gensym("vibrato"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_stabletime, + gensym("stabletime"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_growth, + gensym("growth"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_minpower, + gensym("minpower"), A_FLOAT, 0); + class_addmethod(sigmund_class, (t_method)sigmund_print, + gensym("print"), 0); + class_addmethod(sigmund_class, (t_method)sigmund_printnext, + gensym("printnext"), A_FLOAT, 0); + post("sigmund~ version 0.07"); +} + +#endif /* PD */ + +/************************ Max/MSP glue **********************************/ + +/* -------------------------- MSP glue ------------------------- */ +#ifdef MSP +static void *sigmund_class; + +/* Max/MSP has laxer sync between DSP and "tick"s - so in the perf routine we +keep a circular buffer that is rectified into inbuf only when the tick comes. */ + +static void sigmund_tick(t_sigmund *x) +{ + int i, j, npts = x->x_npts; + if (!x->x_inbuf) + return; + for (i = x->x_infill, j = 0; i < npts; i++, j++) + x->x_inbuf[j] = x->x_inbuf2[i]; + for (i = 0; j < npts; i++, j++) + x->x_inbuf[j] = x->x_inbuf2[i]; + sigmund_doit(x, x->x_npts, x->x_inbuf, x->x_loud, x->x_sr); + 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]), j; + int infill = x->x_infill; + float *fp = x->x_inbuf2 + infill; + + if (x->x_obj.z_disabled) /* return if in muted MSP subpatch -Rd */ + return (w+4); + + if (infill < 0 || infill >= x->x_npts) + infill = 0; + /* for some reason this sometimes happens: */ + if (!x->x_inbuf2) + return (w+4); + for (j = 0; j < n; j++) + { + *fp++ = *in++; + if (++infill == x->x_npts) + infill = 0, fp = x->x_inbuf2; + } + x->x_infill = infill; + if (x->x_countdown <= 0) + { + x->x_countdown = x->x_hop; + clock_delay(x->x_clock, 0); + } + x->x_countdown -= n; + return (w+4); +} + +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~ version 0.07"); + return (0); +} + + +#endif /* MSP */ + + diff --git a/extra/stdout/stdout.pd_linux b/extra/stdout/stdout.pd_linux deleted file mode 100755 index 73254ff1a5793ff52e60d61bd0df11efc7159cf8..0000000000000000000000000000000000000000 Binary files a/extra/stdout/stdout.pd_linux and /dev/null differ diff --git a/src/ todo b/src/ todo new file mode 100644 index 0000000000000000000000000000000000000000..829257e899ebdff1ec9339ca45b85de902a42f2a --- /dev/null +++ b/src/ todo @@ -0,0 +1,16 @@ +fix going outside boundaries +fix drawing when using const or drawing at the threshold + +struct _garray +{ + t_gobj x_gobj; + t_scalar *x_scalar; /* scalar "containing" the array */ + t_glist *x_glist; /* containing glist */ + t_symbol *x_name; /* unexpanded name (possibly with leading '$') */ + t_symbol *x_realname; /* expanded name (symbol we're bound to) */ + char x_usedindsp; /* true if some DSP routine is using this */ + char x_saveit; /* true if we should save this with parent */ + char x_listviewing; /* true if list view window is open */ + char x_hidename; /* don't print name above graph */ + t_symbol *x_send; /* send_changed hook */ +}; diff --git a/src/d_delay.c.orig b/src/d_delay.c.orig new file mode 100644 index 0000000000000000000000000000000000000000..3571e89a6e79994e402bfdc89d07c4a7519e3f9a --- /dev/null +++ b/src/d_delay.c.orig @@ -0,0 +1,325 @@ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* send~, delread~, throw~, catch~ */ + +#include "m_pd.h" +extern int ugen_getsortno(void); + +#define DEFDELVS 64 /* LATER get this from canvas at DSP time */ +static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */ + +/* ----------------------------- delwrite~ ----------------------------- */ +static t_class *sigdelwrite_class; + +typedef struct delwritectl +{ + int c_n; + t_sample *c_vec; + int c_phase; +} t_delwritectl; + +typedef struct _sigdelwrite +{ + t_object x_obj; + t_symbol *x_sym; + t_delwritectl x_cspace; + int x_sortno; /* DSP sort number at which this was last put on chain */ + int x_rsortno; /* DSP sort # for first delread or write in chain */ + int x_vecsize; /* vector size for delread~ to use */ + t_float x_f; +} t_sigdelwrite; + +#define XTRASAMPS 4 +#define SAMPBLK 4 + + /* routine to check that all delwrites/delreads/vds have same vecsize */ +static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize) +{ + if (x->x_rsortno != ugen_getsortno()) + { + x->x_vecsize = vecsize; + x->x_rsortno = ugen_getsortno(); + } + /* + LATER this should really check sample rate and blocking, once that is + supported. Probably we don't actually care about vecsize. + For now just suppress this check. */ +#if 0 + else if (vecsize != x->x_vecsize) + pd_error(x, "delread/delwrite/vd vector size mismatch"); +#endif +} + +#include <stdio.h> + +static void *sigdelwrite_new(t_symbol *s, t_floatarg msec) +{ + int nsamps; + t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class); + if (!*s->s_name) s = gensym("delwrite~"); + pd_bind(&x->x_obj.ob_pd, s); + x->x_sym = s; + if (msec == 0) msec = 1000; + nsamps = msec * sys_getsr() * (t_float)(0.001f); + if (nsamps < 1) nsamps = 1; + nsamps += ((- nsamps) & (SAMPBLK - 1)); + nsamps += DEFDELVS; + x->x_cspace.c_n = nsamps; + x->x_cspace.c_vec = + (t_sample *)getbytes((nsamps + XTRASAMPS) * sizeof(t_sample)); + x->x_cspace.c_phase = XTRASAMPS; + x->x_sortno = 0; + x->x_vecsize = 0; + x->x_f = 0; + return (x); +} + +static t_int *sigdelwrite_perform(t_int *w) +{ + t_sample *in = (t_sample *)(w[1]); + t_delwritectl *c = (t_delwritectl *)(w[2]); + int n = (int)(w[3]); + int phase = c->c_phase, nsamps = c->c_n; + t_sample *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS); + phase += n; + + while (n--) + { + t_sample f = *in++; + if (PD_BIGORSMALL(f)) + f = 0; + *bp++ = f; + if (bp == ep) + { + vp[0] = ep[-4]; + vp[1] = ep[-3]; + vp[2] = ep[-2]; + vp[3] = ep[-1]; + bp = vp + XTRASAMPS; + phase -= nsamps; + } + } + bp = vp + c->c_phase; + + c->c_phase = phase; + return (w+4); +} + +static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp) +{ + dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n); + x->x_sortno = ugen_getsortno(); + sigdelwrite_checkvecsize(x, sp[0]->s_n); +} + +static void sigdelwrite_free(t_sigdelwrite *x) +{ + pd_unbind(&x->x_obj.ob_pd, x->x_sym); + freebytes(x->x_cspace.c_vec, + (x->x_cspace.c_n + XTRASAMPS) * sizeof(t_sample)); +} + +static void sigdelwrite_setup(void) +{ + sigdelwrite_class = class_new(gensym("delwrite~"), + (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free, + sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f); + class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp, + gensym("dsp"), 0); +} + +/* ----------------------------- delread~ ----------------------------- */ +static t_class *sigdelread_class; + +typedef struct _sigdelread +{ + t_object x_obj; + t_symbol *x_sym; + t_float x_deltime; /* delay in msec */ + int x_delsamps; /* delay in samples */ + t_float x_sr; /* samples per msec */ + t_float x_n; /* vector size */ + int x_zerodel; /* 0 or vecsize depending on read/write order */ +} t_sigdelread; + +static void sigdelread_float(t_sigdelread *x, t_float f); + +static void *sigdelread_new(t_symbol *s, t_floatarg f) +{ + t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class); + x->x_sym = s; + x->x_sr = 1; + x->x_n = 1; + x->x_zerodel = 0; + sigdelread_float(x, f); + outlet_new(&x->x_obj, &s_signal); + return (x); +} + +static void sigdelread_float(t_sigdelread *x, t_float f) +{ + int samps; + t_sigdelwrite *delwriter = + (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); + x->x_deltime = f; + if (delwriter) + { + int delsize = delwriter->x_cspace.c_n; + x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime) + + x->x_n - x->x_zerodel; + if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n; + else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS) + x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS; + } +} + +static t_int *sigdelread_perform(t_int *w) +{ + t_sample *out = (t_sample *)(w[1]); + t_delwritectl *c = (t_delwritectl *)(w[2]); + int delsamps = *(int *)(w[3]); + int n = (int)(w[4]); + int phase = c->c_phase - delsamps, nsamps = c->c_n; + t_sample *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS); + if (phase < 0) phase += nsamps; + bp = vp + phase; + + while (n--) + { + *out++ = *bp++; + if (bp == ep) bp -= nsamps; + } + return (w+5); +} + +static void sigdelread_dsp(t_sigdelread *x, t_signal **sp) +{ + t_sigdelwrite *delwriter = + (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); + x->x_sr = sp[0]->s_sr * 0.001; + x->x_n = sp[0]->s_n; + if (delwriter) + { + sigdelwrite_checkvecsize(delwriter, sp[0]->s_n); + x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? + 0 : delwriter->x_vecsize); + sigdelread_float(x, x->x_deltime); + dsp_add(sigdelread_perform, 4, + sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n); + } + else if (*x->x_sym->s_name) + error("delread~: %s: no such delwrite~",x->x_sym->s_name); +} + +static void sigdelread_setup(void) +{ + sigdelread_class = class_new(gensym("delread~"), + (t_newmethod)sigdelread_new, 0, + sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0); + class_addmethod(sigdelread_class, (t_method)sigdelread_dsp, + gensym("dsp"), 0); + class_addfloat(sigdelread_class, (t_method)sigdelread_float); +} + + +/* ----------------------------- vd~ ----------------------------- */ +static t_class *sigvd_class; + +typedef struct _sigvd +{ + t_object x_obj; + t_symbol *x_sym; + t_float x_sr; /* samples per msec */ + int x_zerodel; /* 0 or vecsize depending on read/write order */ + t_float x_f; +} t_sigvd; + +static void *sigvd_new(t_symbol *s) +{ + t_sigvd *x = (t_sigvd *)pd_new(sigvd_class); + if (!*s->s_name) s = gensym("vd~"); + x->x_sym = s; + x->x_sr = 1; + x->x_zerodel = 0; + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); +} + +static t_int *sigvd_perform(t_int *w) +{ + t_sample *in = (t_sample *)(w[1]); + t_sample *out = (t_sample *)(w[2]); + t_delwritectl *ctl = (t_delwritectl *)(w[3]); + t_sigvd *x = (t_sigvd *)(w[4]); + int n = (int)(w[5]); + + int nsamps = ctl->c_n; + t_sample limit = nsamps - n - 1; + t_sample fn = n-1; + t_sample *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase; + t_sample zerodel = x->x_zerodel; + while (n--) + { + t_sample delsamps = x->x_sr * *in++ - zerodel, frac; + int idelsamps; + t_sample a, b, c, d, cminusb; + if (delsamps < 1.00001f) delsamps = 1.00001f; + if (delsamps > limit) delsamps = limit; + delsamps += fn; + fn = fn - 1.0f; + idelsamps = delsamps; + frac = delsamps - (t_sample)idelsamps; + bp = wp - idelsamps; + if (bp < vp + 4) bp += nsamps; + d = bp[-3]; + c = bp[-2]; + b = bp[-1]; + a = bp[0]; + cminusb = c-b; + *out++ = b + frac * ( + cminusb - 0.1666667f * (1.-frac) * ( + (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b) + ) + ); + } + return (w+6); +} + +static void sigvd_dsp(t_sigvd *x, t_signal **sp) +{ + t_sigdelwrite *delwriter = + (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); + x->x_sr = sp[0]->s_sr * 0.001; + if (delwriter) + { + sigdelwrite_checkvecsize(delwriter, sp[0]->s_n); + x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? + 0 : delwriter->x_vecsize); + dsp_add(sigvd_perform, 5, + sp[0]->s_vec, sp[1]->s_vec, + &delwriter->x_cspace, x, sp[0]->s_n); + } + else error("vd~: %s: no such delwrite~",x->x_sym->s_name); +} + +static void sigvd_setup(void) +{ + sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0, + sizeof(t_sigvd), 0, A_DEFSYM, 0); + class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f); +} + +/* ----------------------- global setup routine ---------------- */ + +void d_delay_setup(void) +{ + sigdelwrite_setup(); + sigdelread_setup(); + sigvd_setup(); +} + diff --git a/src/g_canvas.c b/src/g_canvas.c index c8b5aa79836a8a7f66aa730399260d36b11cd481..0fee01389f44f284daab0a0bc7d58b65175c0c01 100644 --- a/src/g_canvas.c +++ b/src/g_canvas.c @@ -709,40 +709,55 @@ void canvas_map(t_canvas *x, t_floatarg f) t_gobj *y; if (flag) { - //fprintf(stderr,"canvas_map 1\n"); - //if (!glist_isvisible(x)) - //{ - //fprintf(stderr,"canvas_map 1 isvisible\n"); - t_selection *sel; - if (!x->gl_havewindow) + if (!glist_isvisible(x)) { - bug("canvas_map"); - canvas_vis(x, 1); - } - - if (!x->gl_list) { - //if there are no objects on the canvas - canvas_create_editor(x); - } - else for (y = x->gl_list; y; y = y->g_next) { - gobj_vis(y, x, 1); + t_selection *sel; + if (!x->gl_havewindow) + { + bug("canvas_map"); + canvas_vis(x, 1); + } + else if (x->gl_mapped == 0) + canvas_vis(x, 1); + + /* if parent has editor enabled and we're a sub-patch, + (but not an abstraction) match its edit mode to that + of its parent patch. */ + /*t_glist *parentx; + if (!canvas_isabstraction(x)) { + if (x->gl_owner) { + parentx = x->gl_owner; + while (parentx->gl_owner) + parentx = parentx->gl_owner; + if (parentx->gl_edit) + canvas_editmode(x, 1); + else if (x->gl_edit) + canvas_editmode(x, 0); + } + }*/ + /* for parent windows, let's make sure the cursor is updated + as soon as the window is open (if in edit mode) */ + //else if (x->gl_edit) { + //canvas_setcursor(x, CURSOR_EDITMODE_NOTHING); + //} + + for (y = x->gl_list; y; y = y->g_next) + gobj_vis(y, x, 1); if (x->gl_editor && x->gl_editor->e_selection) - for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) - gobj_select(sel->sel_what, x, 1); - } - x->gl_mapped = 1; - canvas_drawlines(x); - if (x->gl_isgraph && x->gl_goprect) - canvas_drawredrect(x, 1); - sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x); - //} + for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) + gobj_select(sel->sel_what, x, 1); + x->gl_mapped = 1; + canvas_drawlines(x); + if (x->gl_isgraph && x->gl_goprect) + canvas_drawredrect(x, 1); + sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x); + } } else { - //fprintf(stderr,"canvas_map 0\n"); if (glist_isvisible(x)) { - /* just clear out the whole canvas */ + /* just clear out the whole canvas */ sys_vgui(".x%lx.c dtag all selected\n", x); sys_vgui(".x%lx.c delete all\n", x); x->gl_mapped = 0; @@ -816,9 +831,13 @@ void canvas_free(t_canvas *x) { t_gobj *y; int dspstate = canvas_suspend_dsp(); - + // jsarlo if (x->gl_magic_glass) magicGlass_free(x->gl_magic_glass); + // end jsarlo + + //delete clock for gl_destroy + //if (x->gl_destroy) clock_free(x->gl_destroy); canvas_noundo(x); if (canvas_editing == x) diff --git a/src/g_canvas.c.orig b/src/g_canvas.c.orig new file mode 100644 index 0000000000000000000000000000000000000000..2f032a12d6ef37c4983669f6072f170bfd3dbfeb --- /dev/null +++ b/src/g_canvas.c.orig @@ -0,0 +1,1819 @@ +/* Copyright (c) 1997-2001 Miller Puckette and others. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* this file defines the "glist" class, also known as "canvas" (the two used +to be different but are now unified except for some fossilized names.) */ + +#include <stdlib.h> +#include <stdio.h> +#include "m_pd.h" +#include "m_imp.h" +#include "s_stuff.h" +#include "g_canvas.h" +#include <string.h> +#include "g_all_guis.h" +#include "g_magicglass.h" + +// jsarlo +typedef struct _magicGlass +{ + t_object x_obj; + t_object *x_connectedObj; + int x_connectedOutno; + int x_visible; + char x_string[4096]; + char x_old_string[4096]; + int x_x; + int x_y; + int x_c; + float x_sigF; + int x_dspOn; + int x_viewOn; + float x_maxSample; + int x_sampleCount; + t_clock *x_clearClock; + t_clock *x_flashClock; + unsigned int x_maxSize; + unsigned int x_issignal; +}; +// end jsarlo + + /* LATER consider adding font size to this struct (see glist_getfont()) */ +struct _canvasenvironment +{ + t_symbol *ce_dir; /* directory patch lives in */ + int ce_argc; /* number of "$" arguments */ + t_atom *ce_argv; /* array of "$" arguments */ + int ce_dollarzero; /* value of "$0" */ + t_namelist *ce_path; /* search path */ +}; + +#define GLIST_DEFCANVASWIDTH 450 +#define GLIST_DEFCANVASHEIGHT 300 + +#ifdef __APPLE__ +#define GLIST_DEFCANVASYLOC 22 +#else +#define GLIST_DEFCANVASYLOC 0 +#endif + +/* ---------------------- variables --------------------------- */ + +extern t_pd *newest; +t_class *canvas_class; +int canvas_dspstate; /* whether DSP is on or off */ +t_canvas *canvas_editing; /* last canvas to start text edting */ +t_canvas *canvas_whichfind; /* last canvas we did a find in */ +t_canvas *canvas_list; /* list of all root canvases */ + +/* ------------------ forward function declarations --------------- */ +static void canvas_start_dsp(void); +static void canvas_stop_dsp(void); +static void canvas_drawlines(t_canvas *x); +static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2); +void canvas_reflecttitle(t_canvas *x); +static void canvas_addtolist(t_canvas *x); +static void canvas_takeofflist(t_canvas *x); +static void canvas_pop(t_canvas *x, t_floatarg fvis); + +/* --------- functions to handle the canvas environment ----------- */ + +static t_symbol *canvas_newfilename = &s_; +static t_symbol *canvas_newdirectory = &s_; +static int canvas_newargc; +static t_atom *canvas_newargv; + +static void glist_doupdatewindowlist(t_glist *gl, char *sbuf) +{ + t_gobj *g; + if (glist_amreloadingabstractions) /* not if we're in a reload */ + return; + if (!gl->gl_owner) + { + /* this is a canvas; if we have a window, put on "windows" list */ + t_canvas *canvas = (t_canvas *)gl; + if (canvas->gl_havewindow) + { + if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024) + { + char tbuf[1024]; + sprintf(tbuf, "{{%s} .x%lx} ", gl->gl_name->s_name, + (t_int)canvas); + strcat(sbuf, tbuf); + } + } + } + for (g = gl->gl_list; g; g = g->g_next) + { + if (pd_class(&g->g_pd) == canvas_class) + glist_doupdatewindowlist((t_glist *)g, sbuf); + } + return; +} + + /* maintain the list of visible toplevels for the GUI's "windows" menu */ +void canvas_updatewindowlist( void) +{ + t_canvas *x; + char sbuf[1024]; + strcpy(sbuf, "set menu_windowlist {"); + /* find all root canvases */ + for (x = canvas_list; x; x = x->gl_next) + glist_doupdatewindowlist(x, sbuf); + /* next line updates the window menu state before -postcommand tries it */ + strcat(sbuf, "}\npdtk_fixwindowmenu\n"); + sys_gui(sbuf); +} + + /* add a glist the list of "root" canvases (toplevels without parents.) */ +static void canvas_addtolist(t_canvas *x) +{ + x->gl_next = canvas_list; + canvas_list = x; +} + +static void canvas_takeofflist(t_canvas *x) +{ + /* take it off the window list */ + if (x == canvas_list) canvas_list = x->gl_next; + else + { + t_canvas *z; + for (z = canvas_list; z->gl_next != x; z = z->gl_next) + ; + z->gl_next = x->gl_next; + } +} + + +void canvas_setargs(int argc, t_atom *argv) +{ + /* if there's an old one lying around free it here. This + happens if an abstraction is loaded but never gets as far + as calling canvas_new(). */ + if (canvas_newargv) + freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom)); + canvas_newargc = argc; + canvas_newargv = copybytes(argv, argc * sizeof(t_atom)); +} + +void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym) +{ + canvas_newfilename = filesym; + canvas_newdirectory = dirsym; +} + +t_canvas *canvas_getcurrent(void) +{ + return ((t_canvas *)pd_findbyclass(&s__X, canvas_class)); +} + +void canvas_setcurrent(t_canvas *x) +{ + pd_pushsym(&x->gl_pd); +} + +void canvas_unsetcurrent(t_canvas *x) +{ + pd_popsym(&x->gl_pd); +} + +t_canvasenvironment *canvas_getenv(t_canvas *x) +{ + if (!x) bug("canvas_getenv"); + while (!x->gl_env) + if (!(x = x->gl_owner)) + bug("t_canvasenvironment"); + return (x->gl_env); +} + +int canvas_getdollarzero( void) +{ + t_canvas *x = canvas_getcurrent(); + t_canvasenvironment *env = (x ? canvas_getenv(x) : 0); + if (env) + return (env->ce_dollarzero); + else return (0); +} + +void canvas_getargs(int *argcp, t_atom **argvp) +{ + t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); + *argcp = e->ce_argc; + *argvp = e->ce_argv; +} + +t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) +{ + t_symbol *ret; + char *name = s->s_name; + if (strchr(name, '$')) + { + t_canvasenvironment *env = canvas_getenv(x); + canvas_setcurrent(x); + ret = binbuf_realizedollsym(s, env->ce_argc, env->ce_argv, 1); + canvas_unsetcurrent(x); + } + else ret = s; + return (ret); +} + +t_symbol *canvas_getcurrentdir(void) +{ + t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); + return (e->ce_dir); +} + +t_symbol *canvas_getdir(t_canvas *x) +{ + t_canvasenvironment *e = canvas_getenv(x); + return (e->ce_dir); +} + +void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize) +{ + char *dir = canvas_getenv(x)->ce_dir->s_name; + if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir) + { + strncpy(result, file, resultsize); + result[resultsize-1] = 0; + } + else + { + int nleft; + strncpy(result, dir, resultsize); + result[resultsize-1] = 0; + nleft = resultsize - strlen(result) - 1; + if (nleft <= 0) return; + strcat(result, "/"); + strncat(result, file, nleft); + result[resultsize-1] = 0; + } +} + +void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) +{ + if (strcmp(x->gl_name->s_name, "Pd")) + pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + x->gl_name = s; + if (strcmp(x->gl_name->s_name, "Pd")) + pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + if (glist_isvisible(x)) + canvas_reflecttitle(x); + if (dir && dir != &s_) + { + t_canvasenvironment *e = canvas_getenv(x); + e->ce_dir = dir; + } +} + +/* --------------- traversing the set of lines in a canvas ----------- */ + +int canvas_getindex(t_canvas *x, t_gobj *y) +{ + t_gobj *y2; + int indexno; + for (indexno = 0, y2 = x->gl_list; y2 && y2 != y; y2 = y2->g_next) + indexno++; + return (indexno); +} + +void linetraverser_start(t_linetraverser *t, t_canvas *x) +{ + t->tr_ob = 0; + t->tr_x = x; + t->tr_nextoc = 0; + t->tr_nextoutno = t->tr_nout = 0; +} + +t_outconnect *linetraverser_next(t_linetraverser *t) +{ + t_outconnect *rval = t->tr_nextoc; + int outno; + while (!rval) + { + outno = t->tr_nextoutno; + while (outno == t->tr_nout) + { + t_gobj *y; + t_object *ob = 0; + if (!t->tr_ob) y = t->tr_x->gl_list; + else y = t->tr_ob->ob_g.g_next; + for (; y; y = y->g_next) + if (ob = pd_checkobject(&y->g_pd)) break; + if (!ob) return (0); + t->tr_ob = ob; + t->tr_nout = obj_noutlets(ob); + outno = 0; + if (glist_isvisible(t->tr_x)) + gobj_getrect(y, t->tr_x, + &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12); + else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0; + } + t->tr_nextoutno = outno + 1; + rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno); + t->tr_outno = outno; + } + t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2, + &t->tr_inlet, &t->tr_inno); + t->tr_nin = obj_ninlets(t->tr_ob2); + if (!t->tr_nin) bug("drawline"); + if (glist_isvisible(t->tr_x)) + { + int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1); + int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1); + gobj_getrect(&t->tr_ob2->ob_g, t->tr_x, + &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22); + t->tr_lx1 = t->tr_x11 + + ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) / + outplus + IOMIDDLE; + t->tr_ly1 = t->tr_y12; + t->tr_lx2 = t->tr_x21 + + ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus + + IOMIDDLE; + t->tr_ly2 = t->tr_y21; + } + else + { + t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0; + t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0; + } + return (rval); +} + +void linetraverser_skipobject(t_linetraverser *t) +{ + t->tr_nextoc = 0; + t->tr_nextoutno = t->tr_nout; +} + +/* -------------------- the canvas object -------------------------- */ +int glist_valid = 10000; + +//static void canvas_manual_pd_free(t_canvas *x) { +// sys_flushtogui(); +// pd_free(&x->gl_pd); +//} + +void glist_init(t_glist *x) +{ + /* zero out everyone except "pd" field */ + memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd)); + x->gl_stub = gstub_new(x, 0); + x->gl_valid = ++glist_valid; + x->gl_xlabel = (t_symbol **)t_getbytes(0); + x->gl_ylabel = (t_symbol **)t_getbytes(0); +} + + /* make a new glist. It will either be a "root" canvas or else + it appears as a "text" object in another window (canvas_getcurrent() + tells us which.) */ +t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) +{ + /* first alloc one byte or redundant memory to prevent creation of objects with the same "name" + which leads to double-action invoked from every single action and eventually possible crashes + + we keep a list of these redundant allocations and destroy them when pd quits */ + //if (x->gl_owner && x->gl_env) { +/* + t_redundant_mem *new_rm = (t_redundant_mem *)t_getbytes(sizeof(*new_rm)); + new_rm->rm_what = (int)getbytes(1); + if (rm_start == NULL) { + //fprintf(stderr,"first allocation\n"); + rm_start = new_rm; + rm_end = new_rm; + } + else if (rm_start == rm_end) { + //fprintf(stderr,"second allocation\n"); + rm_end = new_rm; + rm_start->rm_next = rm_end; + } + else { + //fprintf(stderr,"allocation\n"); + rm_end->rm_next = new_rm; + rm_end = new_rm; + } +*/ + //} + + t_canvas *x = (t_canvas *)pd_new(canvas_class); + + /* now that we've created a new canvas, add canvas info to the new_rm */ + //new_rm->rm_canvas = x; + + t_canvas *owner = canvas_getcurrent(); + t_symbol *s = &s_; + int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT; + int xloc = 0, yloc = GLIST_DEFCANVASYLOC; + int font = (owner ? owner->gl_font : sys_defaultfont); + + glist_init(x); + // jsarlo + x->gl_magic_glass = magicGlass_new((int)x); + // end jsarlo + + //if we are root canvas set the clock for script based destructor of the window + //if (!owner) { + // x->gl_destroy = clock_new(x, (t_method)canvas_manual_pd_free); + //} + + x->gl_obj.te_type = T_OBJECT; + if (!owner) + canvas_addtolist(x); + /* post("canvas %lx, owner %lx", x, owner); */ + + if (argc == 5) /* toplevel: x, y, w, h, font */ + { + xloc = atom_getintarg(0, argc, argv); + yloc = atom_getintarg(1, argc, argv); + width = atom_getintarg(2, argc, argv); + height = atom_getintarg(3, argc, argv); + font = atom_getintarg(4, argc, argv); + } + else if (argc == 6) /* subwindow: x, y, w, h, name, vis */ + { + xloc = atom_getintarg(0, argc, argv); + yloc = atom_getintarg(1, argc, argv); + width = atom_getintarg(2, argc, argv); + height = atom_getintarg(3, argc, argv); + s = atom_getsymbolarg(4, argc, argv); + vis = atom_getintarg(5, argc, argv); + } + /* (otherwise assume we're being created from the menu.) */ + + if (canvas_newdirectory->s_name[0]) + { + static int dollarzero = 1000; + t_canvasenvironment *env = x->gl_env = + (t_canvasenvironment *)getbytes(sizeof(*x->gl_env)); + if (!canvas_newargv) + canvas_newargv = getbytes(0); + env->ce_dir = canvas_newdirectory; + env->ce_argc = canvas_newargc; + env->ce_argv = canvas_newargv; + env->ce_dollarzero = dollarzero++; + env->ce_path = 0; + canvas_newdirectory = &s_; + canvas_newargc = 0; + canvas_newargv = 0; + } + else x->gl_env = 0; + + if (yloc < GLIST_DEFCANVASYLOC) + yloc = GLIST_DEFCANVASYLOC; + if (xloc < 0) + xloc = 0; + x->gl_x1 = 0; + x->gl_y1 = 0; + x->gl_x2 = 1; + x->gl_y2 = 1; + canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height); + x->gl_owner = owner; + x->gl_name = (*s->s_name ? s : + (canvas_newfilename ? canvas_newfilename : gensym("Pd"))); + if (strcmp(x->gl_name->s_name, "Pd")) + pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + x->gl_loading = 1; + //fprintf(stderr,"loading = 1 .x%lx owner=.x%lx\n", x, x->gl_owner); + x->gl_goprect = 0; /* no GOP rectangle unless it's turned on later */ + /* cancel "vis" flag if we're a subpatch of an + abstraction inside another patch. A separate mechanism prevents + the toplevel abstraction from showing up. */ + if (vis && gensym("#X")->s_thing && + ((*gensym("#X")->s_thing) == canvas_class)) + { + t_canvas *zzz = (t_canvas *)(gensym("#X")->s_thing); + while (zzz && !zzz->gl_env) + zzz = zzz->gl_owner; + if (zzz && canvas_isabstraction(zzz) && zzz->gl_owner) + vis = 0; + } + x->gl_willvis = vis; + x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8); + x->gl_font = sys_nearestfontsize(font); + pd_pushsym(&x->gl_pd); + + return(x); +} + +void canvas_setgraph(t_glist *x, int flag, int nogoprect); + +static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv) +{ + x->gl_x1 = atom_getfloatarg(0, argc, argv); + x->gl_y1 = atom_getfloatarg(1, argc, argv); + x->gl_x2 = atom_getfloatarg(2, argc, argv); + x->gl_y2 = atom_getfloatarg(3, argc, argv); + x->gl_pixwidth = atom_getintarg(4, argc, argv); + x->gl_pixheight = atom_getintarg(5, argc, argv); + if (argc <= 7) + canvas_setgraph(x, atom_getintarg(6, argc, argv), 1); + else + { + x->gl_xmargin = atom_getintarg(7, argc, argv); + x->gl_ymargin = atom_getintarg(8, argc, argv); + canvas_setgraph(x, atom_getintarg(6, argc, argv), 0); + } +} + + /* make a new glist and add it to this glist. It will appear as + a "graph", not a text object. */ +t_glist *glist_addglist(t_glist *g, t_symbol *sym, + t_float x1, t_float y1, t_float x2, t_float y2, + t_float px1, t_float py1, t_float px2, t_float py2) +{ + static int gcount = 0; + int zz; + int menu = 0; + char *str; + t_glist *x = (t_glist *)pd_new(canvas_class); + glist_init(x); + x->gl_obj.te_type = T_OBJECT; + if (!*sym->s_name) + { + char buf[40]; + sprintf(buf, "graph%d", ++gcount); + sym = gensym(buf); + menu = 1; + } + else if (!strncmp((str = sym->s_name), "graph", 5) + && (zz = atoi(str + 5)) > gcount) + gcount = zz; + /* in 0.34 and earlier, the pixel rectangle and the y bounds were + reversed; this would behave the same, except that the dialog window + would be confusing. The "correct" way is to have "py1" be the value + that is higher on the screen. */ + if (py2 < py1) + { + t_float zz; + zz = y2; + y2 = y1; + y1 = zz; + zz = py2; + py2 = py1; + py1 = zz; + } + if (x1 == x2 || y1 == y2) + x1 = 0, x2 = 100, y1 = 1, y2 = -1; + if (px1 != 0 && px2 == 0) px2 = px1 + GLIST_DEFGRAPHWIDTH; + if (py1 != 0 && py2 == py1) py2 = py1 + GLIST_DEFGRAPHHEIGHT; + if (px1 >= px2 || py1 >= py2) + px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH, + py2 = 20 + GLIST_DEFGRAPHHEIGHT; + + x->gl_name = sym; + x->gl_x1 = x1; + x->gl_x2 = x2; + x->gl_y1 = y1; + x->gl_y2 = y2; + x->gl_obj.te_xpix = px1; + x->gl_obj.te_ypix = py1; + x->gl_pixwidth = px2 - px1; + x->gl_pixheight = py2 - py1; + x->gl_font = (canvas_getcurrent() ? + canvas_getcurrent()->gl_font : sys_defaultfont); + x->gl_screenx1 = x->gl_screeny1 = 0; + x->gl_screenx2 = 450; + x->gl_screeny2 = 300; + if (strcmp(x->gl_name->s_name, "Pd")) + pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + x->gl_owner = g; + x->gl_isgraph = 1; + x->gl_goprect = 0; + x->gl_obj.te_binbuf = binbuf_new(); + binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph")); + if (!menu) + pd_pushsym(&x->gl_pd); + glist_add(g, &x->gl_gobj); + sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", (long unsigned int)glist_getcanvas(g)); + return (x); +} + + /* call glist_addglist from a Pd message */ +void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv) +{ + pd_vmess(&g->gl_pd, gensym("editmode"), "i", 1); + t_symbol *sym = atom_getsymbolarg(0, argc, argv); + /* if we wish to put a graph where the mouse is we need to replace bogus name */ + if (!strcmp(sym->s_name, "NULL")) sym = &s_; + t_float x1 = atom_getfloatarg(1, argc, argv); + t_float y1 = atom_getfloatarg(2, argc, argv); + t_float x2 = atom_getfloatarg(3, argc, argv); + t_float y2 = atom_getfloatarg(4, argc, argv); + t_float px1 = atom_getfloatarg(5, argc, argv); + t_float py1 = atom_getfloatarg(6, argc, argv); + t_float px2 = atom_getfloatarg(7, argc, argv); + t_float py2 = atom_getfloatarg(8, argc, argv); + glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2); +} + + /* return true if the glist should appear as a graph on parent; + otherwise it appears as a text box. */ +int glist_isgraph(t_glist *x) +{ + return (x->gl_isgraph|(x->gl_hidetext<<1)); +} + + /* This is sent from the GUI to inform a toplevel that its window has been + moved or resized. */ +static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2) +{ + int heightwas = y2 - y1; + int heightchange = y2 - y1 - (x->gl_screeny2 - x->gl_screeny1); + if (x->gl_screenx1 == x1 && x->gl_screeny1 == y1 && + x->gl_screenx2 == x2 && x->gl_screeny2 == y2) + return; + x->gl_screenx1 = x1; + x->gl_screeny1 = y1; + x->gl_screenx2 = x2; + x->gl_screeny2 = y2; + if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1)) + { + /* if it's flipped so that y grows upward, + fix so that zero is bottom edge and redraw. This is + only appropriate if we're a regular "text" object on the + parent. */ + t_float diff = x->gl_y1 - x->gl_y2; + t_gobj *y; + x->gl_y1 = heightwas * diff; + x->gl_y2 = x->gl_y1 - diff; + /* and move text objects accordingly; they should stick + to the bottom, not the top. */ + for (y = x->gl_list; y; y = y->g_next) + if (pd_checkobject(&y->g_pd)) + gobj_displace(y, x, 0, heightchange); + canvas_redraw(x); + } +} + +t_symbol *canvas_makebindsym(t_symbol *s) +{ + char buf[MAXPDSTRING]; + strcpy(buf, "pd-"); + strcat(buf, s->s_name); + return (gensym(buf)); +} + +void canvas_reflecttitle(t_canvas *x) +{ + //fprintf(stderr,"canvas_reflecttitle\n"); + char namebuf[MAXPDSTRING]; + t_canvasenvironment *env = canvas_getenv(x); + if (env->ce_argc) + { + int i; + strcpy(namebuf, " ("); + for (i = 0; i < env->ce_argc; i++) + { + if (strlen(namebuf) > MAXPDSTRING/2 - 5) + break; + if (i != 0) + strcat(namebuf, " "); + atom_string(&env->ce_argv[i], namebuf + strlen(namebuf), + MAXPDSTRING/2); + } + strcat(namebuf, ")"); + } + else namebuf[0] = 0; +#ifdef __APPLE__ + sys_vgui("wm attributes .x%lx -modified %d -titlepath {%s/%s}\n", + x, x->gl_dirty, canvas_getdir(x)->s_name, x->gl_name->s_name); + sys_vgui("wm title .x%lx {%s%s}\n", x, x->gl_name->s_name, namebuf); +#else + if(glist_istoplevel(x) || !x->gl_isgraph || x->gl_isgraph && x->gl_havewindow || x->gl_loading || x->gl_dirty) { + /*fprintf(stderr,"%d %d %d %d %d\n", glist_istoplevel(x), !x->gl_isgraph, + x->gl_isgraph && x->gl_havewindow, x->gl_loading, + x->gl_dirty);*/ + sys_vgui("wm title .x%lx {%s%c%s - %s}\n", + x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf, + canvas_getdir(x)->s_name); + } +#endif +} + + /* mark a glist dirty or clean */ +void canvas_dirty(t_canvas *x, t_floatarg n) +{ + t_canvas *x2 = canvas_getrootfor(x); + if (glist_amreloadingabstractions) + return; + if ((unsigned)n != x2->gl_dirty) + { + x2->gl_dirty = n; + if (glist_isvisible(x2)) + canvas_reflecttitle(x2); + } +} + +void canvas_drawredrect(t_canvas *x, int doit) +{ + if (doit) + sys_vgui(".x%lx.c create line\ + %d %d %d %d %d %d %d %d %d %d -fill #ff8080 -tags GOP\n", + glist_getcanvas(x), + x->gl_xmargin, x->gl_ymargin, + x->gl_xmargin + x->gl_pixwidth, x->gl_ymargin, + x->gl_xmargin + x->gl_pixwidth, x->gl_ymargin + x->gl_pixheight, + x->gl_xmargin, x->gl_ymargin + x->gl_pixheight, + x->gl_xmargin, x->gl_ymargin); + else sys_vgui(".x%lx.c delete GOP\n", glist_getcanvas(x)); +} + + /* the window becomes "mapped" (visible and not miniaturized) or + "unmapped" (either miniaturized or just plain gone.) This should be + called from the GUI after the fact to "notify" us that we're mapped. */ +void canvas_map(t_canvas *x, t_floatarg f) +{ + //fprintf(stderr,"canvas_map\n"); + int flag = (f != 0); + t_gobj *y; + if (flag) + { + if (!glist_isvisible(x)) + { + t_selection *sel; + if (!x->gl_havewindow) + { + bug("canvas_map"); + canvas_vis(x, 1); + } + + /* if parent has editor enabled and we're a sub-patch, + (but not an abstraction) match its edit mode to that + of its parent patch. */ + /*t_glist *parentx; + if (!canvas_isabstraction(x)) { + if (x->gl_owner) { + parentx = x->gl_owner; + while (parentx->gl_owner) + parentx = parentx->gl_owner; + if (parentx->gl_edit) + canvas_editmode(x, 1); + else if (x->gl_edit) + canvas_editmode(x, 0); + } + }*/ + /* for parent windows, let's make sure the cursor is updated + as soon as the window is open (if in edit mode) */ + //else if (x->gl_edit) { + //canvas_setcursor(x, CURSOR_EDITMODE_NOTHING); + //} + + for (y = x->gl_list; y; y = y->g_next) + gobj_vis(y, x, 1); + for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) + gobj_select(sel->sel_what, x, 1); + x->gl_mapped = 1; + canvas_drawlines(x); + if (x->gl_isgraph && x->gl_goprect) + canvas_drawredrect(x, 1); + sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x); + } + } + else + { + if (glist_isvisible(x)) + { + /* just clear out the whole canvas */ + sys_vgui(".x%lx.c dtag all selected\n", x); + sys_vgui(".x%lx.c delete all\n", x); + x->gl_mapped = 0; + } + } +} + +void canvas_redraw(t_canvas *x) +{ + if (glist_isvisible(x)) + { + canvas_map(x, 0); + canvas_map(x, 1); + + /* now re-highlight our selection */ + t_selection *y; + for (y = x->gl_editor->e_selection; y; y = y->sel_next) + gobj_select(y->sel_what, x, 1); + } +} + + + /* we call this on a non-toplevel glist to "open" it into its + own window. */ +void glist_menu_open(t_glist *x) +{ + if (glist_isvisible(x) && !glist_istoplevel(x)) + { + t_glist *gl2 = x->gl_owner; + if (!gl2) + bug("glist_menu_open"); /* shouldn't happen but not dangerous */ + else + { + /* erase ourself in parent window */ + gobj_vis(&x->gl_gobj, gl2, 0); + /* get rid of our editor (and subeditors) */ + if (x->gl_editor) + canvas_destroy_editor(x); + x->gl_havewindow = 1; + /* redraw ourself in parent window (blanked out this time) */ + gobj_vis(&x->gl_gobj, gl2, 1); + } + } + canvas_vis(x, 1); +} + +int glist_isvisible(t_glist *x) +{ + return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped); +} + +int glist_istoplevel(t_glist *x) +{ + /* we consider a graph "toplevel" if it has its own window + or if it appears as a box in its parent window so that we + don't draw the actual contents there. */ + return (x->gl_havewindow || !x->gl_isgraph); +} + +int glist_getfont(t_glist *x) +{ + while (!x->gl_env) + if (!(x = x->gl_owner)) + bug("t_canvasenvironment"); + return (x->gl_font); +} + +void canvas_free(t_canvas *x) +{ + t_gobj *y; + int dspstate = canvas_suspend_dsp(); + // jsarlo + if (x->gl_magic_glass) + magicGlass_free(x->gl_magic_glass); + // end jsarlo + + //delete clock for gl_destroy + //if (x->gl_destroy) clock_free(x->gl_destroy); + + canvas_noundo(x); + if (canvas_editing == x) + canvas_editing = 0; + if (canvas_whichfind == x) + canvas_whichfind = 0; + glist_noselect(x); + while (y = x->gl_list) + glist_delete(x, y); + if (x == glist_getcanvas(x)) + canvas_vis(x, 0); + + if (strcmp(x->gl_name->s_name, "Pd")) + pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name)); + if (x->gl_env) + { + freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom)); + freebytes(x->gl_env, sizeof(*x->gl_env)); + } + canvas_resume_dsp(dspstate); + glist_cleanup(x); + gfxstub_deleteforkey(x); /* probably unnecessary */ + if (!x->gl_owner) + canvas_takeofflist(x); +} + +/* ----------------- lines ---------- */ + +static void canvas_drawlines(t_canvas *x) +{ + t_linetraverser t; + t_outconnect *oc; + int issignal; + + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + issignal = (outlet_getsymbol(t.tr_outlet) == &s_signal ? 1 : 0); + sys_vgui(".x%lx.c create line %d %d %d %d -width %d -fill %s \ +-tags {l%lx all_cords}\n", + glist_getcanvas(x), t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2, + (issignal ? 2:1), (issignal ? "$signal_cord" : "$msg_cord"), + oc); + } +} + +void canvas_fixlinesfor(t_canvas *x, t_text *text) +{ + t_linetraverser t; + t_outconnect *oc; + + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + if (t.tr_ob == text || t.tr_ob2 == text) + { + sys_vgui(".x%lx.c coords l%lx %d %d %d %d\n", + glist_getcanvas(x), oc, + t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2); + } + } +} + + /* kill all lines for the object */ +void canvas_deletelinesfor(t_canvas *x, t_text *text) +{ + t_linetraverser t; + t_outconnect *oc; + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + if (t.tr_ob == text || t.tr_ob2 == text) + { + if (x->gl_editor) + { + sys_vgui(".x%lx.c delete l%lx\n", + glist_getcanvas(x), oc); + } + obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); + } + } +} + + /* delete all lines for the object + for efficient redrawing of connections */ +void canvas_eraselinesfor(t_canvas *x, t_text *text) +{ + t_linetraverser t; + t_outconnect *oc; + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + if (t.tr_ob == text || t.tr_ob2 == text) + { + if (x->gl_editor) + { + sys_vgui(".x%lx.c delete l%lx\n", + glist_getcanvas(x), oc); + } + } + } +} + + + /* kill all lines for one inlet or outlet */ +void canvas_deletelinesforio(t_canvas *x, t_text *text, + t_inlet *inp, t_outlet *outp) +{ + t_linetraverser t; + t_outconnect *oc; + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + { + if ((t.tr_ob == text && t.tr_outlet == outp) || + (t.tr_ob2 == text && t.tr_inlet == inp)) + { + if (x->gl_editor) + { + sys_vgui(".x%lx.c delete l%lx\n", + glist_getcanvas(x), oc); + } + obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); + } + } +} + +static void canvas_pop(t_canvas *x, t_floatarg fvis) +{ + if (fvis != 0) + canvas_vis(x, 1); + pd_popsym(&x->gl_pd); + canvas_resortinlets(x); + canvas_resortoutlets(x); + x->gl_loading = 0; + //fprintf(stderr,"loading = 0 .x%lx owner=.x%lx\n", x, x->gl_owner); +} + +void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv); + + +void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv) +{ + t_pd *z; + if (argc > 3) + { + t_atom *ap=argv+3; + if (ap->a_type == A_SYMBOL) + { + t_canvasenvironment *e = canvas_getenv(canvas_getcurrent()); + canvas_rename(x, binbuf_realizedollsym(ap->a_w.w_symbol, + e->ce_argc, e->ce_argv, 1), 0); + } + } + canvas_pop(x, x->gl_willvis); + + if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context"); + else if (*z != canvas_class) error("canvas_restore: wasn't a canvas"); + else + { + t_canvas *x2 = (t_canvas *)z; + x->gl_owner = x2; + canvas_objfor(x2, &x->gl_obj, argc, argv); + } +} + +static void canvas_loadbangabstractions(t_canvas *x) +{ + t_gobj *y; + t_symbol *s = gensym("loadbang"); + for (y = x->gl_list; y; y = y->g_next) + if (pd_class(&y->g_pd) == canvas_class) + { + if (canvas_isabstraction((t_canvas *)y)) + canvas_loadbang((t_canvas *)y); + else + canvas_loadbangabstractions((t_canvas *)y); + } +} + +void canvas_loadbangsubpatches(t_canvas *x) +{ + t_gobj *y; + t_symbol *s = gensym("loadbang"); + for (y = x->gl_list; y; y = y->g_next) + if (pd_class(&y->g_pd) == canvas_class) + { + if (!canvas_isabstraction((t_canvas *)y)) + canvas_loadbangsubpatches((t_canvas *)y); + } + for (y = x->gl_list; y; y = y->g_next) + if ((pd_class(&y->g_pd) != canvas_class) && + zgetfn(&y->g_pd, s)) + pd_vmess(&y->g_pd, s, ""); +} + +void canvas_loadbang(t_canvas *x) +{ + t_gobj *y; + canvas_loadbangabstractions(x); + canvas_loadbangsubpatches(x); +} +/* JMZ: + * initbang is emitted after the canvas is done, but before the parent canvas is done + * therefore, initbangs cannot reach to the outlets + */ +void canvas_initbang(t_canvas *x) +{ + t_gobj *y; + t_symbol *s = gensym("initbang"); + /* run "initbang" for all subpatches, but NOT for the child abstractions */ + for (y = x->gl_list; y; y = y->g_next) + if (pd_class(&y->g_pd) == canvas_class) + { + if (!canvas_isabstraction((t_canvas *)y)) + canvas_initbang((t_canvas *)y); + } + + /* call the initbang()-method for objects that have one */ + for (y = x->gl_list; y; y = y->g_next) + { + if ((pd_class(&y->g_pd) != canvas_class) && zgetfn(&y->g_pd, s)) + { + pd_vmess(&y->g_pd, s, ""); + } + } +} +/* JMZ: + * closebang is emitted before the canvas is destroyed + * and BEFORE subpatches/abstractions in this canvas are destroyed + */ +void canvas_closebang(t_canvas *x) +{ + t_gobj *y; + t_symbol *s = gensym("closebang"); + + /* call the closebang()-method for objects that have one + * but NOT for subpatches/abstractions: these are called separately + * from g_graph:glist_delete() + */ + for (y = x->gl_list; y; y = y->g_next) + { + if ((pd_class(&y->g_pd) != canvas_class) && zgetfn(&y->g_pd, s)) + { + pd_vmess(&y->g_pd, s, ""); + } + } +} + +/* needed for readjustment of garrays */ +extern t_array *garray_getarray(t_garray *x); +extern void garray_fittograph(t_garray *x, int n); +extern t_rtext *glist_findrtext(t_glist *gl, t_text *who); +extern void rtext_gettext(t_rtext *x, char **buf, int *bufsize); + +static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom, + t_symbol *topgeom) +{ + int cxpix, cypix, cw, ch, txpix, typix, tw, th; + if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix) + < 4 || + sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4) + bug("canvas_relocate"); + /* for some reason this is initially called with cw=ch=1 so + we just suppress that here. */ + if (cw > 5 && ch > 5) + canvas_setbounds(x, txpix, typix, + txpix + cw, typix + ch); + /* readjust garrays (if any) */ + t_gobj *g, *gg = NULL; + t_garray *ga = NULL; + t_array *a = NULL; + int num_elem = 0; + + for (g = x->gl_list; g; g = g->g_next) { + //fprintf(stderr, "searching\n"); + + //for subpatch garrays + if (pd_class(&g->g_pd) == garray_class) { + //fprintf(stderr,"found ya\n"); + ga = (t_garray *)g; + if (ga) { + a = garray_getarray(ga); + num_elem = a->a_n; + garray_fittograph(ga, num_elem); + } + } + } +} + +void canvas_popabstraction(t_canvas *x) +{ + newest = &x->gl_pd; + pd_popsym(&x->gl_pd); + //x->gl_loading = 1; + //fprintf(stderr,"loading = 1 .x%lx owner=.x%lx\n", x, x->gl_owner); + canvas_resortinlets(x); + canvas_resortoutlets(x); + x->gl_loading = 0; + //fprintf(stderr,"loading = 0 .x%lx owner=.x%lx\n", x, x->gl_owner); +} + +void canvas_logerror(t_object *y) +{ +#ifdef LATER + canvas_vis(x, 1); + if (!glist_isselected(x, &y->ob_g)) + glist_select(x, &y->ob_g); +#endif +} + +/* -------------------------- subcanvases ---------------------- */ + +static void *subcanvas_new(t_symbol *s) +{ + t_atom a[6]; + t_canvas *x, *z = canvas_getcurrent(); + if (!*s->s_name) s = gensym("/SUBPATCH/"); + SETFLOAT(a, 0); + SETFLOAT(a+1, GLIST_DEFCANVASYLOC); + SETFLOAT(a+2, GLIST_DEFCANVASWIDTH); + SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT); + SETSYMBOL(a+4, s); + SETFLOAT(a+5, 1); + x = canvas_new(0, 0, 6, a); + x->gl_owner = z; + canvas_pop(x, 1); + return (x); +} + +static void canvas_click(t_canvas *x, + t_floatarg xpos, t_floatarg ypos, + t_floatarg shift, t_floatarg ctrl, t_floatarg alt) +{ + canvas_vis(x, 1); +} + + + /* find out from subcanvas contents how much to fatten the box */ +void canvas_fattensub(t_canvas *x, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_gobj *y; + *xp2 += 50; /* fake for now */ + *yp2 += 50; +} + +static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac && av->a_type == A_SYMBOL) + canvas_rename(x, av->a_w.w_symbol, 0); + else if (ac && av->a_type == A_DOLLSYM) + { + t_canvasenvironment *e = canvas_getenv(x); + canvas_setcurrent(x); + canvas_rename(x, binbuf_realizedollsym(av->a_w.w_symbol, + e->ce_argc, e->ce_argv, 1), 0); + canvas_unsetcurrent(x); + } + else canvas_rename(x, gensym("Pd"), 0); +} + +/* ------------------ table ---------------------------*/ + +static int tabcount = 0; + +static void *table_new(t_symbol *s, t_floatarg f) +{ + t_atom a[9]; + t_glist *gl; + t_canvas *x, *z = canvas_getcurrent(); + if (s == &s_) + { + char tabname[255]; + t_symbol *t = gensym("table"); + sprintf(tabname, "%s%d", t->s_name, tabcount++); + s = gensym(tabname); + } + if (f <= 1) + f = 100; + SETFLOAT(a, 0); + SETFLOAT(a+1, GLIST_DEFCANVASYLOC); + SETFLOAT(a+2, 600); + SETFLOAT(a+3, 400); + SETSYMBOL(a+4, s); + SETFLOAT(a+5, 0); + x = canvas_new(0, 0, 6, a); + + x->gl_owner = z; + + /* create a graph for the table */ + gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1, + 50, 350, 550, 50); + + graph_array(gl, s, &s_float, f, 0); + + canvas_pop(x, 0); + + return (x); +} + + /* return true if the "canvas" object is an abstraction (so we don't + save its contents, fogr example.) */ +int canvas_isabstraction(t_canvas *x) +{ + return (x->gl_env != 0); +} + + /* return true if the "canvas" object is a "table". */ +int canvas_istable(t_canvas *x) +{ + t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); + int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); + int istable = (argc && argv[0].a_type == A_SYMBOL && + argv[0].a_w.w_symbol == gensym("table")); + return (istable); +} + + /* return true if the "canvas" object should be treated as a text + object. This is true for abstractions but also for "table"s... */ +/* JMZ: add a flag to gop-abstractions to hide the title */ +int canvas_showtext(t_canvas *x) +{ + t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0); + int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0); + int isarray = (argc && argv[0].a_type == A_SYMBOL && + argv[0].a_w.w_symbol == gensym("graph")); + if(x->gl_hidetext) + return 0; + else + return (!isarray); +} + + /* get the document containing this canvas */ +t_canvas *canvas_getrootfor(t_canvas *x) +{ + if ((!x->gl_owner) || canvas_isabstraction(x)) + return (x); + else return (canvas_getrootfor(x->gl_owner)); +} + +/* ------------------------- DSP chain handling ------------------------- */ + +EXTERN_STRUCT _dspcontext; +#define t_dspcontext struct _dspcontext + +void ugen_start(void); +void ugen_stop(void); + +t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, + int ninlets, int noutlets); +void ugen_add(t_dspcontext *dc, t_object *x); +void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, + t_object *x2, int inno); +void ugen_done_graph(t_dspcontext *dc); + + /* schedule one canvas for DSP. This is called below for all "root" + canvases, but is also called from the "dsp" method for sub- + canvases, which are treated almost like any other tilde object. */ + +static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp) +{ + t_linetraverser t; + t_outconnect *oc; + t_gobj *y; + t_object *ob; + t_symbol *dspsym = gensym("dsp"); + t_dspcontext *dc; + + /* create a new "DSP graph" object to use in sorting this canvas. + If we aren't toplevel, there are already other dspcontexts around. */ + + dc = ugen_start_graph(toplevel, sp, + obj_nsiginlets(&x->gl_obj), + obj_nsigoutlets(&x->gl_obj)); + + /* find all the "dsp" boxes and add them to the graph */ + + ob = &x->gl_magic_glass->x_obj; + if (ob && x->gl_magic_glass->x_connectedObj) { + //fprintf(stderr,"adding cord inspector to dsp\n"); + ugen_add(dc, ob); // this t_canvas could be an array, hence no gl_magic_glass + } + + for (y = x->gl_list; y; y = y->g_next) + if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym)) + ugen_add(dc, ob); + + /* ... and all dsp interconnections */ + linetraverser_start(&t, x); + while (oc = linetraverser_next(&t)) + if (obj_issignaloutlet(t.tr_ob, t.tr_outno)) + ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno); + + /* finally, sort them and add them to the DSP chain */ + ugen_done_graph(dc); +} + +static void canvas_dsp(t_canvas *x, t_signal **sp) +{ + canvas_dodsp(x, 0, sp); +} + + /* this routine starts DSP for all root canvases. */ +static void canvas_start_dsp(void) +{ + t_canvas *x; + if (canvas_dspstate) ugen_stop(); + else sys_gui("pdtk_pd_dsp ON\n"); + ugen_start(); + + for (x = canvas_list; x; x = x->gl_next) + canvas_dodsp(x, 1, 0); + + canvas_dspstate = 1; +} + +static void canvas_stop_dsp(void) +{ + if (canvas_dspstate) + { + ugen_stop(); + sys_gui("pdtk_pd_dsp OFF\n"); + canvas_dspstate = 0; + } +} + + /* DSP can be suspended before, and resumed after, operations which + might affect the DSP chain. For example, we suspend before loading and + resume afterward, so that DSP doesn't get resorted for every DSP object + int the patch. */ + +int canvas_suspend_dsp(void) +{ + int rval = canvas_dspstate; + if (rval) canvas_stop_dsp(); + return (rval); +} + +void canvas_resume_dsp(int oldstate) +{ + if (oldstate) canvas_start_dsp(); +} + + /* this is equivalent to suspending and resuming in one step. */ +void canvas_update_dsp(void) +{ + if (canvas_dspstate) canvas_start_dsp(); +} + +void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv) +{ + int newstate; + if (argc) + { + newstate = atom_getintarg(0, argc, argv); + if (newstate && !canvas_dspstate) + { + sys_set_audio_state(1); + canvas_start_dsp(); + } + else if (!newstate && canvas_dspstate) + { + canvas_stop_dsp(); + sys_set_audio_state(0); + } + } + else post("dsp state %d", canvas_dspstate); +} + +void *canvas_getblock(t_class *blockclass, t_canvas **canvasp) +{ + t_canvas *canvas = *canvasp; + t_gobj *g; + void *ret = 0; + for (g = canvas->gl_list; g; g = g->g_next) + { + if (g->g_pd == blockclass) + ret = g; + } + *canvasp = canvas->gl_owner; + return(ret); +} + +/******************* redrawing data *********************/ + + /* redraw all "scalars" (do this if a drawing command is changed.) + LATER we'll use the "template" information to select which ones we + redraw. Action = 0 for redraw, 1 for draw only, 2 for erase. */ +static void glist_redrawall(t_glist *gl, int action) +{ + t_gobj *g; + int vis = glist_isvisible(gl); + for (g = gl->gl_list; g; g = g->g_next) + { + t_class *cl; + if (vis && g->g_pd == scalar_class) + { + if (action == 1) + { + if (glist_isvisible(gl)) + gobj_vis(g, gl, 1); + } + else if (action == 2) + { + if (glist_isvisible(gl)) + gobj_vis(g, gl, 0); + } + else scalar_redraw((t_scalar *)g, gl); + } + else if (g->g_pd == canvas_class) + glist_redrawall((t_glist *)g, action); + } +} + + /* public interface for above. */ +void canvas_redrawallfortemplate(t_template *template, int action) +{ + t_canvas *x; + /* find all root canvases */ + for (x = canvas_list; x; x = x->gl_next) + glist_redrawall(x, action); +} + + /* find the template defined by a canvas, and redraw all elements + for that */ +void canvas_redrawallfortemplatecanvas(t_canvas *x, int action) +{ + t_gobj *g; + t_template *tmpl; + t_symbol *s1 = gensym("struct"); + for (g = x->gl_list; g; g = g->g_next) + { + t_object *ob = pd_checkobject(&g->g_pd); + t_atom *argv; + if (!ob || ob->te_type != T_OBJECT || + binbuf_getnatom(ob->te_binbuf) < 2) + continue; + argv = binbuf_getvec(ob->te_binbuf); + if (argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL + || argv[0].a_w.w_symbol != s1) + continue; + tmpl = template_findbyname(argv[1].a_w.w_symbol); + canvas_redrawallfortemplate(tmpl, action); + } + canvas_redrawallfortemplate(0, action); +} + +/* ------------------------------- declare ------------------------ */ + +/* put "declare" objects in a patch to tell it about the environment in +which objects should be created in this canvas. This includes directories to +search ("-path", "-stdpath") and object libraries to load +("-lib" and "-stdlib"). These must be set before the patch containing +the "declare" object is filled in with its contents; so when the patch is +saved, we throw early messages to the canvas to set the environment +before any objects are created in it. */ + +static t_class *declare_class; +extern t_class *import_class; + +typedef struct _declare +{ + t_object x_obj; + t_canvas *x_canvas; + int x_useme; +} t_declare; + +static void *declare_new(t_symbol *s, int argc, t_atom *argv) +{ + t_declare *x = (t_declare *)pd_new(declare_class); + x->x_useme = 1; + x->x_canvas = canvas_getcurrent(); + /* LATER update environment and/or load libraries */ + return (x); +} + +static void declare_free(t_declare *x) +{ + x->x_useme = 0; + /* LATER update environment */ +} + +void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b) +{ + t_gobj *y; + + for (y = x->gl_list; y; y = y->g_next) + { + if (pd_class(&y->g_pd) == declare_class) + { + binbuf_addv(b, "s", gensym("#X")); + binbuf_addbinbuf(b, ((t_declare *)y)->x_obj.te_binbuf); + binbuf_addv(b, ";"); + } + else if (pd_class(&y->g_pd) == import_class) + { + int i, argc; + t_atom *argv; + binbuf_addv(b, "s", gensym("#X")); + binbuf_addv(b, "s", gensym("declare")); + argc = binbuf_getnatom(((t_object *)y)->te_binbuf) - 1; + argv = binbuf_getvec(((t_object *)y)->te_binbuf) + 1; + for(i = 0; i < argc; ++i) + { + binbuf_addv(b, "s", gensym("-lib")); + binbuf_add(b, 1, argv + i); + } + binbuf_addv(b, ";"); + } + else if (pd_class(&y->g_pd) == canvas_class) + canvas_savedeclarationsto((t_canvas *)y, b); + } +} + +static void canvas_completepath(char *from, char *to, int bufsize) +{ + if (sys_isabsolutepath(from)) + { + to[0] = '\0'; + } + else + { // if not absolute path, append Pd lib dir + strncpy(to, sys_libdir->s_name, bufsize-4); + to[bufsize-3] = '\0'; + strcat(to, "/"); + } + 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) +{ + int i; + t_canvasenvironment *e = canvas_getenv(x); +#if 0 + startpost("declare:: %s", s->s_name); + postatom(argc, argv); + endpost(); +#endif + for (i = 0; i < argc; i++) + { + char strbuf[FILENAME_MAX]; + char *flag = atom_getsymbolarg(i, argc, argv)->s_name; + if ((argc > i+1) && !strcmp(flag, "-path")) + { + e->ce_path = namelist_append(e->ce_path, + atom_getsymbolarg(i+1, argc, argv)->s_name, 0); + i++; + } + else if ((argc > i+1) && !strcmp(flag, "-stdpath")) + { + canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name, + strbuf, FILENAME_MAX); + e->ce_path = namelist_append(e->ce_path, strbuf, 0); + i++; + } + else if ((argc > i+1) && !strcmp(flag, "-lib")) + { + sys_load_lib(x, atom_getsymbolarg(i+1, argc, argv)->s_name); + i++; + } + else if ((argc > i+1) && !strcmp(flag, "-stdlib")) + { + canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name, + strbuf, FILENAME_MAX); + sys_load_lib(0, strbuf); + i++; + } + else post("declare: %s: unknown declaration", flag); + } +} + + /* utility function to read a file, looking first down the canvas's search + path (set with "declare" objects in the patch and recursively in calling + patches), then down the system one. The filename is the concatenation of + "name" and "ext". "Name" may be absolute, or may be relative with + slashes. If anything can be opened, the true directory + ais put in the buffer dirresult (provided by caller), which should + be "size" bytes. The "nameresult" pointer will be set somewhere in + the interior of "dirresult" and will give the file basename (with + slashes trimmed). If "bin" is set a 'binary' open is + attempted, otherwise ASCII (this only matters on Microsoft.) + If "x" is zero, the file is sought in the directory "." or in the + global path.*/ + +int canvas_open(t_canvas *x, const char *name, const char *ext, + char *dirresult, char **nameresult, unsigned int size, int bin) +{ + t_namelist *nl, thislist; + int fd = -1; + t_canvas *y; + + /* first check if "name" is absolute (and if so, try to open) */ + if (sys_open_absolute(name, ext, dirresult, nameresult, size, bin, &fd)) + return (fd); + + /* otherwise "name" is relative; start trying in directories named + in this and parent environments */ + for (y = x; y; y = y->gl_owner) + if (y->gl_env) + { + t_namelist *nl; + t_canvas *x2 = x; + char *dir; + while (x2 && x2->gl_owner) + x2 = x2->gl_owner; + dir = (x2 ? canvas_getdir(x2)->s_name : "."); + for (nl = y->gl_env->ce_path; nl; nl = nl->nl_next) + { + char realname[FILENAME_MAX]; + if (sys_isabsolutepath(nl->nl_string)) + { + realname[0] = '\0'; + } + else + { /* if not absolute path, append Pd lib dir */ + strncpy(realname, dir, FILENAME_MAX); + realname[FILENAME_MAX-3] = 0; + strcat(realname, "/"); + } + strncat(realname, nl->nl_string, FILENAME_MAX-strlen(realname)); + realname[FILENAME_MAX-1] = 0; + if ((fd = sys_trytoopenone(realname, name, ext, + dirresult, nameresult, size, bin)) >= 0) + return (fd); + } + } + return (open_via_path((x ? canvas_getdir(x)->s_name : "."), name, ext, + dirresult, nameresult, size, bin)); +} + +/* ------------------------------- setup routine ------------------------ */ + + /* why are some of these "glist" and others "canvas"? */ +extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv); +extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); + /* old version... */ +extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv); + /* new version: */ +extern void canvas_hradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_vradio(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv); +extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv); + +void g_graph_setup(void); +void g_editor_setup(void); +void g_readwrite_setup(void); +extern void canvas_properties(t_gobj *z); + +void g_canvas_setup(void) +{ + /* we prevent the user from typing "canvas" in an object box + by sending 0 for a creator function. */ + canvas_class = class_new(gensym("canvas"), 0, + (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0); + /* here is the real creator function, invoked in patch files + by sending the "canvas" message to #N, which is bound + to pd_camvasmaker. */ + class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"), + A_GIMME, 0); + class_addmethod(canvas_class, (t_method)canvas_restore, + gensym("restore"), A_GIMME, 0); + class_addmethod(canvas_class, (t_method)canvas_coords, + gensym("coords"), A_GIMME, 0); + +/* -------------------------- objects ----------------------------- */ + class_addmethod(canvas_class, (t_method)canvas_obj, + gensym("obj"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_msg, + gensym("msg"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_floatatom, + gensym("floatatom"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_symbolatom, + gensym("symbolatom"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)glist_text, + gensym("text"), A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)glist_scalar, + gensym("scalar"), A_GIMME, A_NULL); + +/* -------------- IEMGUI: button, toggle, slider, etc. ------------ */ + class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_hradio, gensym("hradio"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vradio, gensym("vradio"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"), + A_GIMME, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"), + A_GIMME, A_NULL); + +/* ------------------------ gui stuff --------------------------- */ + class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"), + A_DEFFLOAT, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_loadbang, + gensym("loadbang"), A_NULL); + class_addmethod(canvas_class, (t_method)canvas_relocate, + gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_vis, + gensym("vis"), A_FLOAT, A_NULL); + class_addmethod(canvas_class, (t_method)glist_menu_open, + gensym("menu-open"), A_NULL); + class_addmethod(canvas_class, (t_method)canvas_map, + gensym("map"), A_FLOAT, A_NULL); + class_addmethod(canvas_class, (t_method)canvas_dirty, + gensym("dirty"), A_FLOAT, A_NULL); + class_setpropertiesfn(canvas_class, (t_propertiesfn)canvas_properties); + +/* ---------------------- list handling ------------------------ */ + class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"), + A_NULL); + +/* ----- subcanvases, which you get by typing "pd" in a box ---- */ + class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0); + class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0); + + class_addmethod(canvas_class, (t_method)canvas_click, + gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0); + class_addmethod(canvas_class, (t_method)canvas_rename_method, + gensym("rename"), A_GIMME, 0); + +/*---------------------------- tables -- GG ------------------- */ + + class_addcreator((t_newmethod)table_new, gensym("table"), + A_DEFSYM, A_DEFFLOAT, 0); + +/*---------------------------- declare ------------------- */ + declare_class = class_new(gensym("declare"), (t_newmethod)declare_new, + (t_method)declare_free, sizeof(t_declare), CLASS_NOINLET, A_GIMME, 0); + class_addmethod(canvas_class, (t_method)canvas_declare, + gensym("declare"), A_GIMME, 0); + +/* -------------- setups from other files for canvas_class ---------------- */ + g_graph_setup(); + g_editor_setup(); + g_readwrite_setup(); +} diff --git a/src/g_editor.c b/src/g_editor.c index 8daf7f82359b34427486c5d4d26b772495bf9989..a716a3fa7358b063d86d75b099f466de6a31c352 100644 --- a/src/g_editor.c +++ b/src/g_editor.c @@ -48,7 +48,6 @@ static int outlet_issignal = 0; static int inlet_issignal = 0; static int last_inlet_filter = 0; static int last_outlet_filter = 0; -static int copyfromexternalbuffer = 0; struct _outlet { t_object *o_owner; @@ -349,10 +348,8 @@ void glist_noselect(t_glist *x) { if (x->gl_editor) { - if (x->gl_editor->e_selection) { - while (x->gl_editor->e_selection) - glist_deselect(x, x->gl_editor->e_selection->sel_what); - } + while (x->gl_editor->e_selection) + glist_deselect(x, x->gl_editor->e_selection->sel_what); if (x->gl_editor->e_selectedline) glist_deselectline(x); if (c_selection == x) @@ -433,14 +430,11 @@ static const char *canvas_undo_name; void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf, const char *name) { - //fprintf(stderr,"canvas_setundo %s\n", name); - int hadone = 0; /* blow away the old undo information. In one special case the old undo info is re-used; if so we shouldn't free it here. */ if (canvas_undo_fn && canvas_undo_buf && (buf != canvas_undo_buf)) { - //fprintf(stderr,"hadone canvas_setundo\n"); (*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_FREE); hadone = 1; } @@ -611,24 +605,22 @@ static void *canvas_undo_set_cut(t_canvas *x, int mode) /* store connections into/out of the selection */ buf->u_reconnectbuf = binbuf_new(); linetraverser_start(&t, x); - if (linetraverser_next(&t)) { - while (oc = linetraverser_next(&t)) - { - int issel1 = glist_isselected(x, &t.tr_ob->ob_g); - int issel2 = glist_isselected(x, &t.tr_ob2->ob_g); - if (issel1 != issel2) - { - binbuf_addv(buf->u_reconnectbuf, "ssiiii;", - gensym("#X"), gensym("connect"), - (issel1 ? nnotsel : 0) - + glist_selectionindex(x, &t.tr_ob->ob_g, issel1), - t.tr_outno, - (issel2 ? nnotsel : 0) + - glist_selectionindex(x, &t.tr_ob2->ob_g, issel2), - t.tr_inno); - } - } - } + while (oc = linetraverser_next(&t)) + { + int issel1 = glist_isselected(x, &t.tr_ob->ob_g); + int issel2 = glist_isselected(x, &t.tr_ob2->ob_g); + if (issel1 != issel2) + { + binbuf_addv(buf->u_reconnectbuf, "ssiiii;", + gensym("#X"), gensym("connect"), + (issel1 ? nnotsel : 0) + + glist_selectionindex(x, &t.tr_ob->ob_g, issel1), + t.tr_outno, + (issel2 ? nnotsel : 0) + + glist_selectionindex(x, &t.tr_ob2->ob_g, issel2), + t.tr_inno); + } + } if (mode == UCUT_TEXT) { buf->u_objectbuf = canvas_docopy(x); @@ -711,7 +703,7 @@ static void canvas_undo_cut(t_canvas *x, void *z, int action) binbuf_free(buf->u_reconnectbuf); if (buf->u_redotextbuf) binbuf_free(buf->u_redotextbuf); - if (buf != NULL) t_freebytes(buf, sizeof(*buf)); + t_freebytes(buf, sizeof(*buf)); } } @@ -1164,31 +1156,57 @@ typedef struct _undo_canvas_properties unsigned int gl_hidetext:1; /* hide object-name + args when doing graph on parent */ } t_undo_canvas_properties; -t_undo_canvas_properties global_buf; +t_undo_canvas_properties *global_buf; /* we need this to avoid redundant undo creation when pressing apply and then ok in the canvas properties menu */ static void *canvas_undo_set_canvas(t_canvas *x) { + //t_undo_canvas_properties *buf; + /* enable editor (in case it is disabled) and select the object we are working on */ if (!x->gl_edit) canvas_editmode(x, 1); - global_buf.gl_pixwidth = x->gl_pixwidth; - global_buf.gl_pixheight = x->gl_pixheight; - global_buf.gl_x1 = x->gl_x1; - global_buf.gl_y1 = x->gl_y1; - global_buf.gl_x2 = x->gl_x2; - global_buf.gl_y2 = x->gl_y2; - global_buf.gl_screenx1 = x->gl_screenx1; - global_buf.gl_screeny1 = x->gl_screeny1; - global_buf.gl_screenx2 = x->gl_screenx2; - global_buf.gl_screeny2 = x->gl_screeny2; - global_buf.gl_xmargin = x->gl_xmargin; - global_buf.gl_ymargin = x->gl_ymargin; - global_buf.gl_goprect = x->gl_goprect; - global_buf.gl_isgraph = x->gl_isgraph; - global_buf.gl_hidetext = x->gl_hidetext; + if (global_buf == NULL) { + global_buf = (t_undo_canvas_properties *)getbytes(sizeof(*global_buf)); + //fprintf(stderr,"creating a new buffer for canvas properties\n"); + } + + /*if ( + global_buf->gl_pixwidth != x->gl_pixwidth || + global_buf->gl_pixheight != x->gl_pixheight || + global_buf->gl_x1 != x->gl_x1 || + global_buf->gl_y1 != x->gl_y1 || + global_buf->gl_x2 != x->gl_x2 || + global_buf->gl_y2 != x->gl_y2 || + global_buf->gl_screenx1 != x->gl_screenx1 || + global_buf->gl_screeny1 != x->gl_screeny1 || + global_buf->gl_screenx2 != x->gl_screenx2 || + global_buf->gl_screeny2 != x->gl_screeny2 || + global_buf->gl_xmargin != x->gl_xmargin || + global_buf->gl_ymargin != x->gl_ymargin || + global_buf->gl_goprect != x->gl_goprect || + global_buf->gl_isgraph != x->gl_isgraph || + global_buf->gl_hidetext != x->gl_hidetext) + {*/ + //fprintf(stderr,"changing values\n"); + global_buf->gl_pixwidth = x->gl_pixwidth; + global_buf->gl_pixheight = x->gl_pixheight; + global_buf->gl_x1 = x->gl_x1; + global_buf->gl_y1 = x->gl_y1; + global_buf->gl_x2 = x->gl_x2; + global_buf->gl_y2 = x->gl_y2; + global_buf->gl_screenx1 = x->gl_screenx1; + global_buf->gl_screeny1 = x->gl_screeny1; + global_buf->gl_screenx2 = x->gl_screenx2; + global_buf->gl_screeny2 = x->gl_screeny2; + global_buf->gl_xmargin = x->gl_xmargin; + global_buf->gl_ymargin = x->gl_ymargin; + global_buf->gl_goprect = x->gl_goprect; + global_buf->gl_isgraph = x->gl_isgraph; + global_buf->gl_hidetext = x->gl_hidetext; + //} - return (&global_buf); + return (global_buf); } extern int gfxstub_haveproperties(void *key); @@ -1196,7 +1214,7 @@ extern int gfxstub_haveproperties(void *key); static void canvas_undo_canvas_apply(t_canvas *x, void *z, int action) { t_undo_canvas_properties *buf = z; - t_undo_canvas_properties tmp; + t_undo_canvas_properties *tmp; if (!x->gl_edit) canvas_editmode(x, 1); @@ -1206,25 +1224,29 @@ static void canvas_undo_canvas_apply(t_canvas *x, void *z, int action) //close properties window first t_int properties = gfxstub_haveproperties((void *)x); if (properties) { + fprintf(stderr,"have it\n"); sys_vgui("destroy .gfxstub%lx\n", properties); } + //create a temporary data holder + tmp = (t_undo_canvas_properties *)getbytes(sizeof(*tmp)); + //store current canvas values into temporary data holder - tmp.gl_pixwidth = x->gl_pixwidth; - tmp.gl_pixheight = x->gl_pixheight; - tmp.gl_x1 = x->gl_x1; - tmp.gl_y1 = x->gl_y1; - tmp.gl_x2 = x->gl_x2; - tmp.gl_y2 = x->gl_y2; - tmp.gl_screenx1 = x->gl_screenx1; - tmp.gl_screeny1 = x->gl_screeny1; - tmp.gl_screenx2 = x->gl_screenx2; - tmp.gl_screeny2 = x->gl_screeny2; - tmp.gl_xmargin = x->gl_xmargin; - tmp.gl_ymargin = x->gl_ymargin; - tmp.gl_goprect = x->gl_goprect; - tmp.gl_isgraph = x->gl_isgraph; - tmp.gl_hidetext = x->gl_hidetext; + tmp->gl_pixwidth = x->gl_pixwidth; + tmp->gl_pixheight = x->gl_pixheight; + tmp->gl_x1 = x->gl_x1; + tmp->gl_y1 = x->gl_y1; + tmp->gl_x2 = x->gl_x2; + tmp->gl_y2 = x->gl_y2; + tmp->gl_screenx1 = x->gl_screenx1; + tmp->gl_screeny1 = x->gl_screeny1; + tmp->gl_screenx2 = x->gl_screenx2; + tmp->gl_screeny2 = x->gl_screeny2; + tmp->gl_xmargin = x->gl_xmargin; + tmp->gl_ymargin = x->gl_ymargin; + tmp->gl_goprect = x->gl_goprect; + tmp->gl_isgraph = x->gl_isgraph; + tmp->gl_hidetext = x->gl_hidetext; //change canvas values with the ones from the undo buffer x->gl_pixwidth = buf->gl_pixwidth; @@ -1244,21 +1266,24 @@ static void canvas_undo_canvas_apply(t_canvas *x, void *z, int action) x->gl_hidetext = buf->gl_hidetext; //copy data values from the temporary data to the undo buffer - buf->gl_pixwidth = tmp.gl_pixwidth; - buf->gl_pixheight = tmp.gl_pixheight; - buf->gl_x1 = tmp.gl_x1; - buf->gl_y1 = tmp.gl_y1; - buf->gl_x2 = tmp.gl_x2; - buf->gl_y2 = tmp.gl_y2; - buf->gl_screenx1 = tmp.gl_screenx1; - buf->gl_screeny1 = tmp.gl_screeny1; - buf->gl_screenx2 = tmp.gl_screenx2; - buf->gl_screeny2 = tmp.gl_screeny2; - buf->gl_xmargin = tmp.gl_xmargin; - buf->gl_ymargin = tmp.gl_ymargin; - buf->gl_goprect = tmp.gl_goprect; - buf->gl_isgraph = tmp.gl_isgraph; - buf->gl_hidetext = tmp.gl_hidetext; + buf->gl_pixwidth = tmp->gl_pixwidth; + buf->gl_pixheight = tmp->gl_pixheight; + buf->gl_x1 = tmp->gl_x1; + buf->gl_y1 = tmp->gl_y1; + buf->gl_x2 = tmp->gl_x2; + buf->gl_y2 = tmp->gl_y2; + buf->gl_screenx1 = tmp->gl_screenx1; + buf->gl_screeny1 = tmp->gl_screeny1; + buf->gl_screenx2 = tmp->gl_screenx2; + buf->gl_screeny2 = tmp->gl_screeny2; + buf->gl_xmargin = tmp->gl_xmargin; + buf->gl_ymargin = tmp->gl_ymargin; + buf->gl_goprect = tmp->gl_goprect; + buf->gl_isgraph = tmp->gl_isgraph; + buf->gl_hidetext = tmp->gl_hidetext; + + //delete temporary data holder + t_freebytes(tmp, sizeof(*tmp)); //redraw canvas_setgraph(x, x->gl_isgraph, 0); @@ -1268,6 +1293,7 @@ static void canvas_undo_canvas_apply(t_canvas *x, void *z, int action) } if (x->gl_owner && glist_isvisible(x->gl_owner)) { + //fprintf(stderr,"we got gop\n"); glist_noselect(x); gobj_vis(&x->gl_gobj, x->gl_owner, 0); gobj_vis(&x->gl_gobj, x->gl_owner, 1); @@ -1276,17 +1302,13 @@ static void canvas_undo_canvas_apply(t_canvas *x, void *z, int action) //update scrollbars when GOP potentially exceeds window size t_canvas *canvas=(t_canvas *)glist_getcanvas(x); //if gop is being disabled go one level up - if (!x->gl_isgraph && x->gl_owner) { - canvas=canvas->gl_owner; - canvas_redraw(canvas); - } - sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", (t_int)x); + if (!x->gl_isgraph) canvas=canvas->gl_owner; sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", (t_int)canvas); } else if (action == UNDO_FREE) { - //do nothing since undo apply uses a global_buf struct rather than a pointer + t_freebytes(buf, sizeof(*buf)); } } @@ -1295,89 +1317,6 @@ void canvas_canvas_setundo(t_canvas *x) canvas_setundo(x, canvas_undo_canvas_apply, canvas_undo_set_canvas(x), "apply"); } -/* --------- 8. create ----------- */ - -typedef struct _undo_create -{ - int u_index; /* index of the created object object */ - t_binbuf *u_objectbuf; /* the object cleared or typed into */ - t_binbuf *u_reconnectbuf; /* connections into and out of object */ -} t_undo_create; - -void *canvas_undo_set_create(t_canvas *x) -{ - t_gobj *y, *last; - t_linetraverser t; - t_outconnect *oc; - - t_undo_create *buf = (t_undo_create *)getbytes(sizeof(*buf)); - buf->u_index = glist_getindex(x, 0) - 1; - int nnotsel= glist_selectionindex(x, 0, 0); - - buf->u_objectbuf = binbuf_new(); - if (x->gl_list) { - for (y = x->gl_list; y; y = y->g_next) - { - if (glist_isselected(x, y)) { - gobj_save(y, buf->u_objectbuf); - } - } - } - buf->u_reconnectbuf = binbuf_new(); - linetraverser_start(&t, x); - if (linetraverser_next(&t)) { - while (oc = linetraverser_next(&t)) - { - int issel1 = glist_isselected(x, &t.tr_ob->ob_g); - int issel2 = glist_isselected(x, &t.tr_ob2->ob_g); - if (issel1 != issel2) - { - binbuf_addv(buf->u_reconnectbuf, "ssiiii;", - gensym("#X"), gensym("connect"), - (issel1 ? nnotsel : 0) - + glist_selectionindex(x, &t.tr_ob->ob_g, issel1), - t.tr_outno, - (issel2 ? nnotsel : 0) + - glist_selectionindex(x, &t.tr_ob2->ob_g, issel2), - t.tr_inno); - } - } - } - return (buf); -} - -void canvas_undo_create(t_canvas *x, void *z, int action) -{ - t_undo_create *buf = z; - t_gobj *y; - - //fprintf(stderr,"canvas = %lx buf->u_index = %d\n", (t_int)x, buf->u_index); - - if (action == UNDO_UNDO) - { - glist_noselect(x); - y = glist_nth(x, buf->u_index); - glist_select(x, y); - canvas_doclear(x); - } - else if (action == UNDO_REDO) - { - pd_bind(&x->gl_pd, gensym("#X")); - binbuf_eval(buf->u_objectbuf, 0, 0, 0); - pd_unbind(&x->gl_pd, gensym("#X")); - pd_bind(&x->gl_pd, gensym("#X")); - binbuf_eval(buf->u_reconnectbuf, 0, 0, 0); - pd_unbind(&x->gl_pd, gensym("#X")); - y = glist_nth(x, buf->u_index); - glist_select(x, y); - } - else if (action == UNDO_FREE) { - binbuf_free(buf->u_objectbuf); - binbuf_free(buf->u_reconnectbuf); - t_freebytes(buf, sizeof(*buf)); - } -} - /* ------------------------ event handling ------------------------ */ static char *cursorlist[] = { @@ -1522,10 +1461,10 @@ void canvas_destroy_editor(t_glist *x) if (ob = pd_checkobject(&y->g_pd)) rtext_free(glist_findrtext(x, ob)); } - //if (x->gl_editor) { - editor_free(x->gl_editor, x); - x->gl_editor = 0; - //} + if (x->gl_editor) { + editor_free(x->gl_editor, x); + x->gl_editor = 0; + } } } @@ -1683,14 +1622,11 @@ void canvas_setgraph(t_glist *x, int flag, int nogoprect) canvas_destroy_editor(x); x->gl_isgraph = 0; x->gl_hidetext = 0; - //x->gl_editor = 0; if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner)) { gobj_vis(&x->gl_gobj, x->gl_owner, 1); canvas_fixlinesfor(x->gl_owner, &x->gl_obj); } - //if (x->gl_havewindow && hadeditor) - // canvas_editmode(x, 1); } else if (flag) { @@ -1831,7 +1767,6 @@ static void canvas_donecanvasdialog(t_glist *x, canvas_setgraph(x, graphme, 0); canvas_dirty(x, 1); if (x->gl_havewindow) { - //fprintf(stderr,"donecanvasdialog canvas_redraw\n"); canvas_redraw(x); } else if (x->gl_owner && glist_isvisible(x->gl_owner)) @@ -3293,62 +3228,56 @@ void canvas_restoreconnections(t_canvas *x) static t_binbuf *canvas_docopy(t_canvas *x) { - //fprintf(stderr,"canvas_docopy\n"); + //fprintf(stderr,"docopy\n"); t_gobj *y, *last; t_linetraverser t; t_outconnect *oc; t_binbuf *b = binbuf_new(); + //int c = 0; for (y = x->gl_list; y; y = y->g_next) { if (glist_isselected(x, y)) { - //fprintf(stderr,"saving object\n"); + //c++; + //fprintf(stderr, "saving object num %d\n", c); + //fprintf(stderr, "saving object >.x%lx<\n", (t_int)y); + /* introduce redundant comment to avoid recreation of old abstractions + with the same canvas id which results in all commands being registered + multiple times--apparently after much searching it appears that this + is yet another bug in tcl/tk which means that canvas tries to do some + kind of caching behind the curtains resulting in objects not always + having unique ids, contrary to tcl/tk's canvas man page */ + /*if (c==1) { + binbuf_addv(b, "ssiis;", gensym("#X"), gensym("text"), + (int)((t_text *)y)->te_xpix-30, (int)((t_text *)y)->te_ypix-30, gensym("tcltksucks")); + }*/ gobj_save(y, b); } } + //fprintf(stderr,"done saving objects\n"); linetraverser_start(&t, x); + //c = 0; while (oc = linetraverser_next(&t)) { - //fprintf(stderr,"found some lines %d %d\n", glist_isselected(x, &t.tr_ob->ob_g), glist_isselected(x, &t.tr_ob2->ob_g)); if (glist_isselected(x, &t.tr_ob->ob_g) && glist_isselected(x, &t.tr_ob2->ob_g)) { - //fprintf(stderr,"saving lines leading into selected object\n"); + //fprintf(stderr, "lines need to be copied\n"); + //c = 1; binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"), glist_selectionindex(x, &t.tr_ob->ob_g, 1), t.tr_outno, glist_selectionindex(x, &t.tr_ob2->ob_g, 1), t.tr_inno); +// glist_selectionindex(x, &t.tr_ob->ob_g, 1)+1, t.tr_outno, +// glist_selectionindex(x, &t.tr_ob2->ob_g, 1)+1, t.tr_inno); } } + //if (!c) fprintf(stderr, "no lines copied\n"); return (b); } -static void canvas_copyfromexternalbuffer(t_canvas *x, t_symbol *s, int ac, t_atom *av) -{ - if (!x->gl_editor) - return; - /* - if (ac == 0) { - //fprintf(stderr,"init\n"); - copyfromexternalbuffer = 1; - binbuf_free(copy_binbuf); - copy_binbuf = binbuf_new(); - } else { - if (av[0].a_type == A_SYMBOL && strcmp(av[0].a_w.w_symbol->s_name, "#N")) { - //fprintf(stderr,"fill %d\n", ac); - binbuf_add(copy_binbuf, ac, av); - binbuf_addsemi(copy_binbuf); - } else { - //probably should resize window size and position here... - //fprintf(stderr,"ignoring canvas\n"); - } - } - */ -} - static void canvas_copy(t_canvas *x) { if (!x->gl_editor || !x->gl_editor->e_selection) return; - copyfromexternalbuffer = 0; binbuf_free(copy_binbuf); //fprintf(stderr, "canvas_copy\n"); copy_binbuf = canvas_docopy(x); @@ -3473,7 +3402,7 @@ static void canvas_cut(t_canvas *x) if (x->gl_editor && x->gl_editor->e_selectedline) canvas_clearline(x); /* if we are cutting text */ - else if (x->gl_editor && x->gl_editor->e_textedfor) + else if (x->gl_editor->e_textedfor) { char *buf; int bufsize; @@ -3629,7 +3558,7 @@ static void canvas_dopaste(t_canvas *x, t_binbuf *b) //reset canvas_undo_already_set_move canvas_undo_already_set_move = 0; } - else if (canvas_undo_name && !strcmp(canvas_undo_name, "paste") && !copyfromexternalbuffer) { + else if (canvas_undo_name && !strcmp(canvas_undo_name, "paste") ) { canvas_paste_atmouse(x); //fprintf(stderr,"doing a paste\n"); } @@ -3772,10 +3701,6 @@ extern t_class *text_class; void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno, t_floatarg fwhoin, t_floatarg finno) { - if (!x->gl_list) { - post("paste error: no objects to connect, probably incomplete clipboard copy from an external source (e.g. from a text editor)"); - return; - } int whoout = fwhoout, outno = foutno, whoin = fwhoin, inno = finno; t_gobj *src = 0, *sink = 0; t_object *objsrc, *objsink; @@ -4144,8 +4069,6 @@ void g_editor_setup(void) gensym("donecanvasdialog"), A_GIMME, A_NULL); class_addmethod(canvas_class, (t_method)glist_arraydialog, gensym("arraydialog"), A_GIMME, A_NULL); - class_addmethod(canvas_class, (t_method)canvas_copyfromexternalbuffer, - gensym("copyfromexternalbuffer"), A_GIMME, A_NULL); /* -------------- connect method used in reading files ------------------ */ class_addmethod(canvas_class, (t_method)canvas_connect, diff --git a/src/g_editor_patch b/src/g_editor_patch new file mode 100644 index 0000000000000000000000000000000000000000..8011283ac8426be58b64372b8fd1815ee79e106f --- /dev/null +++ b/src/g_editor_patch @@ -0,0 +1,31 @@ +--- g_editor.c.old 2011-02-17 20:02:34.000000000 -0500 ++++ g_editor.c 2011-02-18 13:02:41.000000000 -0500 +@@ -240,6 +240,8 @@ + { + if (x->gl_editor) + { ++ if (c_selection && c_selection != x) ++ glist_noselect(c_selection); + t_selection *sel = (t_selection *)getbytes(sizeof(*sel)); + if (x->gl_editor->e_selectedline) + glist_deselectline(x); +@@ -3211,7 +3213,10 @@ + int dspstate = canvas_suspend_dsp(), nbox, count; + + canvas_editmode(x, 1.); +- glist_noselect(x); ++ if (c_selection && c_selection != x) ++ glist_noselect(c_selection); ++ else ++ glist_noselect(x); + for (g2 = x->gl_list, nbox = 0; g2; g2 = g2->g_next) nbox++; + + /* found the end of the queue */ +@@ -3296,7 +3301,6 @@ + } else { + canvas_setundo(x, canvas_undo_paste, canvas_undo_set_paste(x), + "duplicate"); +- glist_noselect(c_selection); + canvas_dopaste(x, copy_binbuf); + //canvas_paste_xyoffset(x); + canvas_dirty(x, 1); diff --git a/src/g_graph.c b/src/g_graph.c index f48b0f114c840ee7c6acbd336ca10e7023eeea05..3ac48c68ac35fa8bf38ac6b41da882e459f011b9 100644 --- a/src/g_graph.c +++ b/src/g_graph.c @@ -29,27 +29,17 @@ void canvas_drawredrect(t_canvas *x, int doit); void glist_add(t_glist *x, t_gobj *y) { - //fprintf(stderr,"glist_add %lx %d\n", (t_int)x, (x->gl_editor ? 1 : 0)); - t_object *ob; + t_object *ob; y->g_next = 0; - int index = 0; - if (!x->gl_list) x->gl_list = y; else { t_gobj *y2; - for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next) - index++; + for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next); y2->g_next = y; } - if (x->gl_editor && (ob = pd_checkobject(&y->g_pd))) { + if (x->gl_editor && (ob = pd_checkobject(&y->g_pd))) rtext_new(x, ob); - //let's now set up create undo - //glist_select(x, y); - //canvas_setundo(x, canvas_undo_create, canvas_undo_set_create(x, index), - // "create"); - //glist_noselect(x); - } if (x->gl_editor && x->gl_isgraph && !x->gl_goprect && pd_checkobject(&y->g_pd)) { @@ -79,86 +69,74 @@ void canvas_closebang(t_canvas *x); /* delete an object from a glist and free it */ void glist_delete(t_glist *x, t_gobj *y) { - if (x->gl_list) { - - t_gobj *g; - t_object *ob; - t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp")); - t_canvas *canvas = glist_getcanvas(x); - int drawcommand = class_isdrawcommand(y->g_pd); - int wasdeleting; - - if (pd_class(&y->g_pd) == canvas_class) { - /* JMZ: send a closebang to the canvas */ - canvas_closebang((t_canvas *)y); - } - - wasdeleting = canvas_setdeleting(canvas, 1); - if (x->gl_editor) - { - if (x->gl_editor->e_grab == y) x->gl_editor->e_grab = 0; - if (glist_isselected(x, y)) glist_deselect(x, y); - - /* HACK -- we had phantom outlets not getting erased on the - screen because the canvas_setdeleting() mechanism is too - crude. LATER carefully set up rules for when the rtexts - should exist, so that they stay around until all the - steps of becoming invisible are done. In the meantime, just - zap the inlets and outlets here... */ - if (pd_class(&y->g_pd) == canvas_class) - { - t_glist *gl = (t_glist *)y; - if (gl->gl_isgraph) - { - char tag[80]; - //sprintf(tag, "graph%lx", (t_int)gl); - //t_glist *yy = (t_glist *)y; - sprintf(tag, "%s", rtext_gettag(glist_findrtext(x, &gl->gl_obj))); - glist_eraseiofor(x, &gl->gl_obj, tag); - text_eraseborder(&gl->gl_obj, x, - rtext_gettag(glist_findrtext(x, &gl->gl_obj))); - } - else - { - text_eraseborder(&gl->gl_obj, x, - rtext_gettag(glist_findrtext(x, &gl->gl_obj))); - } - } - } - /* if we're a drawing command, erase all scalars now, before deleting - it; we'll redraw them once it's deleted below. */ - if (drawcommand) - canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym( - glist_getcanvas(x)->gl_name)), 2); - if (glist_isvisible(canvas)) - gobj_vis(y, x, 0); - if (x->gl_editor && (ob = pd_checkobject(&y->g_pd))) - rtext_new(x, ob); - if (x->gl_list == y) { - if (y->g_next) - x->gl_list = y->g_next; - else - x->gl_list = NULL; - } - else for (g = x->gl_list; g; g = g->g_next) - { - if (g->g_next == y) - { - if (y->g_next) - g->g_next = y->g_next; - else g->g_next = NULL; - break; - } - } - gobj_delete(y, x); - pd_free(&y->g_pd); - if (chkdsp) canvas_update_dsp(); - if (drawcommand) - canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym( - glist_getcanvas(x)->gl_name)), 1); - canvas_setdeleting(canvas, wasdeleting); - x->gl_valid = ++glist_valid; - } + t_gobj *g; + t_object *ob; + t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp")); + t_canvas *canvas = glist_getcanvas(x); + int drawcommand = class_isdrawcommand(y->g_pd); + int wasdeleting; + + if (pd_class(&y->g_pd) == canvas_class) { + /* JMZ: send a closebang to the canvas */ + canvas_closebang((t_canvas *)y); + } + + wasdeleting = canvas_setdeleting(canvas, 1); + if (x->gl_editor) + { + if (x->gl_editor->e_grab == y) x->gl_editor->e_grab = 0; + if (glist_isselected(x, y)) glist_deselect(x, y); + + /* HACK -- we had phantom outlets not getting erased on the + screen because the canvas_setdeleting() mechanism is too + crude. LATER carefully set up rules for when the rtexts + should exist, so that they stay around until all the + steps of becoming invisible are done. In the meantime, just + zap the inlets and outlets here... */ + if (pd_class(&y->g_pd) == canvas_class) + { + t_glist *gl = (t_glist *)y; + if (gl->gl_isgraph) + { + char tag[80]; + //sprintf(tag, "graph%lx", (t_int)gl); + //t_glist *yy = (t_glist *)y; + sprintf(tag, "%s", rtext_gettag(glist_findrtext(x, &gl->gl_obj))); + glist_eraseiofor(x, &gl->gl_obj, tag); + text_eraseborder(&gl->gl_obj, x, + rtext_gettag(glist_findrtext(x, &gl->gl_obj))); + } + else + { + text_eraseborder(&gl->gl_obj, x, + rtext_gettag(glist_findrtext(x, &gl->gl_obj))); + } + } + } + /* if we're a drawing command, erase all scalars now, before deleting + it; we'll redraw them once it's deleted below. */ + if (drawcommand) + canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym( + glist_getcanvas(x)->gl_name)), 2); + if (glist_isvisible(canvas)) + gobj_vis(y, x, 0); + if (x->gl_editor && (ob = pd_checkobject(&y->g_pd))) + rtext_new(x, ob); + if (x->gl_list == y) x->gl_list = y->g_next; + else for (g = x->gl_list; g; g = g->g_next) + if (g->g_next == y) + { + g->g_next = y->g_next; + break; + } + gobj_delete(y, x); + pd_free(&y->g_pd); + if (chkdsp) canvas_update_dsp(); + if (drawcommand) + canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym( + glist_getcanvas(x)->gl_name)), 1); + canvas_setdeleting(canvas, wasdeleting); + x->gl_valid = ++glist_valid; } /* remove every object from a glist. Experimental. */ diff --git a/src/g_magicglass.c.orig b/src/g_magicglass.c.orig new file mode 100644 index 0000000000000000000000000000000000000000..2b30e528f0f85fb844431a70fa2810fe10c83c0c --- /dev/null +++ b/src/g_magicglass.c.orig @@ -0,0 +1,432 @@ +#include "m_pd.h" +#include <stdio.h> +#include "string.h" +#include "m_pd.h" +#include "m_imp.h" +#include "s_stuff.h" +#define MG_CLOCK_CLEAR_DELAY 500.5 +#define MG_CLOCK_FLASH_DELAY 50 +#define MG_SAMPLE_COUNT 2205 + +EXTERN int glist_getfont(t_glist *x); + +t_class *magicGlass_class; + +typedef struct _magicGlass +{ + t_object x_obj; + t_object *x_connectedObj; + int x_connectedOutno; + int x_visible; + char x_string[4096]; + char x_old_string[4096]; + int x_x; + int x_y; + int x_c; + float x_sigF; + int x_dspOn; + int x_viewOn; + float x_maxSample; + int x_sampleCount; + t_clock *x_clearClock; + t_clock *x_flashClock; + unsigned int x_maxSize; + unsigned int x_issignal; + int x_display_font; +} t_magicGlass; + +void magicGlass_clearText(t_magicGlass *x); + +void magicGlass_bind(t_magicGlass *x, t_object *obj, int outno) +{ + //fprintf(stderr,"magicglass_bind\n"); + if (x->x_connectedObj != obj) + { + if (x->x_connectedObj) + { + obj_disconnect(x->x_connectedObj, + x->x_connectedOutno, + &x->x_obj, + 0); + } + x->x_connectedObj = obj; + x->x_connectedOutno = outno; + x->x_maxSize = 1; + magicGlass_clearText(x); + obj_connect(obj, outno, &x->x_obj, 0); + } +} + +void magicGlass_unbind(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_unbind\n"); + if (x->x_connectedObj) + { + obj_disconnect(x->x_connectedObj, + x->x_connectedOutno, + &x->x_obj, + 0); + } + x->x_dspOn = 0; + x->x_maxSample = -999999; + x->x_sampleCount = 0; + x->x_connectedObj = NULL; + x->x_connectedOutno = 0; + x->x_maxSize = 1; +} + +void magicGlass_updateText(t_magicGlass *x, int moved) +{ + //fprintf(stderr,"magicglass_updateText\n"); + int bgSize; + /* change second argument (10.0) to provide optimal scaling in the following entry */ + float font = (float)(sys_hostfontsize(glist_getfont((t_glist *)(x->x_c))))/10.0; + if (font <= 1.0) { + x->x_display_font = 9; + font = 1.0; + } else { + x->x_display_font = sys_hostfontsize(glist_getfont((t_glist *)(x->x_c))); + } + + if (x->x_visible) + { + if (!moved) { + char *color; + if (x->x_issignal || strcmp(x->x_old_string, x->x_string)) { + color = "#ffffff"; + } + else { + color = "#e87216"; + clock_delay(x->x_flashClock, MG_CLOCK_FLASH_DELAY); + } + sys_vgui(".x%x.c itemconfigure magicGlassText -text {%s} -fill %s\n", + x->x_c, + x->x_string, + color); + } else { + sys_vgui(".x%x.c itemconfigure magicGlassText -text {%s}\n", + x->x_c, + x->x_string); + } + + if (strlen(x->x_string) > 0) + { + if (strlen(x->x_string) > x->x_maxSize) x->x_maxSize = strlen(x->x_string); + } + bgSize = x->x_x + (int)((30.0 * font) + ((font * 7.0) * (float)x->x_maxSize)); + sys_vgui(".x%x.c coords magicGlassText %d %d\n", + x->x_c, + x->x_x + 20, + x->x_y); + sys_vgui(".x%x.c coords magicGlassLine %d %d %d %d %d %d\n", + x->x_c, + x->x_x + 3, + x->x_y, + x->x_x + 13, + x->x_y + 5, + x->x_x + 13, + x->x_y - 5); + sys_vgui(".x%x.c coords magicGlassBg %d %d %d %d\n", + x->x_c, + x->x_x + 13, + x->x_y - (int)(12.0 * font), + bgSize, + x->x_y + (int)(12.0 * font)); + } +} + +void magicGlass_drawNew(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_drawNew\n"); + sys_vgui(".x%x.c create rectangle 0 0 0 0 -outline #ffffff -fill #000000 -tags magicGlassBg\n", + x->x_c); + sys_vgui(".x%x.c create polygon 0 0 0 0 0 0 -fill #000000 -width 4 -tags magicGlassLine\n", + x->x_c); + sys_vgui(".x%x.c create text 0 0 -text {} -anchor w -fill #e87216 -font {{%s} %d %s} -tags magicGlassText\n", + x->x_c, sys_font, x->x_display_font, sys_fontweight); + sys_vgui(".x%x.c raise magicGlassBg\n", + x->x_c); + sys_vgui(".x%x.c raise magicGlassText\n", + x->x_c); + magicGlass_updateText(x, 0); + clock_delay(x->x_flashClock, MG_CLOCK_FLASH_DELAY); +} + +void magicGlass_undraw(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_undraw\n"); + sys_vgui(".x%x.c delete magicGlassBg\n", x->x_c); + sys_vgui(".x%x.c delete magicGlassLine\n", x->x_c); + sys_vgui(".x%x.c delete magicGlassText\n", x->x_c); +} + +void magicGlass_flashText(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_flashText\n"); + sys_vgui(".x%x.c itemconfigure magicGlassText -fill #ffffff\n", + x->x_c); +} + +void magicGlass_clearText(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_clearText\n"); + strcpy(x->x_old_string, x->x_string); + x->x_string[0] = 0; + magicGlass_updateText(x, 0); +} + +void magicGlass_bang(t_magicGlass *x) +{ + x->x_issignal = 0; + strcpy(x->x_old_string, x->x_string); + strcpy(x->x_string, "bang"); + magicGlass_updateText(x, 0); + clock_delay(x->x_clearClock, MG_CLOCK_CLEAR_DELAY); +} + +void magicGlass_float(t_magicGlass *x, t_float f) +{ + x->x_issignal = 0; + strcpy(x->x_old_string, x->x_string); + sprintf(x->x_string, "%g", f); + magicGlass_updateText(x, 0); + clock_delay(x->x_clearClock, MG_CLOCK_CLEAR_DELAY); +} + +void magicGlass_symbol(t_magicGlass *x, t_symbol *sym) +{ + x->x_issignal = 0; + strcpy(x->x_old_string, x->x_string); + sprintf(x->x_string, "symbol %s", sym->s_name); + magicGlass_updateText(x, 0); + clock_delay(x->x_clearClock, MG_CLOCK_CLEAR_DELAY); +} + +void magicGlass_anything(t_magicGlass *x, t_symbol *sym, int argc, t_atom *argv) +{ + char aString[4096]; + char valueString[4096]; + int i; + + x->x_issignal = 0; + + strcpy(x->x_old_string, x->x_string); + strcpy(aString, sym->s_name); + valueString[0] = 0; + for (i = 0; i < argc; i++) + { + if (argv[i].a_type == A_SYMBOL) + { + sprintf(valueString, " %s", argv[i].a_w.w_symbol->s_name); + strcat(aString, valueString); + } + else if (argv[i].a_type == A_FLOAT) + { + sprintf(valueString, " %g", argv[i].a_w.w_float); + strcat(aString, valueString); + } + } + strcpy(x->x_string, aString); + magicGlass_updateText(x, 0); + clock_delay(x->x_clearClock, MG_CLOCK_CLEAR_DELAY); +} + +void magicGlass_list(t_magicGlass *x, t_symbol *sym, int argc, t_atom *argv) +{ + char aString[4096]; + char valueString[4096]; + int i; + + x->x_issignal = 0; + + aString[0] = 0; + valueString[0] = 0; + + strcpy(x->x_old_string, x->x_string); + strcpy(aString, sym->s_name); + for (i = 0; i < argc; i++) + { + if (argv[i].a_type == A_SYMBOL) + { + sprintf(valueString, " %s", argv[i].a_w.w_symbol->s_name); + strcat(aString, valueString); + } + else if (argv[i].a_type == A_FLOAT) + { + sprintf(valueString, " %g", argv[i].a_w.w_float); + strcat(aString, valueString); + } + } + strcpy(x->x_string, aString); + magicGlass_updateText(x, 0); + clock_delay(x->x_clearClock, MG_CLOCK_CLEAR_DELAY); +} + +void magicGlass_setCanvas(t_magicGlass *x, int c) +{ + x->x_c = c; +} + +void magicGlass_show(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_show\n"); + if (!x->x_visible) { + x->x_sampleCount = 0; + x->x_maxSample = -999999; + x->x_string[0] = 0; + x->x_visible = 1; + magicGlass_drawNew(x); + } +} + +void magicGlass_hide(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_hide\n"); + if (x->x_visible) { + magicGlass_undraw(x); + x->x_sampleCount = 0; + x->x_maxSample = -999999; + x->x_string[0] = 0; + x->x_visible = 0; + } +} + +void magicGlass_moveText(t_magicGlass *x, int pX, int pY) +{ + //fprintf(stderr,"magicglass_moveText\n"); + int bgSize; + + x->x_x = pX; + x->x_y = pY; + magicGlass_updateText(x, 1); +} + +int magicGlass_bound(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_bound\n"); + if (x->x_connectedObj) + return 1; + else + return 0; +} + +int magicGlass_isOn(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_isOn\n"); + if (x->x_viewOn) + return 1; + else + return 0; +} + +void magicGlass_setOn(t_magicGlass *x, int i) +{ + //fprintf(stderr,"magicglass_setOn\n"); + if (i) + { + x->x_viewOn = 1; + } + else + { + x->x_viewOn = 0; + } +} + +void magicGlass_setDsp(t_magicGlass *x, int i) +{ + //fprintf(stderr,"magicglass_setDsp\n"); + if (i != x->x_dspOn) { + if (i) + { + x->x_dspOn = 1; + x->x_sampleCount = 0; + x->x_maxSample = -999999; + } + else + { + x->x_dspOn = 0; + } + } +} + +t_int *magicGlass_perform(t_int *w) +{ + t_magicGlass *x = (t_magicGlass *)(w[1]); + if (x->x_dspOn && x->x_connectedObj) + { + //fprintf(stderr,"magicglass_perform\n"); + float *in = (float *)(w[2]); + int N = (int)(w[3]); + int i; + for (i = 0; i < N; i++) + { + if (in[i] > x->x_maxSample) + x->x_maxSample = in[i]; + x->x_sampleCount++; + if (x->x_sampleCount >= MG_SAMPLE_COUNT) + { + sprintf(x->x_string, "~ %g", x->x_maxSample); + magicGlass_updateText(x, 0); + x->x_maxSample = -999999; + x->x_sampleCount = 0; + } + } + } + return (w + 4); +} + +void magicGlass_dsp(t_magicGlass *x, t_signal **sp) +{ + //fprintf(stderr,"magicglass_dsp\n"); + dsp_add(magicGlass_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); + x->x_issignal = 1; +} + +void *magicGlass_new(int c) +{ + //fprintf(stderr,"magicglass_new\n"); + t_magicGlass *x = (t_magicGlass *)pd_new(magicGlass_class); + x->x_connectedObj= NULL; + x->x_connectedOutno = 0; + x->x_visible = 0; + x->x_c = c; + x->x_sigF = 0; + x->x_dspOn = 0; + x->x_viewOn = 0; + x->x_maxSample = -999999; + x->x_sampleCount = 0; + x->x_clearClock = clock_new(x, (t_method)magicGlass_clearText); + x->x_flashClock = clock_new(x, (t_method)magicGlass_flashText); + x->x_maxSize = 1; + x->x_issignal = 0; + x->x_display_font = 9; + return x; +} + +void magicGlass_free(t_magicGlass *x) +{ + //fprintf(stderr,"magicglass_free\n"); + x->x_dspOn = 0; + clock_free(x->x_clearClock); +} + +void magicGlass_setup(void) +{ + magicGlass_class = class_new(gensym("magicGlass"), + 0, + (t_method)magicGlass_free, + sizeof(t_magicGlass), + 0, + A_DEFFLOAT, + 0); + CLASS_MAINSIGNALIN(magicGlass_class, t_magicGlass, x_sigF); + class_addmethod(magicGlass_class, + (t_method)magicGlass_dsp, + gensym("dsp"), + 0); + class_addbang(magicGlass_class, (t_method)magicGlass_bang); + class_addfloat(magicGlass_class, (t_method)magicGlass_float); + class_addsymbol(magicGlass_class, (t_method)magicGlass_symbol); + class_addanything(magicGlass_class, (t_method)magicGlass_anything); + class_addlist(magicGlass_class, (t_method)magicGlass_list); +} diff --git a/src/g_magicglass.h.orig b/src/g_magicglass.h.orig new file mode 100644 index 0000000000000000000000000000000000000000..b6a80fd2a5f7ba47ac203632b3296ab8c54f0ff1 --- /dev/null +++ b/src/g_magicglass.h.orig @@ -0,0 +1,19 @@ +EXTERN void magicGlass_bind(t_magicGlass *x, t_object *obj, int outno); +EXTERN void magicGlass_unbind(t_magicGlass *x); +EXTERN void magicGlass_bang(t_magicGlass *x); +EXTERN void magicGlass_float(t_magicGlass *x, t_float f); +EXTERN void magicGlass_symbol(t_magicGlass *x, t_symbol *sym); +EXTERN void magicGlass_anything(t_magicGlass *x, t_symbol *sym, int argc, t_atom *argv); +EXTERN void magicGlass_list(t_magicGlass *x, t_symbol *sym, int argc, t_atom *argv); +EXTERN void magicGlass_setCanvas(t_magicGlass *x, int c); +EXTERN void magicGlass_show(t_magicGlass *x); +EXTERN void magicGlass_hide(t_magicGlass *x); +EXTERN void magicGlass_moveText(t_magicGlass *x, int pX, int pY); +EXTERN int magicGlass_bound(t_magicGlass *x); +EXTERN int magicGlass_isOn(t_magicGlass *x); +EXTERN void magicGlass_setOn(t_magicGlass *x, int i); +EXTERN void magicGlass_setDsp(t_magicGlass *x, int i); +EXTERN void *magicGlass_new(int c); +EXTERN void magicGlass_free(t_magicGlass *x); +EXTERN void magicGlass_setup(void); + diff --git a/src/g_rtext.c b/src/g_rtext.c index a8efb11d29a87490c21769ce3f2bc1876afc9631..163615161198b0abf804b53afa4cdf0227a7b73c 100644 --- a/src/g_rtext.c +++ b/src/g_rtext.c @@ -358,9 +358,8 @@ t_rtext *glist_findrtext(t_glist *gl, t_text *who) t_rtext *x; if (!gl->gl_editor) canvas_create_editor(gl); - if (gl->gl_editor->e_rtext) - for (x = gl->gl_editor->e_rtext; x && x->x_text != who; x = x->x_next) - ; + for (x = gl->gl_editor->e_rtext; x && x->x_text != who; x = x->x_next) + ; if (!x) bug("glist_findrtext"); return (x); } diff --git a/src/g_text.c b/src/g_text.c index 104fa3d1cc25598151d0fb3dbb3e5dea4a669415..0ff6a3980e6c0aa3f06484f6916fabc791319e08 100644 --- a/src/g_text.c +++ b/src/g_text.c @@ -30,10 +30,7 @@ t_widgetbehavior text_widgetbehavior; static char *invalid_fill = "\"#ffdddd\""; -extern void canvas_apply_setundo(t_canvas *x, t_gobj *y); -extern void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf, const char *name); -extern void *canvas_undo_set_create(t_canvas *x); -extern void canvas_undo_create(t_canvas *x, void *z, int action); +EXTERN void canvas_apply_setundo(t_canvas *x, t_gobj *y); /* ----------------- the "text" object. ------------------ */ @@ -92,7 +89,7 @@ void canvas_getargs(int *argcp, t_atom **argvp); static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected, t_binbuf *b) { - //fprintf(stderr,"canvas_objtext\n"); + //fprintf(stderr,"objtext\n"); t_text *x; int argc; t_atom *argv; @@ -205,7 +202,6 @@ void canvas_howputnew(t_canvas *x, int *connectp, int *xpixp, int *ypixp, void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv) { - //fprintf(stderr,"canvas_obj\n"); t_text *x; if (argc >= 2) { @@ -228,7 +224,6 @@ void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv) if (connectme) canvas_connect(gl, indx, 0, nobj, 0); else canvas_startmotion(glist_getcanvas(gl)); - canvas_setundo(glist_getcanvas(gl), canvas_undo_create, canvas_undo_set_create(gl), "create"); } } @@ -270,7 +265,6 @@ void canvas_iemguis(t_glist *gl, t_symbol *guiobjname) //glist_getnextxy(gl, &xpix, &ypix); //canvas_objtext(gl, xpix, ypix, 1, b); else canvas_startmotion(glist_getcanvas(gl)); - canvas_setundo(glist_getcanvas(gl), canvas_undo_create, canvas_undo_set_create(gl), "create"); } void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv) @@ -541,7 +535,6 @@ void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv) if (connectme) canvas_connect(gl, indx, 0, nobj, 0); else canvas_startmotion(glist_getcanvas(gl)); - canvas_setundo(glist_getcanvas(gl), canvas_undo_create, canvas_undo_set_create(gl), "create"); } } @@ -928,7 +921,6 @@ static void gatom_vis(t_gobj *z, t_glist *glist, int vis) void canvas_atom(t_glist *gl, t_atomtype type, t_symbol *s, int argc, t_atom *argv) { - //fprintf(stderr,"canvas_atom\n"); t_gatom *x = (t_gatom *)pd_new(gatom_class); t_atom at; x->a_text.te_width = 0; /* don't know it yet. */ @@ -1001,7 +993,6 @@ void canvas_atom(t_glist *gl, t_atomtype type, if (connectme) canvas_connect(gl, indx, 0, nobj, 0); else canvas_startmotion(glist_getcanvas(gl)); - canvas_setundo(glist_getcanvas(gl), canvas_undo_create, canvas_undo_set_create(gl), "create"); } } diff --git a/src/m_binbuf.c b/src/m_binbuf.c index 6c7a8af943ad426601c081465b72df21a5e66c6f..d39e18821e5532bab424439f94fb40f5a98e680c 100644 --- a/src/m_binbuf.c +++ b/src/m_binbuf.c @@ -39,7 +39,6 @@ void binbuf_free(t_binbuf *x) { t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec)); t_freebytes(x, sizeof(*x)); - x = NULL; } t_binbuf *binbuf_duplicate(t_binbuf *y) @@ -60,7 +59,6 @@ void binbuf_clear(t_binbuf *x) /* convert text to a binbuf */ void binbuf_text(t_binbuf *x, char *text, size_t size) { - //fprintf(stderr, "current text: %s || %c %d %d\n", text, text[size-1], strlen(text), (int)size); char buf[MAXPDSTRING+1], *bufp, *ebuf = buf+MAXPDSTRING; const char *textp = text, *etext = text+size; t_atom *ap; @@ -387,7 +385,6 @@ void binbuf_addsemi(t_binbuf *x) t_atom a; SETSEMI(&a); binbuf_add(x, 1, &a); - binbuf_add(x, 1, '\0'); } /* Supply atoms to a binbuf from a message, making the opposite changes diff --git a/src/m_class.c b/src/m_class.c index 1dd0c9f9e783cba28ea310760c9cfdcf497790e9..abb9561cce6b0ca8f7e416d0cc8fe83867cc78d6 100644 --- a/src/m_class.c +++ b/src/m_class.c @@ -708,8 +708,8 @@ void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv) return; } for (i = c->c_nmethod, m = c->c_methods; i--; m++) - //if (m->me_name == s) - if (m && m->me_name == s) + if (m->me_name == s) + //if (m && m->me_name == s) { //fprintf(stderr,"me_name %s\n", m->me_name); wp = m->me_arg; diff --git a/src/m_obj.c b/src/m_obj.c index 393b159628c0e07ee0be3a3d8d576e7d611d4790..71166aca4a9b18f90915f76de7939ce75f9f751c 100644 --- a/src/m_obj.c +++ b/src/m_obj.c @@ -554,11 +554,10 @@ done: int obj_noutlets(t_object *x) { - int n = 0; + int n; t_outlet *o; - if (x && x->ob_outlet) - for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++; - return (n); + for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++; + return (n); } int obj_ninlets(t_object *x) diff --git a/src/m_pd.h b/src/m_pd.h index 8fc774716c759dfbf9fcc86da68e726b9530dbed..81e440765d42f4d063ba8c4a6baf3671c3d99e45 100644 --- a/src/m_pd.h +++ b/src/m_pd.h @@ -11,7 +11,7 @@ extern "C" { #define PD_MAJOR_VERSION 0 #define PD_MINOR_VERSION 42 #define PD_BUGFIX_VERSION 5 -#define PD_TEST_VERSION "extended-l2ork-20111025" +#define PD_TEST_VERSION "extended-l2ork-20110920" /* 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/src/main.pd b/src/main.pd new file mode 100644 index 0000000000000000000000000000000000000000..2c0dccfdc79df0c0de7d118efb435a94c688b6bc --- /dev/null +++ b/src/main.pd @@ -0,0 +1,7 @@ +#N canvas 718 319 450 300 10; +#X floatatom 152 85 5 0 0 0 - - -; +#N canvas 473 357 450 300 something 0; +#X floatatom 126 128 5 0 0 0 - - -; +#X coords 0 -1 1 1 85 60 1 100 100; +#X restore 232 145 pd something; +#X obj 235 244; diff --git a/src/makefile b/src/makefile deleted file mode 100644 index 3ebb96a298798ac94cae5d8d5c811aa08e72bbb8..0000000000000000000000000000000000000000 --- a/src/makefile +++ /dev/null @@ -1,311 +0,0 @@ -# On Mac OS X, this needs to be defined to enable dlopen and weak linking -# support. Its safe on other platforms since gcc only checks this env var on -# Apple's gcc. <hans@at.or.at> -ifeq ($(shell uname -s),Darwin) -export MACOSX_DEPLOYMENT_TARGET = 10.3 -endif - -VPATH = ../obj:./ -OBJ_DIR = ../obj -BIN_DIR = ../bin -PDEXEC = $(BIN_DIR)/pd-l2ork -EXT= pd_linux -GUINAME= pd-gui - -prefix = /usr/local -exec_prefix = ${prefix} -bindir = ${exec_prefix}/bin -includedir = ${prefix}/include -libdir = ${exec_prefix}/lib -mandir = ${prefix}/share/man - -GFLAGS = -DINSTALL_PREFIX=\"$(prefix)\" - -# varibles to match packages/Makefile.buildlayout so that they can be easily -# overridden when building Pd-extended builds. <hans@at.or.at> -libpddir = $(libdir)/pd-l2ork -pddocdir = $(libpddir)/doc -libpdbindir = $(libpddir)/bin - -CPPFLAGS = -DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD -DUSEAPI_OSS -fno-strict-aliasing -DPA_USE_ALSA -DUSEAPI_ALSA -MORECFLAGS = -O6 -funroll-loops -fomit-frame-pointer -DUSEAPI_JACK -D_LARGEFILE64_SOURCE -# if on 10.6/Intel, then build GUI as 32-bit -ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 10) - GINCLUDE = -arch i386 $(CPPFLAGS) -framework Tcl -framework Tk -else - GINCLUDE = $(CPPFLAGS) -I/usr/include/tcl8.5 -endif -GLIB = -ltk8.5 -ltcl8.5 -lrt -ljack -ljack - -LDFLAGS = -Wl,-export-dynamic -lasound -lrt -ljack -LIB = -ldl -lm -lpthread -lasound - -WARN_CFLAGS = -Wall -W -Wstrict-prototypes \ - -Wno-unused -Wno-parentheses -Wno-switch -ARCH_CFLAGS = -DPD - -CFLAGS = -g -O2 $(ARCH_CFLAGS) $(WARN_CFLAGS) $(CPPFLAGS) $(MORECFLAGS) - -# the sources - -SYSSRC += s_midi_oss.c s_audio_oss.c s_audio_alsa.c s_audio_alsamm.c s_midi_alsa.c s_audio_jack.c d_fft_mayer.c d_fftroutine.c - -ASIOSRC = - -ASIOOBJ = $(ASIOSRC:.cpp=.o) - -# these files cause a warning when using auto-vectorization: -# "warning: dereferencing type-punned pointer will break strict-aliasing rules" -TYPE_PUNNING_SRC = d_ctl.c d_array.c d_delay.c d_filter.c d_math.c d_osc.c d_soundfile.c - -# these are safe for full gcc 4.x optimization -OPT_SAFE_SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ - g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \ - g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ - g_toggle.c g_vdial.c g_vslider.c g_vumeter.c g_magicglass.c \ - m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ - m_conf.c m_glob.c m_sched.c \ - s_main.c s_inter.c s_file.c s_print.c \ - s_loader.c s_path.c s_entry.c s_audio.c s_midi.c \ - d_ugen.c d_arithmetic.c d_dac.c d_misc.c \ - d_fft.c d_global.c \ - d_resample.c \ - x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \ - x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c x_list.c \ - import.c \ - $(SYSSRC) - -SRC = $(TYPE_PUNNING_SRC) $(OPT_SAFE_SRC) - -TYPE_PUNNING_OBJ = $(TYPE_PUNNING_SRC:.c=.o) -OPT_SAFE_OBJ = $(OPT_SAFE_SRC:.c=.o) -OBJ = $(SRC:.c=.o) - -GSRC = t_main.c t_tkcmd.c - -GOBJ = $(GSRC:.c=.o) - -# get version from m_pd.h to use in doc/1.manual/1.introduction.txt -PD_MAJOR_VERSION := $(shell grep PD_MAJOR_VERSION m_pd.h | \ - sed 's|^.define *PD_MAJOR_VERSION *\([0-9]*\).*|\1|' ) -PD_MINOR_VERSION := $(shell grep PD_MINOR_VERSION m_pd.h | \ - sed 's|^.define *PD_MINOR_VERSION *\([0-9]*\).*|\1|' ) -PD_BUGFIX_VERSION := $(shell grep PD_BUGFIX_VERSION m_pd.h | \ - sed 's|^.define *PD_BUGFIX_VERSION *\([0-9]*\).*|\1|' ) -PD_TEST_VERSION := $(shell grep PD_TEST_VERSION m_pd.h | \ - sed 's|^.define *PD_TEST_VERSION *"\(.*\)".*|\1|' ) -PD_VERSION := $(PD_MAJOR_VERSION).$(PD_MINOR_VERSION).$(PD_BUGFIX_VERSION) -ifneq ($(PD_TEST_VERSION),) - PD_VERSION := $(PD_VERSION)-$(PD_TEST_VERSION) -endif - -# -# ------------------ targets ------------------------------------ -# - -.PHONY: pd gui externs all - -all: pd $(BIN_DIR)/pd-watchdog gui $(BIN_DIR)/pdsend \ - $(BIN_DIR)/pdreceive externs - -bin: pd $(BIN_DIR)/pd-watchdog gui $(BIN_DIR)/pdsend \ - $(BIN_DIR)/pdreceive - -$(OPT_SAFE_OBJ) : %.o : %.c - $(CC) $(CFLAGS) $(OPT_CFLAGS) $(GFLAGS) $(INCLUDE) -c -o $(OBJ_DIR)/$*.o $*.c - -$(TYPE_PUNNING_OBJ) : %.o : %.c - $(CC) $(CFLAGS) $(GFLAGS) $(INCLUDE) -c -o $(OBJ_DIR)/$*.o $*.c - -$(GOBJ) : %.o : %.c - $(CC) $(CFLAGS) $(GFLAGS) $(GINCLUDE) -c -o $(OBJ_DIR)/$*.o $*.c - -$(ASIOOBJ): %.o : %.cpp - $(CXX) $(CFLAGS) $(INCLUDE) -c -o $(OBJ_DIR)/$*.o $*.cpp - -pd: $(PDEXEC) - -ifneq ($(GSRC),) -gui: $(BIN_DIR)/$(GUINAME) -else -gui: -endif - -pd-watchdog: $(BIN_DIR)/pd-watchdog - -$(BIN_DIR): - test -d $(BIN_DIR) || mkdir -p $(BIN_DIR) - -$(BIN_DIR)/pd-watchdog: s_watchdog.c $(BIN_DIR) - $(CC) $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pd-watchdog s_watchdog.c - -$(BIN_DIR)/pdsend: u_pdsend.c $(BIN_DIR) - $(CC) $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pdsend u_pdsend.c - -$(BIN_DIR)/pdreceive: u_pdreceive.c $(BIN_DIR) - $(CC) $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pdreceive u_pdreceive.c - -$(PDEXEC): $(OBJ) $(BIN_DIR) - cd ../obj; $(CC) $(LDFLAGS) $(DBG_CFLAGS) -o $(PDEXEC) $(OBJ) $(LIB) - -$(BIN_DIR)/pd-gui: $(GOBJ) $(GSRC) - cd ../obj; $(CC) $(INCLUDE) -o $(BIN_DIR)/$(GUINAME) $(GOBJ) $(GLIB) - -# if on 10.6/Intel, then force build GUI as 32-bit -ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 10) - ARCH_FLAG = -arch i386 -else - ARCH_FLAG = -endif -#this is for Max OSX only... -$(BIN_DIR)/libPdTcl.dylib: $(GOBJ) $(GSRC) - cd ../obj && $(CC) $(ARCH_FLAG) $(CFLAGS) -dynamiclib -read_only_relocs warning \ - -o $(BIN_DIR)/libPdTcl.dylib $(GOBJ) \ - -F \ - -framework Tcl -framework Tk -framework System \ - -Wl,-install_name,@executable_path/../Resources/bin/libPdTcl.dylib - install_name_tool -change /Tcl.framework/Versions/8.4/Tcl\ - @executable_path/../Frameworks/Tcl.framework/Versions/8.4/Tcl \ - -change /Tk.framework/Versions/8.4/Tk \ - @executable_path/../Frameworks/Tk.framework/Versions/8.4/Tk \ - ../bin/libPdTcl.dylib - -# this is for Windows/MinGW (only?) -$(BIN_DIR)/pdtcl.dll: $(GOBJ) - cd $(BIN_DIR); dllwrap --export-all-symbols --output-def pdtcl.def \ - --output-lib=pdtcl.a --dllname=$(GUINAME) $(OBJ_DIR)/t_tkcmd.o $(LIB) $(GLIB) - strip --strip-unneeded $(BIN_DIR)/pdtcl.dll - -externs: - make -C ../extra/bonk~ - make -C ../extra/choice - make -C ../extra/expr~ - make -C ../extra/fiddle~ - make -C ../extra/loop~ - make -C ../extra/lrshift~ - make -C ../extra/pique - make -C ../extra/sigmund~ - make -C ../extra/pd~ - make -C ../extra/stdout - -BINARYMODE=-m755 - -ABOUT_FILE=$(DESTDIR)$(pddocdir)/1.manual/1.introduction.txt -install: all - install -d $(DESTDIR)$(libpdbindir) - install $(BIN_DIR)/$(GUINAME) $(DESTDIR)$(libpdbindir)/$(GUINAME) - install $(BIN_DIR)/pd-watchdog $(DESTDIR)$(libpdbindir)/pd-watchdog - install -m644 pd.tk $(DESTDIR)$(libpdbindir)/pd.tk - install -m644 pkgIndex.tcl $(DESTDIR)$(libpdbindir)/pkgIndex.tcl - install -m644 helpbrowser.tcl $(DESTDIR)$(libpdbindir)/helpbrowser.tcl - install -d $(DESTDIR)$(bindir) - install $(BINARYMODE) $(PDEXEC) $(DESTDIR)$(bindir)/pd-l2ork -# kludge to allow pd~ to work by default in pd-l2ork - rm -f $(DESTDIR)$(libpddir)/pd - ln -s $(bindir)/pd-l2ork $(DESTDIR)$(libpddir)/pd - install -m755 $(BIN_DIR)/pdsend $(DESTDIR)$(bindir)/pdsend - install -m755 $(BIN_DIR)/pdreceive $(DESTDIR)$(bindir)/pdreceive - for dir in $(shell ls -1 ../doc | grep -v CVS); do \ - echo "installing $$dir"; \ - install -d $(DESTDIR)$(pddocdir)/$$dir ; \ - install -m644 -p ../doc/$$dir/*.* $(DESTDIR)$(pddocdir)/$$dir ; \ - done - for dir in $(shell ls -1 ../doc/7.stuff | grep -v CVS); do \ - echo "installing 7.stuff/$$dir"; \ - install -d $(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ - install -m644 -p ../doc/7.stuff/$$dir/*.* \ - $(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ - done - mv $(ABOUT_FILE) $(ABOUT_FILE).tmp - cat $(ABOUT_FILE).tmp | sed 's|PD_VERSION|Pd version $(PD_VERSION)|' \ - > $(ABOUT_FILE) - rm $(ABOUT_FILE).tmp - rsync -ax --exclude=.git --exclude=.svn ../extra $(DESTDIR)$(libpddir)/ - install -d $(DESTDIR)$(includedir)/pdl2ork - install -m644 m_pd.h $(DESTDIR)$(includedir)/pdl2ork/m_pd.h - install -m644 m_imp.h $(DESTDIR)$(includedir)/pdl2ork/m_imp.h - install -m644 g_canvas.h $(DESTDIR)$(includedir)/pdl2ork/g_canvas.h - install -m644 s_stuff.h $(DESTDIR)$(includedir)/pdl2ork/s_stuff.h - install -m644 g_all_guis.h $(DESTDIR)$(includedir)/pdl2ork/g_all_guis.h - install -d $(DESTDIR)$(mandir)/man1 - gzip < ../man/pd.1 > $(DESTDIR)$(mandir)/man1/pd-l2ork.1.gz - chmod 644 $(DESTDIR)$(mandir)/man1/pd-l2ork.1.gz - gzip < ../man/pdsend.1 > $(DESTDIR)$(mandir)/man1/pdsend.1.gz - chmod 644 $(DESTDIR)$(mandir)/man1/pdsend.1.gz - gzip < ../man/pdreceive.1 > $(DESTDIR)$(mandir)/man1/pdreceive.1.gz - chmod 644 $(DESTDIR)$(mandir)/man1/pdreceive.1.gz - @echo "Pd install succeeded." - -local-clean: - -rm -f -- $(OBJ) - -rm -f ../obj/* $(PDEXEC) $(BIN_DIR)/$(GUINAME) $(BIN_DIR)/pdsend \ - $(BIN_DIR)/pdreceive $(BIN_DIR)/pd-watchdog m_stamp.c - -rm -f -- *~ - -(cd ../doc/6.externs; rm -f *.pd_linux) - -rm -f makefile.dependencies - touch makefile.dependencies - chmod 666 makefile.dependencies - -extra-clean: - -rm -f `find ../extra/ -name "*.pd_*"` - -rm -f tags - -clean: extra-clean local-clean - -distclean: clean - -rm -f config.cache config.log config.status makefile tags \ - autom4te.cache/output.* autom4te.cache/traces.* autom4te.cache/requests - -rmdir autom4te.cache - -rm -rf autom4te-*.cache - -tags: $(SRC) $(GSRC); ctags *.[ch] - -depend: makefile.dependencies - -makefile.dependencies: makefile - $(CC) $(CPPFLAGS) -M $(SRC) > makefile.dependencies - -uninstall: - rm -f -r $(DESTDIR)$(libpddir) - rm -f $(DESTDIR)$(bindir)/pd-l2ork - rm -f $(DESTDIR)$(bindir)/pdsend - rm -f $(DESTDIR)$(bindir)/pdreceive - rm -f $(DESTDIR)$(includedir)/m_pd.h - rm -f $(DESTDIR)$(includedir)/m_imp.h - rm -f $(DESTDIR)$(includedir)/s_stuff.h - rm -f $(DESTDIR)$(includedir)/g_all_guis.h - rm -f $(DESTDIR)$(includedir)/g_canvas. - rm -f $(DESTDIR)$(mandir)/man1/pd.1.gz - rm -f $(DESTDIR)$(mandir)/man1/pdsend.1.gz - rm -f $(DESTDIR)$(mandir)/man1/pdreceive.1.gz - -include makefile.dependencies - - -TAGS: etags - -etags: - etags *.h $(SRC) $(SYSSRC) - etags --append --language=none --regex="/proc[ \t]+\([^ \t]+\)/\1/" pd.tk *.tcl - find /usr/include -type f -name \*.h -exec etags -a '{}' \; - make etags_`uname -s` - -etags_Darwin: - find /System/Library/Frameworks -type f -name \*.h -exec etags -a '{}' \; - find /Library/Frameworks -type f -name \*.h -exec etags -a '{}' \; - find /sw/include -type f -name \*.h -exec etags -a '{}' \; - -etags_Linux: - -etags_MINGW: - find /usr/local/include/ -type f -name \*.h -exec etags -a '{}' \; - - - - - - - - - - diff --git a/src/makefile.dependencies b/src/makefile.dependencies index 255b80c76e3603d93b3fe8fba92db0372004e465..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/src/makefile.dependencies +++ b/src/makefile.dependencies @@ -1,1132 +0,0 @@ -d_ctl.o: d_ctl.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/math.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h -d_array.o: d_array.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/endian.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h -d_delay.o: d_delay.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/string.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/xlocale.h /usr/include/stdio.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h -d_filter.o: d_filter.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/math.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h -d_math.o: d_math.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/math.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h /usr/include/sys/types.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h -d_osc.o: d_osc.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/math.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h -d_soundfile.o: d_soundfile.c config.h /usr/include/unistd.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/pthread.h \ - /usr/include/sched.h /usr/include/bits/sched.h /usr/include/xlocale.h \ - /usr/include/signal.h /usr/include/bits/setjmp.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/errno.h /usr/include/bits/errno.h \ - /usr/include/linux/errno.h /usr/include/asm/errno.h \ - /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ - m_pd.h -g_canvas.o: g_canvas.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h m_pd.h \ - m_imp.h s_stuff.h g_magicglass.h g_canvas.h /usr/include/string.h \ - /usr/include/xlocale.h g_all_guis.h -g_graph.o: g_graph.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h m_pd.h m_imp.h t_tk.h g_canvas.h s_stuff.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h -g_text.o: g_text.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h m_pd.h m_imp.h s_stuff.h t_tk.h g_canvas.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/math.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h -g_rtext.o: g_rtext.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h m_imp.h s_stuff.h g_canvas.h t_tk.h -g_array.o: g_array.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h m_pd.h \ - g_canvas.h /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h -g_template.o: g_template.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h m_pd.h \ - s_stuff.h g_canvas.h -g_io.o: g_io.c m_pd.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - g_canvas.h /usr/include/string.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/xlocale.h -g_scalar.o: g_scalar.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h m_pd.h \ - g_canvas.h -g_traversal.o: g_traversal.c /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h m_pd.h \ - g_canvas.h -g_guiconnect.o: g_guiconnect.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h g_canvas.h -g_readwrite.o: g_readwrite.c /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h m_pd.h \ - g_canvas.h /usr/include/string.h /usr/include/xlocale.h -g_editor.o: g_editor.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h m_pd.h \ - m_imp.h s_stuff.h g_magicglass.h g_canvas.h /usr/include/string.h \ - /usr/include/xlocale.h -g_all_guis.o: g_all_guis.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_bang.o: g_bang.c config.h /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_hdial.o: g_hdial.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_hslider.o: g_hslider.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_mycanvas.o: g_mycanvas.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_numbox.o: g_numbox.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_toggle.o: g_toggle.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_vdial.o: g_vdial.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h -g_vslider.o: g_vslider.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_vumeter.o: g_vumeter.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h m_pd.h g_canvas.h t_tk.h g_all_guis.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -g_magicglass.o: g_magicglass.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h m_imp.h s_stuff.h \ - g_magicglass.h -m_pd.o: m_pd.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h m_pd.h m_imp.h g_canvas.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h -m_class.o: m_class.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h m_imp.h s_stuff.h \ - /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/sys/types.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h /usr/include/string.h \ - /usr/include/xlocale.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h -m_obj.o: m_obj.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h m_imp.h -m_atom.o: m_atom.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h -m_memory.o: m_memory.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - m_pd.h m_imp.h -m_binbuf.o: m_binbuf.c config.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h m_pd.h s_stuff.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/string.h /usr/include/xlocale.h -m_conf.o: m_conf.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h -m_glob.o: m_glob.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h m_imp.h -m_sched.o: m_sched.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h m_imp.h s_stuff.h \ - /usr/include/pthread.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sched.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/include/bits/sched.h /usr/include/bits/time.h \ - /usr/include/xlocale.h /usr/include/signal.h /usr/include/bits/sigset.h \ - /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h -s_main.o: s_main.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h m_imp.h s_stuff.h \ - /usr/include/sys/types.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/sys/stat.h /usr/include/bits/stat.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed/limits.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed/syslimits.h \ - /usr/include/limits.h /usr/include/bits/posix1_lim.h \ - /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ - /usr/include/bits/posix2_lim.h /usr/include/string.h \ - /usr/include/xlocale.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/stdlib.h \ - /usr/include/alloca.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ - /usr/include/getopt.h -s_inter.o: s_inter.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h m_imp.h \ - g_canvas.h /usr/include/unistd.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/bits/confname.h /usr/include/getopt.h \ - /usr/include/sys/socket.h /usr/include/sys/uio.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/uio.h /usr/include/bits/socket.h \ - /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ - /usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \ - /usr/include/asm-generic/sockios.h /usr/include/netinet/in.h \ - /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/bits/in.h \ - /usr/include/netinet/tcp.h /usr/include/netdb.h /usr/include/rpc/netdb.h \ - /usr/include/bits/netdb.h /usr/include/stdlib.h /usr/include/alloca.h \ - /usr/include/sys/time.h /usr/include/sys/mman.h /usr/include/bits/mman.h \ - /usr/include/sys/resource.h /usr/include/bits/resource.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h /usr/include/signal.h \ - /usr/include/bits/signum.h /usr/include/bits/siginfo.h \ - /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h \ - /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h \ - /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/string.h \ - /usr/include/xlocale.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/execinfo.h /usr/include/sched.h /usr/include/bits/sched.h -s_file.o: s_file.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h \ - /usr/include/string.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/xlocale.h /usr/include/stdlib.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/errno.h /usr/include/bits/errno.h \ - /usr/include/linux/errno.h /usr/include/asm/errno.h \ - /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h \ - /usr/include/sys/stat.h /usr/include/bits/stat.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h -s_print.o: s_print.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/stdlib.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h s_stuff.h -s_loader.o: s_loader.c /usr/include/dlfcn.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/bits/dlfcn.h /usr/include/stdlib.h /usr/include/sys/types.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h \ - /usr/include/sys/stat.h /usr/include/bits/stat.h /usr/include/string.h \ - /usr/include/xlocale.h m_pd.h s_stuff.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h -s_path.o: s_path.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ - /usr/include/getopt.h /usr/include/sys/stat.h /usr/include/bits/stat.h \ - /usr/include/string.h /usr/include/xlocale.h m_pd.h m_imp.h s_stuff.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/ctype.h -s_entry.o: s_entry.c -s_audio.o: s_audio.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h \ - /usr/include/stdio.h /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h \ - /usr/include/sys/time.h /usr/include/time.h /usr/include/bits/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/sys/resource.h \ - /usr/include/bits/resource.h /usr/include/stdlib.h \ - /usr/include/sys/types.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/errno.h /usr/include/bits/errno.h \ - /usr/include/linux/errno.h /usr/include/asm/errno.h \ - /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h -s_midi.o: s_midi.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h m_imp.h \ - /usr/include/unistd.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/bits/confname.h /usr/include/getopt.h \ - /usr/include/sys/time.h /usr/include/time.h /usr/include/bits/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/signal.h /usr/include/bits/signum.h \ - /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \ - /usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \ - /usr/include/bits/pthreadtypes.h /usr/include/bits/sigthread.h -d_ugen.o: d_ugen.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h m_imp.h \ - /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/sys/types.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/time.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h -d_arithmetic.o: d_arithmetic.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h -d_dac.o: d_dac.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h -d_misc.o: d_misc.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h -d_fft.o: d_fft.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h -d_global.o: d_global.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/string.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/xlocale.h -d_resample.o: d_resample.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h -x_arithmetic.o: x_arithmetic.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/math.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h -x_connective.o: x_connective.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/string.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/xlocale.h /usr/include/stdio.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h -x_interface.o: x_interface.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h -x_midi.o: x_midi.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h -x_misc.o: x_misc.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h \ - /usr/include/math.h /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h /usr/include/stdio.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ - /usr/include/getopt.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/sys/time.h \ - /usr/include/sys/times.h /usr/include/sys/param.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed/limits.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed/syslimits.h \ - /usr/include/limits.h /usr/include/bits/posix1_lim.h \ - /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ - /usr/include/bits/posix2_lim.h /usr/include/linux/param.h \ - /usr/include/asm/param.h /usr/include/asm-generic/param.h -x_time.o: x_time.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h -x_acoustics.o: x_acoustics.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/math.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/huge_val.h /usr/include/bits/huge_valf.h \ - /usr/include/bits/huge_vall.h /usr/include/bits/inf.h \ - /usr/include/bits/nan.h /usr/include/bits/mathdef.h \ - /usr/include/bits/mathcalls.h -x_net.o: x_net.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h \ - /usr/include/sys/types.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/sys/socket.h \ - /usr/include/sys/uio.h /usr/include/bits/uio.h \ - /usr/include/bits/socket.h /usr/include/bits/sockaddr.h \ - /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ - /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ - /usr/include/netinet/in.h /usr/include/stdint.h \ - /usr/include/bits/wchar.h /usr/include/bits/in.h \ - /usr/include/netinet/tcp.h /usr/include/netdb.h /usr/include/rpc/netdb.h \ - /usr/include/bits/netdb.h /usr/include/stdio.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h -x_qlist.o: x_qlist.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/string.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/xlocale.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/bits/confname.h \ - /usr/include/getopt.h -x_gui.o: x_gui.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/confname.h \ - /usr/include/getopt.h -x_list.o: x_list.c config.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h /usr/include/malloc.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/stdio.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/alloca.h -import.o: import.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h g_canvas.h \ - /usr/include/stdio.h /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h -s_midi_oss.o: s_midi_oss.c config.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdlib.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/sys/stat.h /usr/include/bits/stat.h \ - /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h m_pd.h s_stuff.h -s_audio_oss.o: s_audio_oss.c /usr/include/linux/soundcard.h \ - /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \ - /usr/include/asm-generic/ioctl.h /usr/include/endian.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/linux/patchkey.h m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h s_stuff.h \ - /usr/include/errno.h /usr/include/bits/errno.h \ - /usr/include/linux/errno.h /usr/include/asm/errno.h \ - /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ - /usr/include/stdio.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/libio.h \ - /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdlib.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/sys/time.h \ - /usr/include/sys/stat.h /usr/include/bits/stat.h \ - /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \ - /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \ - /usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h \ - /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/sys/mman.h \ - /usr/include/bits/mman.h -s_audio_alsa.o: s_audio_alsa.c /usr/include/alsa/asoundlib.h \ - /usr/include/unistd.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/assert.h /usr/include/sys/poll.h \ - /usr/include/bits/poll.h /usr/include/errno.h /usr/include/bits/errno.h \ - /usr/include/linux/errno.h /usr/include/asm/errno.h \ - /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ - /usr/include/alsa/asoundef.h /usr/include/alsa/version.h \ - /usr/include/alsa/global.h /usr/include/alsa/input.h \ - /usr/include/alsa/output.h /usr/include/alsa/error.h \ - /usr/include/alsa/conf.h /usr/include/alsa/pcm.h \ - /usr/include/alsa/rawmidi.h /usr/include/alsa/timer.h \ - /usr/include/alsa/hwdep.h /usr/include/alsa/control.h \ - /usr/include/alsa/mixer.h /usr/include/alsa/seq_event.h \ - /usr/include/alsa/seq.h /usr/include/alsa/seqmid.h \ - /usr/include/alsa/seq_midi_event.h m_pd.h s_stuff.h \ - /usr/include/sys/time.h /usr/include/sys/stat.h /usr/include/bits/stat.h \ - /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \ - /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \ - /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \ - /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \ - /usr/include/sys/ttydefaults.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/sys/mman.h \ - /usr/include/bits/mman.h s_audio_alsa.h -s_audio_alsamm.o: s_audio_alsamm.c /usr/include/alsa/asoundlib.h \ - /usr/include/unistd.h /usr/include/features.h \ - /usr/include/bits/predefs.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-32.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/assert.h /usr/include/sys/poll.h \ - /usr/include/bits/poll.h /usr/include/errno.h /usr/include/bits/errno.h \ - /usr/include/linux/errno.h /usr/include/asm/errno.h \ - /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ - /usr/include/alsa/asoundef.h /usr/include/alsa/version.h \ - /usr/include/alsa/global.h /usr/include/alsa/input.h \ - /usr/include/alsa/output.h /usr/include/alsa/error.h \ - /usr/include/alsa/conf.h /usr/include/alsa/pcm.h \ - /usr/include/alsa/rawmidi.h /usr/include/alsa/timer.h \ - /usr/include/alsa/hwdep.h /usr/include/alsa/control.h \ - /usr/include/alsa/mixer.h /usr/include/alsa/seq_event.h \ - /usr/include/alsa/seq.h /usr/include/alsa/seqmid.h \ - /usr/include/alsa/seq_midi_event.h m_pd.h s_stuff.h \ - /usr/include/sys/time.h /usr/include/sys/stat.h /usr/include/bits/stat.h \ - /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \ - /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \ - /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \ - /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \ - /usr/include/sys/ttydefaults.h /usr/include/sched.h \ - /usr/include/bits/sched.h s_audio_alsa.h -s_midi_alsa.o: s_midi_alsa.c config.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdlib.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/sys/stat.h /usr/include/bits/stat.h \ - /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/alsa/asoundlib.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/assert.h \ - /usr/include/sys/poll.h /usr/include/bits/poll.h \ - /usr/include/alsa/asoundef.h /usr/include/alsa/version.h \ - /usr/include/alsa/global.h /usr/include/alsa/input.h \ - /usr/include/alsa/output.h /usr/include/alsa/error.h \ - /usr/include/alsa/conf.h /usr/include/alsa/pcm.h \ - /usr/include/alsa/rawmidi.h /usr/include/alsa/timer.h \ - /usr/include/alsa/hwdep.h /usr/include/alsa/control.h \ - /usr/include/alsa/mixer.h /usr/include/alsa/seq_event.h \ - /usr/include/alsa/seq.h /usr/include/alsa/seqmid.h \ - /usr/include/alsa/seq_midi_event.h m_pd.h s_stuff.h -s_audio_jack.o: s_audio_jack.c -d_fft_mayer.o: d_fft_mayer.c m_pd.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h -d_fftroutine.o: d_fftroutine.c /usr/include/stdio.h \ - /usr/include/features.h /usr/include/bits/predefs.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/i486-linux-gnu/4.4.3/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/math.h /usr/include/bits/huge_val.h \ - /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \ - /usr/include/bits/inf.h /usr/include/bits/nan.h \ - /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \ - /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h m_pd.h diff --git a/src/pd.tk b/src/pd.tk index 0adbdb41e333b7c8c7e56566f2844812e33218f1..38ade0c3c0b3496dacfbaa88f906ad820b9f9678 100644 --- a/src/pd.tk +++ b/src/pd.tk @@ -330,8 +330,6 @@ set pointer_y_global 0 set copytexttocanvas 0 set global_clipboard 0 -# used for comparison to avoid redundant copyfromexternalbuffer -set last_clipboard 0 set global_selection 0 # x:y location tooltip during dragging @@ -1600,7 +1598,7 @@ proc menu_copy {name} { if {![string match .gfxstub* $name] && ![string match .printout* $name] && ![string match *entry $name]} { pd [concat $name copy \;] set copytexttocanvas 0 - clipboard clear + # clipboard clear } else { # pdtk_post "this_is_text\n" set copytexttocanvas 1 @@ -1614,12 +1612,12 @@ proc menu_paste {name} { # pdtk_post "pasting..." if {![string match .gfxstub* $name] && ![string match .printout* $name] && ![string match *entry $name]} { # puts stderr "this is not an entry $copytexttocanvas\n" - # if {$copytexttocanvas} { - # pdtk_pastetext - #} else { + if {$copytexttocanvas} { + pdtk_pastetext + } else { pd [concat $name paste \;] pdtk_canvas_getscroll $name.c - #} + } } else { # puts stderr "pasting text..." pdtk_pastetext @@ -1756,66 +1754,40 @@ proc menu_mycnv {name accel} { # correct edit menu, enabling or disabling undo/redo/cut/copy/paste proc menu_fixeditmenu {name} { - catch { - # pdtk_post "fixeditmenu $name\n" - - global pd_undoaction - global pd_redoaction - global pd_undocanvas - - global global_selection - global global_clipboard - global last_clipboard - - # investigate if we have already something copied from an external source - set current_clipboard 0 - catch {set current_clipboard [clipboard get]} - if {$current_clipboard != 0} { - # make sure the clipboard contents have not changed - if { [string compare $last_clipboard $current_clipboard] } { - set data [split $current_clipboard "\n"] - set first 0 - foreach line $data { - if { !$first } { - pd [concat $name copyfromexternalbuffer\;] - pd [concat $name copyfromexternalbuffer $line\;] - set first 1 - } else { - pd [concat $name copyfromexternalbuffer $line\;] - } - } - set global_clipboard 1 - set last_clipboard $current_clipboard - pdtk_canvas_update_edit_menu $name 1 - } - } + # pdtk_post "fixeditmenu $name\n" - # puts stderr [concat menu_fixeditmenu $name $pd_undocanvas $pd_undoaction] - if {$name == $pd_undocanvas && $pd_undoaction != "no"} { - $name.m.edit entryconfigure "Undo*" -state normal \ - -label [concat "Undo " $pd_undoaction] - } else { - $name.m.edit entryconfigure "Undo*" -state disabled -label "Undo" - } - if {$name == $pd_undocanvas && $pd_redoaction != "no"} { - $name.m.edit entryconfigure "Redo*" -state normal\ - -label [concat "Redo " $pd_redoaction] - } else { - $name.m.edit entryconfigure "Redo*" -state disabled - } + global pd_undoaction + global pd_redoaction + global pd_undocanvas - if {$global_selection == 1} { - $name.m.edit entryconfigure "Duplicate" -state normal - } else { - $name.m.edit entryconfigure "Duplicate" -state disabled - } + global global_selection + global global_clipboard - if {$global_clipboard == 1} { - $name.m.edit entryconfigure "Paste" -state normal - } else { - $name.m.edit entryconfigure "Paste" -state disabled - } - } + # puts stderr [concat menu_fixeditmenu $name $pd_undocanvas $pd_undoaction] + if {$name == $pd_undocanvas && $pd_undoaction != "no"} { + $name.m.edit entryconfigure "Undo*" -state normal \ + -label [concat "Undo " $pd_undoaction] + } else { + $name.m.edit entryconfigure "Undo*" -state disabled -label "Undo" + } + if {$name == $pd_undocanvas && $pd_redoaction != "no"} { + $name.m.edit entryconfigure "Redo*" -state normal\ + -label [concat "Redo " $pd_redoaction] + } else { + $name.m.edit entryconfigure "Redo*" -state disabled + } + + if {$global_selection == 1} { + $name.m.edit entryconfigure "Duplicate" -state normal + } else { + $name.m.edit entryconfigure "Duplicate" -state disabled + } + + if {$global_clipboard == 1} { + $name.m.edit entryconfigure "Paste" -state normal + } else { + $name.m.edit entryconfigure "Paste" -state disabled + } } # message from Pd to update the currently available undo/redo action @@ -2457,6 +2429,7 @@ proc pdtk_canvas_new {name width height geometry editable} { } bind $name.c <Map> {pdtk_canvas_map %W} bind $name.c <Unmap> {pdtk_canvas_unmap %W} + focus $name.c switch $pd_nt { 0 { bind $name.c <Button-4> "pdtk_canvas_scroll $name.c y -1" @@ -2481,7 +2454,6 @@ proc pdtk_canvas_new {name width height geometry editable} { set pdtk_canvas_mouseup_name "" bind $name <FocusIn> "menu_fixeditmenu $name" - focus $name } #### jsarlo ##### diff --git a/src/test.pd b/src/test.pd new file mode 100644 index 0000000000000000000000000000000000000000..bea66522bdb7a20b89eb047c3dd7958b6c18bedd --- /dev/null +++ b/src/test.pd @@ -0,0 +1,6 @@ +#N canvas 1 52 450 300 10; +#X obj 130 81 inlet; +#X obj 130 103 + 1; +#X obj 130 125 outlet; +#X connect 0 0 1 0; +#X connect 1 0 2 0; diff --git a/tcl/pd_menus.tcl~ b/tcl/pd_menus.tcl~ new file mode 100644 index 0000000000000000000000000000000000000000..94e6a9cd53961ccd5993352df948359ab8d2002a --- /dev/null +++ b/tcl/pd_menus.tcl~ @@ -0,0 +1,473 @@ +# Copyright (c) 1997-2009 Miller Puckette. +#(c) 2008 WordTech Communications LLC. License: standard Tcl license, http://www.tcl.tk/software/tcltk/license.html + +package provide pd_menus 0.1 + +package require pd_menucommands +package require Tk +#package require tile +## replace Tk widgets with Ttk widgets on 8.5 +#namespace import -force ttk::* + +# TODO figure out Undo/Redo/Cut/Copy/Paste state changes for menus +# TODO figure out parent window/window list for Window menu +# TODO what is the Tcl package constructor or init()? +# TODO $::pd_menus::menubar or .menubar globally? + +# since there is one menubar that is used for all windows, the menu -commands +# use {} quotes so that $::focused_window is interpreted when the menu item +# is called, not when the command is mapped to the menu item. This is the +# opposite of the 'bind' commands in pd_bindings.tcl + + +# ------------------------------------------------------------------------------ +# global variables + +# TODO this should properly be inside the pd_menus namespace, now it is global +namespace import ::pd_menucommands::* + +namespace eval ::pd_menus:: { + variable accelerator + variable menubar ".menubar" + variable current_toplevel ".pdwindow" + + namespace export create_menubar + namespace export configure_for_pdwindow + namespace export configure_for_canvas + namespace export configure_for_dialog + + # turn off tearoff menus globally + option add *tearOff 0 +} + +# ------------------------------------------------------------------------------ +# +proc ::pd_menus::create_menubar {} { + variable accelerator + variable menubar + if {$::windowingsystem eq "aqua"} { + set accelerator "Cmd" + } else { + set accelerator "Ctrl" + } + menu $menubar + set menulist "file edit put find media window help" + if { $::windowingsystem eq "aqua" } {create_apple_menu $menubar} + # FIXME why does the following (if uncommented) kill my menubar? + # if { $::windowingsystem eq "win32" } {create_system_menu $menubar} + foreach mymenu $menulist { + menu $menubar.$mymenu + $menubar add cascade -label [_ [string totitle $mymenu]] \ + -menu $menubar.$mymenu + [format build_%s_menu $mymenu] $menubar.$mymenu . + if {$::windowingsystem eq "win32"} { + # fix menu font size on Windows with tk scaling = 1 + $menubar.$mymenu configure -font menufont + } + } +} + +proc ::pd_menus::configure_for_pdwindow {} { + variable menubar + # these are meaningless for the Pd window, so disable them + set file_items_to_disable {"Save" "Save As..." "Print..." "Close"} + foreach menuitem $file_items_to_disable { + $menubar.file entryconfigure [_ $menuitem] -state disabled + } + set edit_items_to_disable {"Undo" "Redo" "Duplicate" "Tidy Up" "Edit Mode"} + foreach menuitem $edit_items_to_disable { + $menubar.edit entryconfigure [_ $menuitem] -state disabled + } + # disable everything on the Put menu + for {set i 0} {$i <= [$menubar.put index end]} {incr i} { + # catch errors that happen when trying to disable separators + catch {$menubar.put entryconfigure $i -state disabled } + } +} + +proc ::pd_menus::configure_for_canvas {mytoplevel} { + variable menubar + set file_items_to_disable {"Save" "Save As..." "Print..." "Close"} + foreach menuitem $file_items_to_disable { + $menubar.file entryconfigure [_ $menuitem] -state normal + } + set edit_items_to_disable {"Undo" "Redo" "Duplicate" "Tidy Up" "Edit Mode"} + foreach menuitem $edit_items_to_disable { + $menubar.edit entryconfigure [_ $menuitem] -state normal + } + for {set i 0} {$i <= [$menubar.put index end]} {incr i} { + # catch errors that happen when trying to disable separators + catch {$menubar.put entryconfigure $i -state normal } + } + # TODO set "Edit Mode" state using editmode($mytoplevel) +} + +proc ::pd_menus::configure_for_dialog {mytoplevel} { + variable menubar + # these are meaningless for the dialog panels, so disable them + set file_items_to_disable {"Save" "Save As..." "Print..." "Close"} + foreach menuitem $file_items_to_disable { + $menubar.file entryconfigure [_ $menuitem] -state disabled + } + set edit_items_to_disable {"Undo" "Redo" "Duplicate" "Tidy Up" "Edit Mode"} + foreach menuitem $edit_items_to_disable { + $menubar.edit entryconfigure [_ $menuitem] -state disabled + } + # disable everything on the Put menu + for {set i 0} {$i <= [$menubar.put index end]} {incr i} { + # catch errors that happen when trying to disable separators + catch {$menubar.put entryconfigure $i -state disabled } + } +} + + +# ------------------------------------------------------------------------------ +# menu building functions +proc ::pd_menus::build_file_menu {mymenu mytoplevel} { + [format build_file_menu_%s $::windowingsystem] $mymenu + $mymenu entryconfigure [_ "New"] -command {menu_new} + $mymenu entryconfigure [_ "Open"] -command {menu_open} + $mymenu entryconfigure [_ "Save"] -command {pdsend "$::focused_window menusave"} + $mymenu entryconfigure [_ "Save As..."] -command {pdsend "$::focused_window menusaveas"} + #$mymenu entryconfigure [_ "Revert*"] -command {menu_revert $current_toplevel} + $mymenu entryconfigure [_ "Close"] -command {pdsend "$::focused_window menuclose 0"} + $mymenu entryconfigure [_ "Message"] -command {menu_message_dialog} + $mymenu entryconfigure [_ "Print..."] -command {menu_print $::focused_window} +} + +proc ::pd_menus::build_edit_menu {mymenu mytoplevel} { + variable accelerator + $mymenu add command -label [_ "Undo"] -accelerator "$accelerator+Z" \ + -command {menu_undo $::focused_window} + $mymenu add command -label [_ "Redo"] -accelerator "Shift+$accelerator+Z" \ + -command {menu_redo $::focused_window} + $mymenu add separator + $mymenu add command -label [_ "Cut"] -accelerator "$accelerator+X" \ + -command {pdsend "$::focused_window cut"} + $mymenu add command -label [_ "Copy"] -accelerator "$accelerator+C" \ + -command {pdsend "$::focused_window copy"} + $mymenu add command -label [_ "Paste"] -accelerator "$accelerator+V" \ + -command {pdsend "$::focused_window paste"} + $mymenu add command -label [_ "Duplicate"] -accelerator "$accelerator+D" \ + -command {pdsend "$::focused_window duplicate"} + $mymenu add command -label [_ "Select All"] -accelerator "$accelerator+A" \ + -command {pdsend "$::focused_window selectall"} + $mymenu add separator + if {$::windowingsystem eq "aqua"} { + $mymenu add command -label [_ "Text Editor"] \ + -command {menu_texteditor $::focused_window} + $mymenu add command -label [_ "Font"] -accelerator "$accelerator+T" \ + -command {menu_font_dialog $::focused_window} + } else { + $mymenu add command -label [_ "Text Editor"] -accelerator "$accelerator+T"\ + -command {menu_texteditor $::focused_window} + $mymenu add command -label [_ "Font"] \ + -command {menu_font_dialog $::focused_window} + } + $mymenu add command -label [_ "Tidy Up"] \ + -command {pdsend "$::focused_window tidy"} + $mymenu add command -label [_ "Toggle Console"] -accelerator "Shift+$accelerator+R" \ + -command {.controls.switches.console invoke} + $mymenu add command -label [_ "Clear Console"] -accelerator "Shift+$accelerator+L" \ + -command {menu_clear_console} + $mymenu add separator + $mymenu add checkbutton -label [_ "Edit Mode"] \ + -accelerator "$accelerator+E" -variable ::editmode_button \ + -command {menu_editmode $::editmode_button} + -command {pdsend "$::focused_window editmode 0"} + #if { ! [catch {console hide}]} { + # TODO set up menu item to show/hide the Tcl/Tk console, if it available + #} + + if {$::windowingsystem ne "aqua"} { + $mymenu add separator + $mymenu add command -label [_ "Preferences"] \ + -command {menu_preferences_dialog} + } +} + +proc ::pd_menus::build_put_menu {mymenu mytoplevel} { + variable accelerator + $mymenu add command -label [_ "Object"] -accelerator "$accelerator+1" \ + -command {pdsend "$::focused_window obj 0"} + $mymenu add command -label [_ "Message"] -accelerator "$accelerator+2" \ + -command {pdsend "$::focused_window msg 0"} + $mymenu add command -label [_ "Number"] -accelerator "$accelerator+3" \ + -command {pdsend "$::focused_window floatatom 0"} + $mymenu add command -label [_ "Symbol"] -accelerator "$accelerator+4" \ + -command {pdsend "$::focused_window symbolatom 0"} + $mymenu add command -label [_ "Comment"] -accelerator "$accelerator+5" \ + -command {pdsend "$::focused_window text 0"} + $mymenu add separator + $mymenu add command -label [_ "Bang"] -accelerator "Shift+$accelerator+B" \ + -command {pdsend "$::focused_window bng 0"} + $mymenu add command -label [_ "Toggle"] -accelerator "Shift+$accelerator+T" \ + -command {pdsend "$::focused_window toggle 0"} + $mymenu add command -label [_ "Number2"] -accelerator "Shift+$accelerator+N" \ + -command {pdsend "$::focused_window numbox 0"} + $mymenu add command -label [_ "Vslider"] -accelerator "Shift+$accelerator+V" \ + -command {pdsend "$::focused_window vslider 0"} + $mymenu add command -label [_ "Hslider"] -accelerator "Shift+$accelerator+H" \ + -command {pdsend "$::focused_window hslider 0"} + $mymenu add command -label [_ "Vradio"] -accelerator "Shift+$accelerator+D" \ + -command {pdsend "$::focused_window vradio 0"} + $mymenu add command -label [_ "Hradio"] -accelerator "Shift+$accelerator+I" \ + -command {pdsend "$::focused_window hradio 0"} + $mymenu add command -label [_ "VU Meter"] -accelerator "Shift+$accelerator+U"\ + -command {pdsend "$::focused_window vumeter 0"} + $mymenu add command -label [_ "Canvas"] -accelerator "Shift+$accelerator+C" \ + -command {pdsend "$::focused_window mycnv 0"} + $mymenu add separator + $mymenu add command -label [_ "Graph"] -command {pdsend "$::focused_window graph"} + $mymenu add command -label [_ "Array"] -command {pdsend "$::focused_window menuarray"} +} + +proc ::pd_menus::build_find_menu {mymenu mytoplevel} { + variable accelerator + $mymenu add command -label [_ "Find..."] -accelerator "$accelerator+F" \ + -command {::dialog_find::menu_find_dialog $::focused_window} + $mymenu add command -label [_ "Find Again"] -accelerator "$accelerator+G" \ + -command {pdsend "$::focused_window findagain"} + $mymenu add command -label [_ "Find Last Error"] \ + -command {pdsend "$::focused_window finderror"} +} + +proc ::pd_menus::build_media_menu {mymenu mytoplevel} { + variable accelerator + $mymenu add radiobutton -label [_ "DSP On"] -accelerator "$accelerator+/" \ + -variable ::dsp -value 1 -command {pdsend "pd dsp 1"} + $mymenu add radiobutton -label [_ "DSP Off"] -accelerator "$accelerator+." \ + -variable ::dsp -value 0 -command {pdsend "pd dsp 0"} + $mymenu add separator + + set audioapi_list_length [llength $::audioapi_list] + for {set x 0} {$x<$audioapi_list_length} {incr x} { + # pdtk_post "audio [lindex [lindex $::audioapi_list $x] 0]" + $mymenu add radiobutton -label [lindex [lindex $::audioapi_list $x] 0] \ + -command {menu_audio 0} -variable ::pd_whichapi \ + -value [lindex [lindex $::audioapi_list $x] 1]\ + -command {pdsend "pd audio-setapi $::pd_whichapi"} + } + if {$audioapi_list_length > 0} {$mymenu add separator} + + set midiapi_list_length [llength $::midiapi_list] + for {set x 0} {$x<$midiapi_list_length} {incr x} { + # pdtk_post "midi [lindex [lindex $::midiapi_list $x] 0]" + $mymenu add radiobutton -label [lindex [lindex $::midiapi_list $x] 0] \ + -command {menu_midi 0} -variable ::pd_whichmidiapi \ + -value [lindex [lindex $::midiapi_list $x] 1]\ + -command {pdsend "pd midi-setapi $::pd_whichmidiapi"} + } + if {$midiapi_list_length > 0} {$mymenu add separator} + + if {$::windowingsystem ne "aqua"} { + $mymenu add command -label [_ "Audio settings..."] \ + -command {pdsend "pd audio-properties"} + $mymenu add command -label [_ "MIDI settings..."] \ + -command {pdsend "pd midi-properties"} + $mymenu add separator + } + $mymenu add command -label [_ "Test Audio and MIDI..."] \ + -command {menu_doc_open doc/7.stuff/tools testtone.pd} + $mymenu add command -label [_ "Load Meter"] \ + -command {menu_doc_open doc/7.stuff/tools load-meter.pd} +} + +proc ::pd_menus::build_window_menu {mymenu mytoplevel} { + variable accelerator + if {$::windowingsystem eq "aqua"} { + $mymenu add command -label [_ "Minimize"] -command {menu_minimize .} \ + -accelerator "$accelerator+M" + $mymenu add command -label [_ "Zoom"] -command {menu_zoom .} + $mymenu add separator + } + $mymenu add command -label [_ "Parent Window"] \ + -command {pdsend "$::focused_window findparent"} + $mymenu add command -label [_ "Pd window"] -command {menu_raise_pdwindow} \ + -accelerator "$accelerator+R" + $mymenu add separator + if {$::windowingsystem eq "aqua"} { + $mymenu add command -label [_ "Bring All to Front"] \ + -command {menu_bringalltofront} + $mymenu add separator + } +} + +proc ::pd_menus::build_help_menu {mymenu mytoplevel} { + if {$::windowingsystem ne "aqua"} { + $mymenu add command -label [_ "About Pd"] \ + -command {menu_doc_open doc/1.manual 1.introduction.txt} + } + $mymenu add command -label [_ "HTML Manual..."] \ + -command {menu_doc_open doc/1.manual index.htm} + $mymenu add command -label [_ "Browser..."] \ + -command {placeholder menu_helpbrowser \$help_top_directory} +} + +# ------------------------------------------------------------------------------ +# update the menu entries for opening recent files +proc ::pd_menus::update_recentfiles_menu {} { + variable menubar + switch -- $::windowingsystem { + "aqua" {::pd_menus::update_openrecent_menu_aqua .openrecent} + "win32" {update_recentfiles_on_menu $menubar.file} + "x11" {update_recentfiles_on_menu $menubar.file} + } +} + +proc ::pd_menus::clear_recentfiles_menu {} { + set ::recentfiles_list {} + ::pd_menus::update_recentfiles_menu +} + +proc ::pd_menus::update_openrecent_menu_aqua {mymenu} { + if {! [winfo exists $mymenu]} {menu $mymenu} + $mymenu delete 0 end + foreach filename $::recentfiles_list { + puts "creating menu item for $filename" + $mymenu add command -label [file tail $filename] \ + -command "open_file $filename" + } + $mymenu add separator + $mymenu add command -label [_ "Clear Menu"] \ + -command "::pd_menus::clear_recentfiles_menu" +} + +# this expects to be run on the File menu, and to insert above the last separator +proc ::pd_menus::update_recentfiles_on_menu {mymenu} { + set lastitem [$mymenu index end] + set i 1 + while {[$mymenu type [expr $lastitem-$i]] ne "separator"} {incr i} + set bottom_separator [expr $lastitem-$i] + incr i + while {[$mymenu type [expr $lastitem-$i]] ne "separator"} {incr i} + set top_separator [expr $lastitem-$i] + if {$top_separator < [expr $bottom_separator-1]} { + $mymenu delete [expr $top_separator+1] [expr $bottom_separator-1] + } + set i 0 + foreach filename $::recentfiles_list { + $mymenu insert [expr $top_separator+$i+1] command \ + -label [file tail $filename] -command "open_file $filename" + incr i + } +} + +# ------------------------------------------------------------------------------ +# menu building functions for Mac OS X/aqua + +# for Mac OS X only +proc ::pd_menus::create_apple_menu {mymenu} { + # TODO this should open a Pd patch called about.pd + menu $mymenu.apple + $mymenu.apple add command -label [_ "About Pd"] \ + -command {menu_doc_open doc/1.manual 1.introduction.txt} + $mymenu add cascade -label "Apple" -menu $mymenu.apple + $mymenu.apple add separator + # starting in 8.4.14, this is created automatically + set patchlevel [split [info patchlevel] .] + if {[lindex $patchlevel 1] < 5 && [lindex $patchlevel 2] < 14} { + $mymenu.apple add command -label [_ "Preferences..."] \ + -command {menu_preferences_dialog" -accelerator "Cmd+,} + } +} + +proc ::pd_menus::build_file_menu_aqua {mymenu} { + variable accelerator + $mymenu add command -label [_ "New"] -accelerator "$accelerator+N" + $mymenu add command -label [_ "Open"] -accelerator "$accelerator+O" + ::pd_menus::update_openrecent_menu_aqua .openrecent + $mymenu add cascade -label [_ "Open Recent"] -menu .openrecent + $mymenu add separator + $mymenu add command -label [_ "Close"] -accelerator "$accelerator+W" + $mymenu add command -label [_ "Save"] -accelerator "$accelerator+S" + $mymenu add command -label [_ "Save As..."] -accelerator "$accelerator+Shift+S" + #$mymenu add command -label [_ "Save All"] + #$mymenu add command -label [_ "Revert to Saved"] + $mymenu add separator + $mymenu add command -label [_ "Message"] + $mymenu add separator + $mymenu add command -label [_ "Print..."] -accelerator "$accelerator+P" +} + +# the "Edit", "Put", and "Find" menus do not have cross-platform differences + +proc ::pd_menus::build_media_menu_aqua {mymenu} { +} + +proc ::pd_menus::build_window_menu_aqua {mymenu} { +} + +# the "Help" does not have cross-platform differences + +# ------------------------------------------------------------------------------ +# menu building functions for UNIX/X11 + +proc ::pd_menus::build_file_menu_x11 {mymenu} { + variable accelerator + $mymenu add command -label [_ "New"] -accelerator "$accelerator+N" + $mymenu add command -label [_ "Open"] -accelerator "$accelerator+O" + $mymenu add separator + $mymenu add command -label [_ "Save"] -accelerator "$accelerator+S" + $mymenu add command -label [_ "Save As..."] -accelerator "Shift+$accelerator+S" + # $mymenu add command -label "Revert" + $mymenu add separator + $mymenu add command -label [_ "Message"] -accelerator "$accelerator+M" + $mymenu add command -label [_ "Print..."] -accelerator "$accelerator+P" + $mymenu add separator + # the recent files get inserted in here by update_recentfiles_on_menu + $mymenu add separator + $mymenu add command -label [_ "Close"] -accelerator "$accelerator+W" + $mymenu add command -label [_ "Quit"] -accelerator "$accelerator+Q" \ + -command {pdsend "pd verifyquit"} +} + +# the "Edit", "Put", and "Find" menus do not have cross-platform differences + +proc ::pd_menus::build_media_menu_x11 {mymenu} { +} + +proc ::pd_menus::build_window_menu_x11 {mymenu} { +} + +# the "Help" does not have cross-platform differences + +# ------------------------------------------------------------------------------ +# menu building functions for Windows/Win32 + +# for Windows only +proc ::pd_menus::create_system_menu {mymenu} { + $mymenu add cascade -menu [menu $mymenu.system] + # TODO add Close, Minimize, etc and whatever else is on the little menu + # that is on the top left corner of the window frame +} + +proc ::pd_menus::build_file_menu_win32 {mymenu} { + variable accelerator + $mymenu add command -label [_ "New"] -accelerator "$accelerator+N" + $mymenu add command -label [_ "Open"] -accelerator "$accelerator+O" + $mymenu add separator + $mymenu add command -label [_ "Save"] -accelerator "$accelerator+S" + $mymenu add command -label [_ "Save As..."] -accelerator "Shift+$accelerator+S" + # $mymenu add command -label "Revert" + $mymenu add separator + $mymenu add command -label [_ "Message"] -accelerator "$accelerator+M" + $mymenu add command -label [_ "Print..."] -accelerator "$accelerator+P" + $mymenu add separator + # the recent files get inserted in here by update_recentfiles_on_menu + $mymenu add separator + $mymenu add command -label [_ "Close"] -accelerator "$accelerator+W" + $mymenu add command -label [_ "Quit"] -accelerator "$accelerator+Q"\ + -command {pdsend "pd verifyquit"} +} + +# the "Edit", "Put", and "Find" menus do not have cross-platform differences + +proc ::pd_menus::build_media_menu_win32 {mymenu} { +} + +proc ::pd_menus::build_window_menu_win32 {mymenu} { +} + +# the "Help" does not have cross-platform differences +