diff --git a/doc/1.manual/x5.htm b/doc/1.manual/x5.htm index 9cccef2575b12ef5312b458aebf128d2c2f86e6a..634e0eeb92671085096b990f2336f8d040fa26a2 100644 --- a/doc/1.manual/x5.htm +++ b/doc/1.manual/x5.htm @@ -20,6 +20,16 @@ <H3> <A name="s2"> 5.1. release notes </A> </H3> +<P> ------------------ 0.42 --------------------------- + +<P> ".pdrc" loading suppressed if pd is started with "-noprefs". + +<P> Bug fix in pipe object: if sending a list to pipe, it didn't update the +delay time when asked to. + +<P> Binbufs fixed to handle arbitrary length messages. (This fixed a problem +reloading data structures with huge arrays). + <P> ------------------ 0.41-3,4 --------------------------- <P> 2 fixes for PC: no bonk~, and the audio device selection diff --git a/doc/3.audio.examples/I01.Fourier.analysis.pd b/doc/3.audio.examples/I01.Fourier.analysis.pd index 31bcce631e6d064d44cd547650790c4e448ee079..f82e1710547cd4ceada5d4fba44d7699fbf80ff2 100644 --- a/doc/3.audio.examples/I01.Fourier.analysis.pd +++ b/doc/3.audio.examples/I01.Fourier.analysis.pd @@ -1,6 +1,6 @@ -#N canvas 25 8 688 708 12; +#N canvas 247 4 688 708 12; #X floatatom 38 264 7 0 0 0 - - -; -#N canvas 0 0 450 300 graph1 0; +#N canvas 0 0 450 300 (subpatch) 0; #X array \$0-real 64 float 2; #X coords 0 64 64 -64 256 200 1; #X restore 423 184 graph; @@ -12,7 +12,7 @@ #X obj 38 637 tabwrite~ \$0-real; #X obj 67 614 tabwrite~ \$0-imaginary; #X obj 38 384 osc~; -#N canvas 0 0 450 300 graph1 0; +#N canvas 0 0 450 300 (subpatch) 0; #X array \$0-imaginary 64 float 2; #X coords 0 64 64 -64 256 200 1; #X restore 423 417 graph; @@ -20,8 +20,8 @@ #X floatatom 91 316 3 0 100 0 - - -; #X obj 91 337 / 100; #X obj 38 191 / 64; -#X text 504 163 real part; -#X text 489 398 imaginary part; +#X text 595 165 real part; +#X text 550 398 imaginary part; #X obj 80 545 loadbang; #X text 94 166 <- frequency; #X text 133 182 (as multiple; diff --git a/doc/5.reference/exp~-help.pd b/doc/5.reference/exp~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..fc9089af98e488f60550f3a71d614c18fba5cad8 --- /dev/null +++ b/doc/5.reference/exp~-help.pd @@ -0,0 +1,23 @@ +#N canvas 35 5 531 296 10; +#X obj 19 107 sig~; +#X obj 50 167 loadbang; +#X obj 50 191 metro 100; +#X obj 50 215 snapshot~; +#X floatatom 19 88 5 0 0 0 - - -; +#X floatatom 50 240 7 0 0 0 - - -; +#X text 314 271 updated for Pd version 0.42.; +#X text 83 131 <-- optional creation argument initializes right inlet +(the base of the logarithm).; +#X obj 21 14 exp~; +#X text 60 14 - exponential function; +#X text 76 31 raises the Euler number 'e' (about 2.718) \, to the power +of the input signal.; +#X text 18 272 See also:; +#X obj 92 271 pow~; +#X obj 20 132 exp~; +#X connect 0 0 13 0; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 3 0 5 0; +#X connect 4 0 0 0; +#X connect 13 0 3 0; diff --git a/doc/5.reference/help-intro.pd b/doc/5.reference/help-intro.pd index 10ae3502f2a1079e3ad1fcb05a1d4f26fef10e06..1315f27c576bb25cb4ca18fa0ee485da4872a338 100644 --- a/doc/5.reference/help-intro.pd +++ b/doc/5.reference/help-intro.pd @@ -81,15 +81,15 @@ #X text 119 1178 - greater or lesser of 2 numbers; #X obj 19 1201 clip; #X text 119 1201 - force a number into a range; -#X obj 16 1251 notein; -#X obj 75 1251 ctlin; -#X obj 126 1251 pgmin; -#X obj 176 1251 bendin; -#X obj 235 1251 touchin; -#X obj 16 1274 polytouchin; -#X obj 120 1274 midiin; -#X obj 179 1274 sysexin; -#X text 318 1263 - MIDI input; +#X obj 16 1261 notein; +#X obj 75 1261 ctlin; +#X obj 126 1261 pgmin; +#X obj 176 1261 bendin; +#X obj 235 1261 touchin; +#X obj 16 1284 polytouchin; +#X obj 120 1284 midiin; +#X obj 179 1284 sysexin; +#X text 318 1273 - MIDI input; #X obj 19 1317 noteout; #X obj 87 1317 ctlout; #X obj 147 1317 pgmout; @@ -99,8 +99,6 @@ #X obj 210 1338 midiout; #X text 318 1327 - MIDI output; #X obj 20 1370 makenote; -#X text 109 1368 - schedule a delayed "note off" message corresponding -to a note-on; #X obj 19 1402 stripnote; #X text 112 1403 - strip "note off" messages; #X obj 17 1441 tabread; @@ -143,18 +141,17 @@ to a note-on; #X obj 16 2052 q8_rsqrt~; #X text 116 2052 - cheap reciprocal square root (beware -- 8 bits!) ; -#X obj 16 2082 q8_sqrt~; -#X text 116 2082 - cheap square root (beware -- 8 bits!); -#X obj 16 2112 wrap~; -#X text 116 2112 - wraparound (fractional part; -#X obj 16 2142 fft~; -#X text 116 2142 - complex forward discrete Fourier transform; -#X obj 16 2172 ifft~; -#X text 116 2172 - complex inverse discrete Fourier transform; -#X obj 16 2202 rfft~; -#X text 116 2202 - real forward discrete Fourier transform; -#X obj 16 2232 rifft~; -#X text 116 2232 - real inverse discrete Fourier transform; +#X obj 16 2074 q8_sqrt~; +#X text 116 2074 - cheap square root (beware -- 8 bits!); +#X obj 16 2104 wrap~; +#X obj 16 2134 fft~; +#X text 116 2134 - complex forward discrete Fourier transform; +#X obj 16 2156 ifft~; +#X text 116 2156 - complex inverse discrete Fourier transform; +#X obj 16 2186 rfft~; +#X text 116 2186 - real forward discrete Fourier transform; +#X obj 16 2208 rifft~; +#X text 116 2208 - real inverse discrete Fourier transform; #X obj 16 2262 framp~; #X text 116 2262 - output a ramp for each block; #X obj 16 2292 mtof~; @@ -314,7 +311,7 @@ to a note-on; #X text 20 961 ------------------------- MATH -----------------; #X text 19 721 ------------------------- TIME -------------------------- ; -#X text 17 1232 ------------------------ MIDI ------------------------- +#X text 17 1242 ------------------------ MIDI ------------------------- ; #X text 24 120 --------------- GLUE ----------------; #X text 18 3768 ------------------------ SUBWINDOWS ------------------------ @@ -358,3 +355,13 @@ aren't typed into object boxes but come straight off the "add" menu.) Right-click (or double-click on a Macintosh) on any object to get its "help window".; #X text 118 4368 - get a pointer into a list within a scalar; +#X obj 19 1224 wrap; +#X text 118 1224 - wrap a number to range [0 \, 1); +#X text 116 2104 - wraparound (fractional part); +#X obj 15 2236 pow~; +#X obj 59 2236 log~; +#X obj 103 2236 exp~; +#X text 197 2238 - math; +#X obj 149 2237 abs~; +#X text 109 1368 - schedule delayed "note off" message corresponding +to a note-on; diff --git a/doc/5.reference/log~-help.pd b/doc/5.reference/log~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..fdad98d2af358573c4293d301ee7c2f9b17adb86 --- /dev/null +++ b/doc/5.reference/log~-help.pd @@ -0,0 +1,26 @@ +#N canvas 299 273 531 296 10; +#X obj 19 103 sig~; +#X obj 50 167 loadbang; +#X obj 50 191 metro 100; +#X obj 50 215 snapshot~; +#X floatatom 19 79 5 0 0 0 - - -; +#X obj 60 103 sig~; +#X floatatom 60 79 5 0 0 0 - - -; +#X floatatom 50 240 7 0 0 0 - - -; +#X text 316 257 updated for Pd version 0.42.; +#X obj 21 14 log~; +#X text 60 14 - logarithms; +#X text 76 31 computes the logarithm of the left inlet \, to the base +'e' (about 2.718) \, or to another base specified by the inlet or a +cration argument.; +#X obj 20 132 log~ 2; +#X text 83 131 <-- optional creation argument initializes right inlet +(the base of the logarithm).; +#X connect 0 0 12 0; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 3 0 7 0; +#X connect 4 0 0 0; +#X connect 5 0 12 1; +#X connect 6 0 5 0; +#X connect 12 0 3 0; diff --git a/doc/5.reference/pow~-help.pd b/doc/5.reference/pow~-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..049e8ba948f875c97283e57e0ab7a95dfcd3bf90 --- /dev/null +++ b/doc/5.reference/pow~-help.pd @@ -0,0 +1,30 @@ +#N canvas 191 0 534 413 10; +#X obj 21 14 pow~; +#X obj 67 109 sig~; +#X obj 98 173 loadbang; +#X obj 98 197 metro 100; +#X obj 98 221 snapshot~; +#X floatatom 67 73 5 0 0 0 - - -; +#X obj 108 109 sig~; +#X floatatom 108 73 5 0 0 0 - - -; +#X obj 68 138 pow~ 2; +#X floatatom 98 246 7 0 0 0 - - -; +#X obj 413 268 pow~ 2; +#X text 20 271 An optional creation argument initializes right inlet: +; +#X text 319 384 updated for Pd version 0.42.; +#X text 23 303 WARNING: it's easy to generate "infinity" by accident +\, and if you do \, the DSP chain may dramatically slow down if you're +using an i386 or ia64 processor. Out-of-range floating point values +are thousands of times slower to compute with than in-range ones.; +#X text 68 12 - raise a signal to a numeric power (given by another +signal). The left inlet must be a positive number. The right inlet +my be positive \, zero \, or negative.; +#X connect 1 0 8 0; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 4 0 9 0; +#X connect 5 0 1 0; +#X connect 6 0 8 1; +#X connect 7 0 6 0; +#X connect 8 0 4 0; diff --git a/extra/makefile b/extra/makefile index 944475a1c477063f182ce982271def72c6974916..313795235e375f23c89903c99c308286455e8302 100644 --- a/extra/makefile +++ b/extra/makefile @@ -23,36 +23,6 @@ PDNTLIB = /NODEFAULTLIB:libcmt /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel32 \ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c link /nologo /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB) -# ----------------------- IRIX 5.x ----------------------- - -pd_irix5: $(NAME).pd_irix5 - -.SUFFIXES: .pd_irix5 - -SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2 - -SGIINCLUDE = -I../../src - -.c.pd_irix5: - $(CC) $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c - ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o - rm $*.o - -# ----------------------- IRIX 6.x ----------------------- - -pd_irix6: $(NAME).pd_irix6 - -.SUFFIXES: .pd_irix6 - -SGICFLAGS6 = -n32 -DPD -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \ - -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \ - -Ofast=ip32 - -.c.pd_irix6: - $(CC) $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c - ld -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o - rm $*.o - # ----------------------- LINUX i386 ----------------------- pd_linux: $(NAME).pd_linux diff --git a/extra/pd~/makefile b/extra/pd~/makefile new file mode 100644 index 0000000000000000000000000000000000000000..e0599d541afa571ac1eb4308eaefcc54e97b4769 --- /dev/null +++ b/extra/pd~/makefile @@ -0,0 +1,12 @@ +NAME=pd~ +CSYM=pd_tilde + +include ../makefile + +pd_linux: pdsched.pd_linux + +pdsched.pd_linux: pdsched.c + $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c + $(CC) -export_dynamic -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..466c5cdc39aeeeedf6aee1f70267b8758e3a29ce --- /dev/null +++ b/extra/pd~/notes.txt @@ -0,0 +1,23 @@ +pd -schedlib `pwd`/pdsched + + +problems: +confusion about file extent (l_ia64 / pd_linux) +Pd dies silently if scheduler doesn't load +figure out about setting nchannels from command line +maximum nchannels in and out + + +paper? +cost per watt +flops per watt +cost per flop +cost of multiprocessing + +history - 6-processor ISPW / 1-processor PC / 4-processor PC +will multiprocessing ever get cheap enough to be worth it? + (including programming/complexity cost) +will multiprocessing be 2-to-4 or 16-up? + +Max/FTS, pd, pd~ + diff --git a/extra/pd~/pdsched.c b/extra/pd~/pdsched.c new file mode 100644 index 0000000000000000000000000000000000000000..0a0852d173bf146ccf1abb888f3f86c27abeff17 --- /dev/null +++ b/extra/pd~/pdsched.c @@ -0,0 +1,83 @@ +/* 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); + 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"); + } + 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..6ff3bb0614cd601a63f0cc0c525b7700975661bc --- /dev/null +++ b/extra/pd~/pd~-help.pd @@ -0,0 +1,13 @@ +#N canvas 315 103 450 300 10; +#X msg 52 86 foo bar baz; +#X obj 209 52 osc~ 440; +#X obj 74 211 env~ 8192; +#X floatatom 77 243 5 0 0 0 - - -; +#X obj 285 204 r a; +#X obj 281 232 print a; +#X obj 70 166 pd~ -pddir /home/msp/pd z.pd; +#X connect 0 0 6 0; +#X connect 1 0 6 0; +#X connect 2 0 3 0; +#X connect 4 0 5 0; +#X connect 6 0 2 0; diff --git a/extra/pd~/pd~.c b/extra/pd~/pd~.c new file mode 100644 index 0000000000000000000000000000000000000000..477cae0f9c0a6edc23bdc83c5566e6c36048d93c --- /dev/null +++ b/extra/pd~/pd~.c @@ -0,0 +1,599 @@ +/* + 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; + +void *pd_tilde_class; +#define getbytes t_getbytes +#define freebytes t_freebytes +#endif /* MSP */ + +#ifdef PD +#include "m_pd.h" +#include "s_stuff.h" +static t_class *pd_tilde_class; +char *class_gethelpdir(t_class *c); +#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_ppc", + 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; +#endif /* PD */ +#ifdef MSP + t_pxobject x_obj; + void *obex; + void *x_cookedout; + void *x_clock; + short x_vol; + +#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; + 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); +void main(); +static void pd_tilde_thresh(t_pd_tilde *x, t_floatarg f1, t_floatarg f2); +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) + { + pd_error(x, "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) + { + pd_error(x, "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 *pdargs, int ninsig, int noutsig, int fifo, float samplerate) +{ + int i, pid, pipe1[2], pipe2[2]; + char cmdbuf[MAXPDSTRING], pdexecbuf[MAXPDSTRING], schedbuf[MAXPDSTRING]; + float *fp; + t_sample **g; + 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) + { + pd_error(x, "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) + { + pd_error(x, "pd~: can't stat %s", schedbuf); + goto fail1; + } + } + snprintf(cmdbuf, MAXPDSTRING, "%s -schedlib %s/pdsched %s\n", + pdexecbuf, schedlibdir, pdargs); + fprintf(stderr, "%s", cmdbuf); + if (pipe(pipe1) < 0) + { + pd_error(x, "pd~: can't create pipe"); + goto fail1; + } + if (pipe(pipe2) < 0) + { + pd_error(x, "pd~: can't create pipe"); + goto fail2; + } + if ((pid = fork()) < 0) + { + pd_error(x, "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))) + { + pd_error(x, "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, gotsomething = 0, setclock = 0, + numbuffill = 0, c; + char numbuf[80]; + FILE *infd = x->x_infd; + if (!infd) + goto zeroit; + fprintf(x->x_outfd, ";\n"); + 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) + pd_error(x, "pd~: %s", strerror(errno)); + else pd_error(x, "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) + { + 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_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 = 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 + 1) + { + t_pd *whom; + if (vec[messstart].a_type != A_SYMBOL) + bug("pd_tilde_tick"); + else if (!(whom = vec[messstart].a_w.w_symbol->s_thing)) + pd_error(x, "%s: no such object", + vec[messstart].a_w.w_symbol->s_name); + else if (vec[messstart+1].a_type == A_SYMBOL) + typedmess(whom, vec[messstart+1].a_w.w_symbol, + i-messstart-2, vec+(messstart+2)); + else pd_list(whom, 0, i-messstart-1, vec+(messstart+1)); + } + 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], *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 (argc--) + { + if (sp < ep-1) + sp[0] = ' ', sp[1] = 0, sp++; + atom_string(argv++, sp, ep-sp); + sp += strlen(sp); + } + fprintf(x->x_outfd, "%s;\n", msgbuf); +} + +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, arglength, fifo = 5; + float sr = sys_getsr(); + t_sample **g; + t_symbol *pddir = gensym("."), + *scheddir = gensym(class_gethelpdir(pd_tilde_class)); + char pdargstring[MAXPDSTRING]; + 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 0 + { + pd_error(x, +"usage: pd~ [-sr #] [-ninsig #] [-noutsig #] [-fifo #] [-pddir <>]"); + post( +"... [-scheddir <>] [pd-argument...]"); + argc = 0; + } +#endif + + pdargstring[0] = 0; + while (argc--) + { + atom_string(argv++, pdargstring + strlen(pdargstring), + MAXPDSTRING - strlen(pdargstring)); + if (strlen(pdargstring) < MAXPDSTRING-1) + strcat(pdargstring, " "); + } + 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; + 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); + for (j = 0, g = x->x_outsig; j < noutsig; j++, g++) + outlet_new(&x->x_obj, &s_signal); + + pd_tilde_donew(x, pddir->s_name, scheddir->s_name, pdargstring, + ninsig, noutsig, fifo, sr); + + 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_addanything(pd_tilde_class, pd_tilde_anything); + post("pd~ version 0.1"); +} +#endif + +/* -------------------------- MSP glue ------------------------- */ +#ifdef MSP + +void main() +{ + t_class *c; + t_object *attr; + long attrflags = 0; + t_symbol *sym_long = gensym("long"), *sym_float32 = gensym("float32"); + + c = class_new("pd_tilde~", (method)pd_tilde_new, (method)pd_tilde_free, sizeof(t_pd_tilde), (method)0L, A_GIMME, 0); + + class_obexoffset_set(c, calcoffset(t_pd_tilde, obex)); + + attr = attr_offset_new("npoints", sym_long, attrflags, (method)0L, (method)0L, calcoffset(t_pd_tilde, x_npoints)); + class_addattr(c, attr); + + class_addmethod(c, (method)pd_tilde_dsp, "dsp", A_CANT, 0); + class_addmethod(c, (method)pd_tilde_bang, "bang", A_CANT, 0); + class_addmethod(c, (method)pd_tilde_forget, "forget", 0); + class_addmethod(c, (method)pd_tilde_thresh, "thresh", A_FLOAT, A_FLOAT, 0); + class_addmethod(c, (method)pd_tilde_print, "print", A_DEFFLOAT, 0); + class_addmethod(c, (method)pd_tilde_read, "read", A_DEFSYM, 0); + class_addmethod(c, (method)pd_tilde_write, "write", A_DEFSYM, 0); + class_addmethod(c, (method)pd_tilde_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); + pd_tilde_class = c; +} + +static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av) +{ + short j; + t_pd_tilde *x; + + if (x = (t_pd_tilde *)object_alloc(pd_tilde_class)) { + + t_insig *g; + + if (ac) { + switch (av[0].a_type) { + case A_LONG: + x->x_nsig = av[0].a_w.w_long; + break; + } + } + + attr_args_process(x, ac, av); + + x->x_insig = (t_insig *)getbytes(x->x_nsig * sizeof(*x->x_insig)); + + x->x_ninsig = x->x_nsig; + + dsp_setup((t_pxobject *)x, x->x_nsig); + + 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_nsig-1; j < x->x_nsig; j++, g--) + { + g->g_outlet = listout((t_object *)x); + } + + x->x_clock = clock_new(x, (method)pd_tilde_tick); + + pd_tilde_donew(x, x->x_npoints, x->x_period, x->x_nsig, x->x_nfilters, + x->x_halftones, x->x_overlap, x->x_firstbin, sys_getsr()); + } + return (x); +} + +/* Attribute setters. */ +void pd_tilde_minvel_set(t_pd_tilde *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; + } +} + +/* end attr setters */ + +void pd_tilde_assist(t_pd_tilde *x, void *b, long m, long a, char *s) +{ +} + +#endif /* MSP */ diff --git a/extra/pd~/z.txt b/extra/pd~/z.txt new file mode 100644 index 0000000000000000000000000000000000000000..89e279680b382063c616be633698ef3bbaeafbcf --- /dev/null +++ b/extra/pd~/z.txt @@ -0,0 +1,128 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/extra/stdout/makefile b/extra/stdout/makefile new file mode 100644 index 0000000000000000000000000000000000000000..67801999bf27df3cacaf2b8f8373bedbcc2d006d --- /dev/null +++ b/extra/stdout/makefile @@ -0,0 +1,4 @@ +NAME=stdout +CSYM=stdout + +include ../makefile diff --git a/extra/stdout/stdout-help.pd b/extra/stdout/stdout-help.pd new file mode 100644 index 0000000000000000000000000000000000000000..b3d024896238edc7043a72b24e650a27cfc9b846 --- /dev/null +++ b/extra/stdout/stdout-help.pd @@ -0,0 +1,13 @@ +#N canvas 110 37 789 525 10; +#X msg 84 147 walk the dog; +#X msg 91 169 1; +#X msg 90 215 flush; +#X obj 84 240 stdout; +#X text 472 410 updated for Pd version 0.42; +#X obj 14 13 stdout; +#X text 67 14 - write messages to standard output; +#X msg 96 192 1 2; +#X connect 0 0 3 0; +#X connect 1 0 3 0; +#X connect 2 0 3 0; +#X connect 7 0 3 0; diff --git a/extra/stdout/stdout.c b/extra/stdout/stdout.c new file mode 100644 index 0000000000000000000000000000000000000000..06c99308ba9839389af405c02ab3ca7776f24e02 --- /dev/null +++ b/extra/stdout/stdout.c @@ -0,0 +1,51 @@ +/* stdout -- write messages to standard output. + + Copyright 2008 Miller Puckette + BSD license; see README.txt in this distribution for details. +*/ + +#include "m_pd.h" +#include <stdio.h> +#include <string.h> +static t_class *stdout_class; + +typedef struct _stdout +{ + t_object x_obj; +} t_stdout; + +static void *stdout_new(t_float fnonrepeat) +{ + t_stdout *x = (t_stdout *)pd_new(stdout_class); + return (x); +} + +static void stdout_anything(t_stdout *x, t_symbol *s, int argc, t_atom *argv) +{ + char msgbuf[MAXPDSTRING], *sp, *ep = msgbuf+MAXPDSTRING; + msgbuf[0] = 0; + strncpy(msgbuf, s->s_name, MAXPDSTRING); + msgbuf[MAXPDSTRING-1] = 0; + sp = msgbuf + strlen(msgbuf); + while (argc--) + { + if (sp < ep-1) + sp[0] = ' ', sp[1] = 0, sp++; + atom_string(argv++, sp, ep-sp); + sp += strlen(sp); + } + printf("%s;\n", msgbuf); +} + +static void stdout_flush(t_stdout *x) +{ + fflush(stdout); +} + +void stdout_setup(void) +{ + stdout_class = class_new(gensym("stdout"), (t_newmethod)stdout_new, + (t_method)stdout_flush, sizeof(t_stdout), 0, 0); + class_addmethod(stdout_class, (t_method)stdout_flush, gensym("flush"), 0); + class_addanything(stdout_class, stdout_anything); +} diff --git a/src/CHANGELOG.txt b/src/CHANGELOG.txt index 9620a7fae1925aba8885de15216490fa29290502..6d7891713967b613e589ce5c7c2d245ff3e47a3f 100644 --- a/src/CHANGELOG.txt +++ b/src/CHANGELOG.txt @@ -2,6 +2,11 @@ This file describes implementation and API changes; stuff more visible to the user appears in the "release notes" instead. See the bottom of this file for original notes on source stype and organization. +0.42.0 + +changed definition of t_float, t_sample, t_floatarg so that they can be +set via #defines (PD_FLOATTYPE, etc). + 0.41.0 add support for callback-based audio I/O diff --git a/src/d_fftroutine.c b/src/d_fftroutine.c index 4678d38a77797c4f4a6737ede8055352fcde6c01..0222a0c006ac522e93e1334f4ea5e59cf13eab86 100644 --- a/src/d_fftroutine.c +++ b/src/d_fftroutine.c @@ -98,7 +98,7 @@ #define FALSE 0 #endif -#define SAMPLE float /* data type used in calculation */ +#define SAMPLE PD_FLOATTYPE /* data type used in calculation */ #define SHORT_SIZE sizeof(short) #define INT_SIZE sizeof(int) @@ -154,8 +154,8 @@ typedef struct Tfft_net { void cfft(int trnsfrm_dir, int npnt, int window, - float *source_buf, int source_form, int source_scale, - float *result_buf, int result_form, int result_scale, int debug); + SAMPLE *source_buf, int source_form, int source_scale, + SAMPLE *result_buf, int result_form, int result_scale, int debug); /*****************************************************************************/ @@ -172,10 +172,10 @@ int power_of_two(int n); void create_hanning(SAMPLE *window, int n, SAMPLE scale); void create_rectangular(SAMPLE *window, int n, SAMPLE scale); void short_to_float(short *short_buf, float *float_buf, int n); -void load_registers(FFT_NET *fft_net, float *buf, int buf_form, +void load_registers(FFT_NET *fft_net, SAMPLE *buf, int buf_form, int buf_scale, int trnsfrm_dir); void compute_fft(FFT_NET *fft_net); -void store_registers(FFT_NET *fft_net, float *buf, int buf_form, +void store_registers(FFT_NET *fft_net, SAMPLE *buf, int buf_form, int buf_scale, int debug); void build_fft_network(FFT_NET *fft_net, int n, int window_type); @@ -184,8 +184,8 @@ void build_fft_network(FFT_NET *fft_net, int n, int window_type); /*****************************************************************************/ void cfft(int trnsfrm_dir, int npnt, int window, - float *source_buf, int source_form, int source_scale, - float *result_buf, int result_form, int result_scale, int debug) + SAMPLE *source_buf, int source_form, int source_scale, + SAMPLE *result_buf, int result_form, int result_scale, int debug) /* modifies: result_buf effects: Computes npnt FFT specified by form, scale, and dir parameters. @@ -471,7 +471,7 @@ void build_fft_network(FFT_NET *fft_net, int n, int window_type) /* REGISTER LOAD AND STORE */ /*****************************************************************************/ -void load_registers(FFT_NET *fft_net, float *buf, int buf_form, +void load_registers(FFT_NET *fft_net, SAMPLE *buf, int buf_form, int buf_scale, int trnsfrm_dir) /* effects: Multiplies the input buffer with the appropriate window and @@ -605,7 +605,7 @@ void load_registers(FFT_NET *fft_net, float *buf, int buf_form, } -void store_registers(FFT_NET *fft_net, float *buf, int buf_form, +void store_registers(FFT_NET *fft_net, SAMPLE *buf, int buf_form, int buf_scale, int debug) /* modifies: buf @@ -989,10 +989,10 @@ void short_to_float(short *short_buf, float *float_buf, int n) /* here's the meat: */ -void pd_fft(float *buf, int npoints, int inverse) +void pd_fft(t_float *buf, int npoints, int inverse) { double renorm; - float *fp, *fp2; + SAMPLE *fp, *fp2; int i; renorm = (inverse ? npoints : 1.); cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR, diff --git a/src/d_math.c b/src/d_math.c index 213b866e556fc174a4e21ed192ca0213437d22f9..738f2d6cdc0f913d22a64b46c45d1d717c555a82 100644 --- a/src/d_math.c +++ b/src/d_math.c @@ -97,7 +97,7 @@ static void init_rsqrt(void) /* these are used in externs like "bonk" */ -float q8_rsqrt(float f) +t_float q8_rsqrt(t_float f) { long l = *(long *)(&f); if (f < 0) return (0); @@ -105,7 +105,7 @@ float q8_rsqrt(float f) rsqrt_mantissatab[(l >> 13) & 0x3ff]); } -float q8_sqrt(float f) +t_float q8_sqrt(t_float f) { long l = *(long *)(&f); if (f < 0) return (0); @@ -116,8 +116,8 @@ float q8_sqrt(float f) /* the old names are OK unless we're in IRIX N32 */ #ifndef N32 -float qsqrt(float f) {return (q8_sqrt(f)); } -float qrsqrt(float f) {return (q8_rsqrt(f)); } +t_float qsqrt(t_float f) {return (q8_sqrt(f)); } +t_float qrsqrt(t_float f) {return (q8_rsqrt(f)); } #endif @@ -555,6 +555,189 @@ void powtodb_tilde_setup(void) class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0); } +/* ----------------------------- pow ----------------------------- */ +static t_class *pow_tilde_class; + +typedef struct _pow_tilde +{ + t_object x_obj; + t_float x_f; +} t_pow_tilde; + +static void *pow_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_pow_tilde *x = (t_pow_tilde *)pd_new(pow_tilde_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); +} + +t_int *pow_tilde_perform(t_int *w) +{ + t_sample *in1 = (t_sample *)(w[1]); + t_sample *in2 = (t_sample *)(w[2]); + t_sample *out = (t_sample *)(w[3]); + int n = (int)(w[4]); + while (n--) + { + float f = *in1++; + if (f > 0) + *out = pow(f, *in2); + else *out = 0; + out++; + in2++; + } + return (w+5); +} + +static void pow_tilde_dsp(t_pow_tilde *x, t_signal **sp) +{ + dsp_add(pow_tilde_perform, 4, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); +} + +static void pow_tilde_setup(void) +{ + pow_tilde_class = class_new(gensym("pow~"), (t_newmethod)pow_tilde_new, 0, + sizeof(t_pow_tilde), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(pow_tilde_class, t_pow_tilde, x_f); + class_addmethod(pow_tilde_class, (t_method)pow_tilde_dsp, gensym("dsp"), 0); +} + +/* ----------------------------- exp ----------------------------- */ +static t_class *exp_tilde_class; + +typedef struct _exp_tilde +{ + t_object x_obj; + t_float x_f; +} t_exp_tilde; + +static void *exp_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_exp_tilde *x = (t_exp_tilde *)pd_new(exp_tilde_class); + outlet_new(&x->x_obj, &s_signal); + return (x); +} + +t_int *exp_tilde_perform(t_int *w) +{ + t_sample *in1 = (t_sample *)(w[1]); + t_sample *out = (t_sample *)(w[2]); + int n = (int)(w[3]); + while (n--) + *out = exp(*in1); + return (w+4); +} + +static void exp_tilde_dsp(t_exp_tilde *x, t_signal **sp) +{ + dsp_add(exp_tilde_perform, 3, + sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); +} + +static void exp_tilde_setup(void) +{ + exp_tilde_class = class_new(gensym("exp~"), (t_newmethod)exp_tilde_new, 0, + sizeof(t_exp_tilde), 0, 0); + CLASS_MAINSIGNALIN(exp_tilde_class, t_exp_tilde, x_f); + class_addmethod(exp_tilde_class, (t_method)exp_tilde_dsp, gensym("dsp"), 0); +} + +/* ----------------------------- log ----------------------------- */ +static t_class *log_tilde_class; + +typedef struct _log_tilde +{ + t_object x_obj; + t_float x_f; +} t_log_tilde; + +static void *log_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_log_tilde *x = (t_log_tilde *)pd_new(log_tilde_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); +} + +t_int *log_tilde_perform(t_int *w) +{ + t_sample *in1 = (t_sample *)(w[1]); + t_sample *in2 = (t_sample *)(w[2]); + t_sample *out = (t_sample *)(w[3]); + int n = (int)(w[4]); + while (n--) + { + float f = *in1++, g = *in2++; + if (f <= 0) + *out = -1000; /* rather than blow up, output a number << 0 */ + else if (g <= 0) + *out = log(f); + else *out = log(f)/log(g); + out++; + } + return (w+5); +} + +static void log_tilde_dsp(t_log_tilde *x, t_signal **sp) +{ + dsp_add(log_tilde_perform, 4, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); +} + +static void log_tilde_setup(void) +{ + log_tilde_class = class_new(gensym("log~"), (t_newmethod)log_tilde_new, 0, + sizeof(t_log_tilde), 0, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(log_tilde_class, t_log_tilde, x_f); + class_addmethod(log_tilde_class, (t_method)log_tilde_dsp, gensym("dsp"), 0); +} + +/* ----------------------------- abs ----------------------------- */ +static t_class *abs_tilde_class; + +typedef struct _abs_tilde +{ + t_object x_obj; + t_float x_f; +} t_abs_tilde; + +static void *abs_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_abs_tilde *x = (t_abs_tilde *)pd_new(abs_tilde_class); + outlet_new(&x->x_obj, &s_signal); + return (x); +} + +t_int *abs_tilde_perform(t_int *w) +{ + t_sample *in1 = (t_sample *)(w[1]); + t_sample *out = (t_sample *)(w[2]); + int n = (int)(w[3]); + while (n--) + { + float f = *in1++; + *out = (f >= 0 ? f : -f); + } + return (w+4); +} + +static void abs_tilde_dsp(t_abs_tilde *x, t_signal **sp) +{ + dsp_add(abs_tilde_perform, 3, + sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); +} + +static void abs_tilde_setup(void) +{ + abs_tilde_class = class_new(gensym("abs~"), (t_newmethod)abs_tilde_new, 0, + sizeof(t_abs_tilde), 0, 0); + CLASS_MAINSIGNALIN(abs_tilde_class, t_abs_tilde, x_f); + class_addmethod(abs_tilde_class, (t_method)abs_tilde_dsp, gensym("dsp"), 0); +} /* ------------------------ global setup routine ------------------------- */ @@ -571,6 +754,10 @@ void d_math_setup(void) rmstodb_tilde_setup(); dbtopow_tilde_setup(); powtodb_tilde_setup(); + pow_tilde_setup(); + exp_tilde_setup(); + log_tilde_setup(); + abs_tilde_setup(); class_sethelpsymbol(mtof_tilde_class, s); class_sethelpsymbol(ftom_tilde_class, s); diff --git a/src/g_array.c b/src/g_array.c index 0ebc99fb814113dd47fdd0f2e4929699e4da37ae..a73c5ba544a07b9f9a8a5869f2bf9e90e8d368fc 100644 --- a/src/g_array.c +++ b/src/g_array.c @@ -1402,13 +1402,14 @@ static void garray_read(t_garray *x, t_symbol *filename) } for (i = 0; i < nelem; i++) { - if (!fscanf(fd, "%f", ((t_float *)(array->a_vec + - elemsize * i) + yonset))) + float f; + if (!fscanf(fd, "%f", &f)) { post("%s: read %d elements into table of size %d", filename->s_name, i, nelem); break; } + else *((t_float *)(array->a_vec + elemsize * i) + yonset) = f; } while (i < nelem) *((t_float *)(array->a_vec + diff --git a/src/g_canvas.c b/src/g_canvas.c index 36d3d3d64446d9d19e31903c5a708a7b60787b43..3220360f51a257401d6956a0ec4f09459ce47979 100644 --- a/src/g_canvas.c +++ b/src/g_canvas.c @@ -47,7 +47,7 @@ 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); -static void canvas_reflecttitle(t_canvas *x); +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); @@ -682,144 +682,6 @@ void canvas_redraw(t_canvas *x) } } -/* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */ - -static t_editor *editor_new(t_glist *owner) -{ - char buf[40]; - t_editor *x = (t_editor *)getbytes(sizeof(*x)); - x->e_connectbuf = binbuf_new(); - x->e_deleted = binbuf_new(); - x->e_glist = owner; - sprintf(buf, ".x%lx", (t_int)owner); - x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf)); - return (x); -} - -static void editor_free(t_editor *x, t_glist *y) -{ - glist_noselect(y); - guiconnect_notarget(x->e_guiconnect, 1000); - binbuf_free(x->e_connectbuf); - binbuf_free(x->e_deleted); - freebytes((void *)x, sizeof(*x)); -} - - /* recursively create or destroy all editors of a glist and its - sub-glists, as long as they aren't toplevels. */ -void canvas_create_editor(t_glist *x, int createit) -{ - t_gobj *y; - t_object *ob; - if (createit) - { - if (x->gl_editor) - bug("canvas_create_editor"); - else - { - x->gl_editor = editor_new(x); - for (y = x->gl_list; y; y = y->g_next) - if (ob = pd_checkobject(&y->g_pd)) - rtext_new(x, ob); - } - } - else - { - if (!x->gl_editor) - bug("canvas_create_editor"); - else - { - for (y = x->gl_list; y; y = y->g_next) - if (ob = pd_checkobject(&y->g_pd)) - rtext_free(glist_findrtext(x, ob)); - editor_free(x->gl_editor, x); - x->gl_editor = 0; - } - } - for (y = x->gl_list; y; y = y->g_next) - if (pd_class(&y->g_pd) == canvas_class && - ((t_canvas *)y)->gl_isgraph && !((t_canvas *)y)->gl_havewindow) - canvas_create_editor((t_canvas *)y, createit); -} - - /* we call this when we want the window to become visible, mapped, and - in front of all windows; or with "f" zero, when we want to get rid of - the window. */ -void canvas_vis(t_canvas *x, t_floatarg f) -{ - char buf[30]; - int flag = (f != 0); - if (flag) - { - /* post("havewindow %d, isgraph %d, isvisible %d editor %d", - x->gl_havewindow, x->gl_isgraph, glist_isvisible(x), - (x->gl_editor != 0)); */ - /* test if we're already visible and toplevel */ - if (x->gl_editor) - { /* just put us in front */ -#ifdef MSW - canvas_vis(x, 0); - canvas_vis(x, 1); -#else - sys_vgui("raise .x%lx\n", x); - sys_vgui("focus .x%lx.c\n", x); - sys_vgui("wm deiconify .x%lx\n", x); -#endif - } - else - { - canvas_create_editor(x, 1); - sys_vgui("pdtk_canvas_new .x%lx %d %d +%d+%d %d\n", x, - (int)(x->gl_screenx2 - x->gl_screenx1), - (int)(x->gl_screeny2 - x->gl_screeny1), - (int)(x->gl_screenx1), (int)(x->gl_screeny1), - x->gl_edit); - canvas_reflecttitle(x); - x->gl_havewindow = 1; - canvas_updatewindowlist(); - } - } - else /* make invisible */ - { - int i; - t_canvas *x2; - if (!x->gl_havewindow) - { - /* bug workaround -- a graph in a visible patch gets "invised" - when the patch is closed, and must lose the editor here. It's - probably not the natural place to do this. Other cases like - subpatches fall here too but don'd need the editor freed, so - we check if it exists. */ - if (x->gl_editor) - canvas_create_editor(x, 0); - return; - } - sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x); - glist_noselect(x); - if (glist_isvisible(x)) - canvas_map(x, 0); - canvas_create_editor(x, 0); - sys_vgui("destroy .x%lx\n", x); - for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++) - ; - sys_vgui(".mbar.find delete %d\n", i); - /* if we're a graph on our parent, and if the parent exists - and is visible, show ourselves on parent. */ - if (glist_isgraph(x) && x->gl_owner) - { - t_glist *gl2 = x->gl_owner; - if (!x->gl_owner->gl_isdeleting) - canvas_create_editor(x, 1); - if (glist_isvisible(gl2)) - gobj_vis(&x->gl_gobj, gl2, 0); - x->gl_havewindow = 0; - if (glist_isvisible(gl2)) - gobj_vis(&x->gl_gobj, gl2, 1); - } - else x->gl_havewindow = 0; - canvas_updatewindowlist(); - } -} /* we call this on a non-toplevel glist to "open" it into its own window. */ @@ -835,7 +697,8 @@ void glist_menu_open(t_glist *x) /* erase ourself in parent window */ gobj_vis(&x->gl_gobj, gl2, 0); /* get rid of our editor (and subeditors) */ - canvas_create_editor(x, 0); + if (x->gl_editor) + canvas_create_editor(x, 0); x->gl_havewindow = 1; /* redraw ourself in parent window (blanked out this time) */ gobj_vis(&x->gl_gobj, gl2, 1); @@ -1475,6 +1338,22 @@ void canvas_savedeclarationsto(t_canvas *x, t_binbuf *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; @@ -1496,12 +1375,8 @@ static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv) } else if ((argc > i+1) && !strcmp(flag, "-stdpath")) { - strncpy(strbuf, sys_libdir->s_name, MAXPDSTRING-3); - strbuf[MAXPDSTRING-4] = 0; - strcat(strbuf, "/"); - strncpy(strbuf, atom_getsymbolarg(i+1, argc, argv)->s_name, - MAXPDSTRING-strlen(strbuf)); - strbuf[MAXPDSTRING-1] = 0; + canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name, + strbuf, MAXPDSTRING); e->ce_path = namelist_append(e->ce_path, strbuf, 0); i++; } @@ -1512,12 +1387,8 @@ static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv) } else if ((argc > i+1) && !strcmp(flag, "-stdlib")) { - strncpy(strbuf, sys_libdir->s_name, MAXPDSTRING-3); - strbuf[MAXPDSTRING-4] = 0; - strcat(strbuf, "/"); - strncpy(strbuf, atom_getsymbolarg(i+1, argc, argv)->s_name, - MAXPDSTRING-strlen(strbuf)); - strbuf[MAXPDSTRING-1] = 0; + canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name, + strbuf, MAXPDSTRING); sys_load_lib(0, strbuf); i++; } @@ -1564,9 +1435,16 @@ int canvas_open(t_canvas *x, const char *name, const char *ext, for (nl = y->gl_env->ce_path; nl; nl = nl->nl_next) { char realname[MAXPDSTRING]; - strncpy(realname, dir, MAXPDSTRING); - realname[MAXPDSTRING-3] = 0; - strcat(realname, "/"); + if (sys_isabsolutepath(nl->nl_string)) + { + realname[0] = '\0'; + } + else + { /* if not absolute path, append Pd lib dir */ + strncpy(realname, dir, MAXPDSTRING); + realname[MAXPDSTRING-3] = 0; + strcat(realname, "/"); + } strncat(realname, nl->nl_string, MAXPDSTRING-strlen(realname)); realname[MAXPDSTRING-1] = 0; if ((fd = sys_trytoopenone(realname, name, ext, diff --git a/src/g_canvas.h b/src/g_canvas.h index e2b6626a4cf4eb7fac446046ccc6ed7e7a0b62bc..c074ad5c1e9012bd5026195b7fa61d4ff3ad1d9d 100644 --- a/src/g_canvas.h +++ b/src/g_canvas.h @@ -7,8 +7,8 @@ functions. "Glists" and "canvases" and "graphs" used to be different structures until being unified in version 0.35. A glist occupies its own window if the "gl_havewindow" flag is set. Its -appearance on its "parent" or "owner" (if it has one) is as a graph if -"gl_isgraph" is set, and otherwise as a text box. +appearance on its "parent", also called "owner", (if it has one) is as a graph +if "gl_isgraph" is set, and otherwise as a text box. A glist is "root" if it has no owner, i.e., a document window. In this case "gl_havewindow" is always set. @@ -353,6 +353,7 @@ EXTERN int gobj_click(t_gobj *x, struct _glist *glist, EXTERN void gobj_save(t_gobj *x, t_binbuf *b); EXTERN void gobj_properties(t_gobj *x, struct _glist *glist); EXTERN void gobj_save(t_gobj *x, t_binbuf *b); +EXTERN int gobj_shouldvis(t_gobj *x, struct _glist *glist); /* -------------------- functions on glists --------------------- */ EXTERN t_glist *glist_new( void); @@ -414,7 +415,6 @@ EXTERN int text_xcoord(t_text *x, t_glist *glist); EXTERN int text_ycoord(t_text *x, t_glist *glist); EXTERN int text_xpix(t_text *x, t_glist *glist); EXTERN int text_ypix(t_text *x, t_glist *glist); -EXTERN int text_shouldvis(t_text *x, t_glist *glist); /* -------------------- functions on rtexts ------------------------- */ #define RTEXT_DOWN 1 diff --git a/src/g_editor.c b/src/g_editor.c index a44d952a3e3c9a486bee9f7b9e56d4bfe27f3ea6..ee2a76ac531304daddbcd9964e636f0a315a3af9 100644 --- a/src/g_editor.c +++ b/src/g_editor.c @@ -61,28 +61,43 @@ void gobj_delete(t_gobj *x, t_glist *glist) (*x->g_pd->c_wb->w_deletefn)(x, glist); } +int gobj_shouldvis(t_gobj *x, struct _glist *glist) +{ + t_object *ob; + if (!glist->gl_havewindow && glist->gl_isgraph && glist->gl_goprect && + glist->gl_owner && (pd_class(&glist->gl_pd) != garray_class)) + { + /* if we're graphing-on-parent and the object falls outside the + graph rectangle, don't draw it. */ + int x1, y1, x2, y2, gx1, gy1, gx2, gy2, m; + gobj_getrect(&glist->gl_gobj, glist->gl_owner, &x1, &y1, &x2, &y2); + if (x1 > x2) + m = x1, x1 = x2, x2 = m; + if (y1 > y2) + m = y1, y1 = y2, y2 = m; + gobj_getrect(x, glist, &gx1, &gy1, &gx2, &gy2); + if (gx1 < x1 || gx1 > x2 || gx2 < x1 || gx2 > x2 || + gy1 < y1 || gy1 > y2 || gy2 < y1 || gy2 > y2) + return (0); + } + if (ob = pd_checkobject(&x->g_pd)) + { + /* return true if the text box should be drawn. We don't show text + boxes inside graphs---except comments, if we're doing the new + (goprect) style. */ + return (glist->gl_havewindow || + (ob->te_pd != canvas_class && + ob->te_pd->c_wb != &text_widgetbehavior) || + (ob->te_pd == canvas_class && (((t_glist *)ob)->gl_isgraph)) || + (glist->gl_goprect && (ob->te_type == T_TEXT))); + } + else return (1); +} + void gobj_vis(t_gobj *x, struct _glist *glist, int flag) { - if (x->g_pd->c_wb && x->g_pd->c_wb->w_visfn) - { - if (!glist->gl_havewindow && glist->gl_isgraph && glist->gl_goprect && - glist->gl_owner && (pd_class(&glist->gl_pd) != garray_class)) - { - /* if we're graphing-on-parent and the object falls outside the - graph rectangle, don't draw it. */ - int x1, y1, x2, y2, gx1, gy1, gx2, gy2, m; - gobj_getrect(&glist->gl_gobj, glist->gl_owner, &x1, &y1, &x2, &y2); - if (x1 > x2) - m = x1, x1 = x2, x2 = m; - if (y1 > y2) - m = y1, y1 = y2, y2 = m; - gobj_getrect(x, glist, &gx1, &gy1, &gx2, &gy2); - if (gx1 < x1 || gx1 > x2 || gx2 < x1 || gx2 > x2 || - gy1 < y1 || gy1 > y2 || gy2 < y1 || gy2 > y2) - return; - } + if (x->g_pd->c_wb && x->g_pd->c_wb->w_visfn && gobj_shouldvis(x, glist)) (*x->g_pd->c_wb->w_visfn)(x, glist, flag); - } } int gobj_click(t_gobj *x, struct _glist *glist, @@ -765,9 +780,8 @@ int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos, { int x1, y1, x2, y2; t_text *ob; - if ((ob = pd_checkobject(&y->g_pd)) && - !text_shouldvis(ob, x)) - return (0); + if (!gobj_shouldvis(y, x)) + return (0); gobj_getrect(y, x, &x1, &y1, &x2, &y2); if (xpos >= x1 && xpos <= x2 && ypos >= y1 && ypos <= y2) { @@ -817,12 +831,157 @@ static void canvas_rightclick(t_canvas *x, int xpos, int ypos, t_gobj *y) x, xpos, ypos, canprop, canopen); } +/* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */ + +static t_editor *editor_new(t_glist *owner) +{ + char buf[40]; + t_editor *x = (t_editor *)getbytes(sizeof(*x)); + x->e_connectbuf = binbuf_new(); + x->e_deleted = binbuf_new(); + x->e_glist = owner; + sprintf(buf, ".x%lx", (t_int)owner); + x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf)); + return (x); +} + +static void editor_free(t_editor *x, t_glist *y) +{ + glist_noselect(y); + guiconnect_notarget(x->e_guiconnect, 1000); + binbuf_free(x->e_connectbuf); + binbuf_free(x->e_deleted); + freebytes((void *)x, sizeof(*x)); +} + + /* recursively create or destroy all editors of a glist and its + sub-glists, as long as they aren't toplevels. */ +void canvas_create_editor(t_glist *x, int createit) +{ + t_gobj *y; + t_object *ob; + if (createit) + { + if (x->gl_editor) + bug("canvas_create_editor"); + else + { + x->gl_editor = editor_new(x); + for (y = x->gl_list; y; y = y->g_next) + if (ob = pd_checkobject(&y->g_pd)) + rtext_new(x, ob); + } + } + else + { + if (!x->gl_editor) + bug("canvas_create_editor"); + else + { + for (y = x->gl_list; y; y = y->g_next) + if (ob = pd_checkobject(&y->g_pd)) + rtext_free(glist_findrtext(x, ob)); + editor_free(x->gl_editor, x); + x->gl_editor = 0; + } + } + for (y = x->gl_list; y; y = y->g_next) + if (pd_class(&y->g_pd) == canvas_class && + ((t_canvas *)y)->gl_isgraph && !((t_canvas *)y)->gl_havewindow) + canvas_create_editor((t_canvas *)y, createit); +} + +void canvas_reflecttitle(t_canvas *x); +void canvas_map(t_canvas *x, t_floatarg f); + + /* we call this when we want the window to become visible, mapped, and + in front of all windows; or with "f" zero, when we want to get rid of + the window. */ +void canvas_vis(t_canvas *x, t_floatarg f) +{ + char buf[30]; + int flag = (f != 0); + if (flag) + { + /* post("havewindow %d, isgraph %d, isvisible %d editor %d", + x->gl_havewindow, x->gl_isgraph, glist_isvisible(x), + (x->gl_editor != 0)); */ + /* test if we're already visible and toplevel */ + if (x->gl_editor) + { /* just put us in front */ +#ifdef MSW + canvas_vis(x, 0); + canvas_vis(x, 1); +#else + sys_vgui("raise .x%lx\n", x); + sys_vgui("focus .x%lx.c\n", x); + sys_vgui("wm deiconify .x%lx\n", x); +#endif + } + else + { + canvas_create_editor(x, 1); + sys_vgui("pdtk_canvas_new .x%lx %d %d +%d+%d %d\n", x, + (int)(x->gl_screenx2 - x->gl_screenx1), + (int)(x->gl_screeny2 - x->gl_screeny1), + (int)(x->gl_screenx1), (int)(x->gl_screeny1), + x->gl_edit); + canvas_reflecttitle(x); + x->gl_havewindow = 1; + canvas_updatewindowlist(); + } + } + else /* make invisible */ + { + int i; + t_canvas *x2; + if (!x->gl_havewindow) + { + /* bug workaround -- a graph in a visible patch gets "invised" + when the patch is closed, and must lose the editor here. It's + probably not the natural place to do this. Other cases like + subpatches fall here too but don'd need the editor freed, so + we check if it exists. */ + if (x->gl_editor) + canvas_create_editor(x, 0); + return; + } + sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x); + glist_noselect(x); + if (glist_isvisible(x)) + canvas_map(x, 0); + canvas_create_editor(x, 0); + sys_vgui("destroy .x%lx\n", x); + for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++) + ; + sys_vgui(".mbar.find delete %d\n", i); + /* if we're a graph on our parent, and if the parent exists + and is visible, show ourselves on parent. */ + if (glist_isgraph(x) && x->gl_owner) + { + t_glist *gl2 = x->gl_owner; + if (!x->gl_owner->gl_isdeleting) + canvas_create_editor(x, 1); + if (glist_isvisible(gl2)) + gobj_vis(&x->gl_gobj, gl2, 0); + x->gl_havewindow = 0; + if (glist_isvisible(gl2)) + gobj_vis(&x->gl_gobj, gl2, 1); + } + else x->gl_havewindow = 0; + canvas_updatewindowlist(); + } +} + /* set a canvas up as a graph-on-parent. Set reasonable defaults for any missing paramters and redraw things if necessary. */ void canvas_setgraph(t_glist *x, int flag, int nogoprect) { if (!flag && glist_isgraph(x)) { + int hadeditor = (x->gl_editor != 0); + if (hadeditor) + canvas_create_editor(x, 0); if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner)) gobj_vis(&x->gl_gobj, x->gl_owner, 0); x->gl_isgraph = 0; @@ -831,6 +990,8 @@ void canvas_setgraph(t_glist *x, int flag, int nogoprect) gobj_vis(&x->gl_gobj, x->gl_owner, 1); canvas_fixlinesfor(x->gl_owner, &x->gl_obj); } + if (hadeditor) + canvas_create_editor(x, 1); } else if (flag) { diff --git a/src/g_graph.c b/src/g_graph.c index f4196def136bb0f69364113b899c0d46a41ea385..cfda6c2ca14d90ed8d4e8f121399acdcfcd9aa56 100644 --- a/src/g_graph.c +++ b/src/g_graph.c @@ -176,8 +176,9 @@ void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn, t_canvas *glist_getcanvas(t_glist *x) { - while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph) - x = x->gl_owner; + while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph && + gobj_shouldvis(&x->gl_gobj, x->gl_owner)) + x = x->gl_owner; return((t_canvas *)x); } @@ -671,7 +672,6 @@ void glist_redraw(t_glist *x) /* --------------------------- widget behavior ------------------- */ -extern t_widgetbehavior text_widgetbehavior; int garray_getname(t_garray *x, t_symbol **namep); @@ -904,7 +904,7 @@ static void graph_getrect(t_gobj *z, t_glist *glist, hadwindow = x->gl_havewindow; x->gl_havewindow = 0; for (g = x->gl_list; g; g = g->g_next) - if ((!(ob = pd_checkobject(&g->g_pd))) || text_shouldvis(ob, x)) + if (gobj_shouldvis(g, x)) { /* don't do this for arrays, just let them hang outside the box. */ @@ -1107,8 +1107,6 @@ void g_graph_setup(void) A_SYMBOL, A_FLOAT, A_SYMBOL, A_DEFFLOAT, A_NULL); class_addmethod(canvas_class, (t_method)canvas_menuarray, gensym("menuarray"), A_NULL); - class_addmethod(canvas_class, (t_method)glist_arraydialog, - gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); class_addmethod(canvas_class, (t_method)glist_sort, gensym("sort"), A_NULL); } diff --git a/src/g_template.c b/src/g_template.c index 4d66bbed55d1bd91e648945c4a8e0715d8b1198c..aff6f7cb443e5da78891836cf0a8c800f236654e 100644 --- a/src/g_template.c +++ b/src/g_template.c @@ -721,11 +721,11 @@ struct _fielddesc t_symbol *fd_symbol; /* the field is a constant symbol */ t_symbol *fd_varsym; /* the field is variable and this is the name */ } fd_un; - t_float fd_v1; /* min and max values */ - t_float fd_v2; - t_float fd_screen1; /* min and max screen values */ - t_float fd_screen2; - t_float fd_quantum; /* quantization in value */ + float fd_v1; /* min and max values */ + float fd_v2; + float fd_screen1; /* min and max screen values */ + float fd_screen2; + float fd_quantum; /* quantization in value */ }; static void fielddesc_setfloat_const(t_fielddesc *fd, t_float f) @@ -2225,7 +2225,7 @@ static void drawnumber_key(void *z, t_floatarg fkey) else { /* key entry for a numeric field. This is just a stopgap. */ - t_float newf; + float newf; if (drawnumber_motion_firstkey) sbuf[0] = 0; else sprintf(sbuf, "%g", template_getfloat(drawnumber_motion_template, diff --git a/src/g_text.c b/src/g_text.c index bbdb7729d3a980bec4299bf1398b5b269f62e0d0..1d4559ecd36464e40b28faea2f4b734a97c92a71 100644 --- a/src/g_text.c +++ b/src/g_text.c @@ -989,7 +989,7 @@ static void text_select(t_gobj *z, t_glist *glist, int state) t_text *x = (t_text *)z; t_rtext *y = glist_findrtext(glist, x); rtext_select(y, state); - if (glist_isvisible(glist) && text_shouldvis(x, glist)) + if (glist_isvisible(glist) && gobj_shouldvis(&x->te_g, glist)) sys_vgui(".x%lx.c itemconfigure %sR -fill %s\n", glist, rtext_gettag(y), (state? "blue" : "black")); } @@ -1007,22 +1007,12 @@ static void text_delete(t_gobj *z, t_glist *glist) canvas_deletelinesfor(glist, x); } - /* return true if the text box should be drawn. We don't show text boxes - inside graphs---except comments, if we're doing the new (goprect) style. */ -int text_shouldvis(t_text *x, t_glist *glist) -{ - return (glist->gl_havewindow || - (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) || - (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph)) || - (glist->gl_goprect && (x->te_type == T_TEXT))); -} - static void text_vis(t_gobj *z, t_glist *glist, int vis) { t_text *x = (t_text *)z; if (vis) { - if (text_shouldvis(x, glist)) + if (gobj_shouldvis(&x->te_g, glist)) { t_rtext *y = glist_findrtext(glist, x); if (x->te_type == T_ATOM) @@ -1035,7 +1025,7 @@ static void text_vis(t_gobj *z, t_glist *glist, int vis) else { t_rtext *y = glist_findrtext(glist, x); - if (text_shouldvis(x, glist)) + if (gobj_shouldvis(&x->te_g, glist)) { text_eraseborder(x, glist, rtext_gettag(y)); rtext_erase(y); diff --git a/src/m_class.c b/src/m_class.c index ab0b86bed226bfb76ed33e4b14a656f5ca8e53f0..cd4fbb1c60d0086b1988f0927a2f224bb2c46514 100644 --- a/src/m_class.c +++ b/src/m_class.c @@ -18,6 +18,10 @@ #include <string.h> #include <stdio.h> +#ifdef _MSC_VER /* This is only for Microsoft's compiler, not cygwin, e.g. */ +#define snprintf sprintf_s +#endif + static t_symbol *class_loadsym; /* name under which an extern is invoked */ static void pd_defaultfloat(t_pd *x, t_float f); static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv); @@ -149,7 +153,6 @@ static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv) argument form, one for the multiple one; see select_setup() to find out how this is handled. */ -extern t_widgetbehavior text_widgetbehavior; extern void text_save(t_gobj *z, t_binbuf *b); t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod, @@ -168,7 +171,7 @@ t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod, { if (count == MAXPDARG) { - error("class %s: sorry: only %d creation args allowed", + error("class %s: sorry: only %d args typechecked; use A_GIMME", s->s_name, MAXPDARG); break; } @@ -300,6 +303,19 @@ void class_addmethod(t_class *c, t_method fn, t_symbol *sel, } else { + int i; + for (i = 0; i < c->c_nmethod; i++) + if (c->c_methods[i].me_name == sel) + { + char nbuf[80]; + snprintf(nbuf, 80, "%s_aliased", sel->s_name); + c->c_methods[i].me_name = gensym(nbuf); + if (c == pd_objectmaker) + post("warning: class '%s' overwritten; old one renamed '%s'", + sel->s_name, nbuf); + else post("warning: old method '%s' for class '%s' renamed '%s'", + sel->s_name, c->c_name->s_name, nbuf); + } c->c_methods = t_resizebytes(c->c_methods, c->c_nmethod * sizeof(*c->c_methods), (c->c_nmethod + 1) * sizeof(*c->c_methods)); @@ -753,19 +769,22 @@ badarg: s->s_name, c->c_name->s_name); } + /* convenience routine giving a stdarg interface to typedmess(). Only + ten args supported; it seems unlikely anyone will need more since + longer messages are likely to be programmatically generated anyway. */ void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...) { va_list ap; - t_atom arg[MAXPDARG], *at =arg; + t_atom arg[10], *at = arg; int nargs = 0; char *fp = fmt; va_start(ap, fmt); while (1) { - if (nargs > MAXPDARG) + if (nargs >= 10) { - pd_error(x, "pd_vmess: only %d allowed", MAXPDARG); + pd_error(x, "pd_vmess: only 10 allowed"); break; } switch(*fp++) diff --git a/src/m_pd.h b/src/m_pd.h index 580bac0b8ea2a3dc0bdb3ddacb63993eb0fd37e5..f48a13b915f6f5460b388d98a9ec89ae203a1574 100644 --- a/src/m_pd.h +++ b/src/m_pd.h @@ -9,9 +9,9 @@ extern "C" { #endif #define PD_MAJOR_VERSION 0 -#define PD_MINOR_VERSION 41 -#define PD_BUGFIX_VERSION 4 -#define PD_TEST_VERSION "" +#define PD_MINOR_VERSION 42 +#define PD_BUGFIX_VERSION 0 +#define PD_TEST_VERSION "test1" /* 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 */ @@ -55,11 +55,15 @@ extern "C" { #define MAXPDARG 5 /* max number of args we can typecheck today */ /* signed and unsigned integer types the size of a pointer: */ -/* GG: long is the size of a pointer */ -typedef long t_int; - -typedef float t_float; /* a floating-point number at most the same size */ -typedef float t_floatarg; /* floating-point type for function calls */ +#if !defined(PD_LONGINTTYPE) +#define PD_LONGINTTYPE long +#endif +#if !defined(PD_FLOATTYPE) +#define PD_FLOATTYPE float +#endif +typedef PD_LONGINTTYPE t_int; /* pointer-size integer */ +typedef PD_FLOATTYPE t_float; /* a float type at most the same size */ +typedef PD_FLOATTYPE t_floatarg; /* float type for function calls */ typedef struct _symbol { @@ -443,7 +447,7 @@ EXTERN t_propertiesfn class_getpropertiesfn(t_class *c); EXTERN void post(const char *fmt, ...); EXTERN void startpost(const char *fmt, ...); EXTERN void poststring(const char *s); -EXTERN void postfloat(float f); +EXTERN void postfloat(t_floatarg f); EXTERN void postatom(int argc, t_atom *argv); EXTERN void endpost(void); EXTERN void error(const char *fmt, ...); @@ -457,6 +461,7 @@ EXTERN void sys_ouch(void); /* ------------ system interface routines ------------------- */ EXTERN int sys_isreadablefile(const char *name); +EXTERN int sys_isabsolutepath(const char *dir); EXTERN void sys_bashfilename(const char *from, char *to); EXTERN void sys_unbashfilename(const char *from, char *to); EXTERN int open_via_path(const char *name, const char *ext, const char *dir, @@ -474,7 +479,7 @@ EXTERN int sys_trylock(void); /* --------------- signals ----------------------------------- */ -typedef float t_sample; +typedef PD_FLOATTYPE t_sample; #define MAXLOGSIG 32 #define MAXSIGSIZE (1 << MAXLOGSIG) diff --git a/src/notes.txt b/src/notes.txt index ea8ed631d312e76b6330751c5b7816c96ccb0873..622b6548a327a4a3f65e11185a34b8dcd39cacc1 100644 --- a/src/notes.txt +++ b/src/notes.txt @@ -1,4 +1,6 @@ ---------------- dolist -------------------- +done: + test: compile on various versions of linux windows: @@ -43,6 +45,7 @@ scofo reports error on reading score1.txt loading e-mailed patches without removing headers crashes pd check if _vsnprintf with zero argument in windows works any better... detect adc~ and dac~ reblocking +wierd bug: help doesn't work if pd is started in 5.reference directory more demonstration patches: vibrato using variable delay @@ -50,6 +53,8 @@ real-time spectrum grapher document ||, |, etc, better features: +pasting should look at current mouse location +optionally suppress leading "." directories and files on "open" change config.h to #ifdef _MSC_VER (include MSW fake) else include a real one stick snprintf alias in the MSW fake. flag to prevent unlocking patches @@ -80,7 +85,6 @@ tables: flag to hide array names think of a way to embed abstractions in a patch make watchdog work for MACOSX -pasting should look at current mouse location delete-in-rectangle message to Pds put serial object in main dist (see rat@telecoma, Apr. 25; winfried May 22) open/save panel to take messages to init directory, and to set extent list diff --git a/src/s_loader.c b/src/s_loader.c index aac508985cefca41c255558782b70b03e4121aa4..c608508cd18fcd612a119a5ac8e334dfe9bb066c 100644 --- a/src/s_loader.c +++ b/src/s_loader.c @@ -247,7 +247,7 @@ int sys_run_scheduler(const char *externalschedlibname, typedef int (*t_externalschedlibmain)(const char *); t_externalschedlibmain externalmainfunc; char filename[MAXPDSTRING]; - snprintf(filename, sizeof(filename), "%s.%s", externalschedlibname, + snprintf(filename, sizeof(filename), "%s%s", externalschedlibname, sys_dllextent); sys_bashfilename(filename, filename); #ifdef MSW diff --git a/src/s_main.c b/src/s_main.c index 877ed41f626953dc8e90b26c7240acdb3243b67d..dc4c3f6e9408269de00b11ac63009ee3a32563e8 100644 --- a/src/s_main.c +++ b/src/s_main.c @@ -282,7 +282,8 @@ int sys_main(int argc, char **argv) if (!noprefs) sys_loadpreferences(); /* load default settings */ #ifndef MSW - sys_rcfile(); /* parse the startup file */ + if (!noprefs) + sys_rcfile(); /* parse the startup file */ #endif if (sys_argparse(argc-1, argv+1)) /* parse cmd line */ return (1); @@ -391,6 +392,8 @@ static char *(usagemessage[]) = { "-nrt -- don't use real-time priority\n", #endif "-nosleep -- spin, don't sleep (may lower latency on multi-CPUs)\n", +"-schedlib <file> -- plug in external scheduler\n", +"-extraflags <s> -- string argument to send schedlib\n", }; static void sys_parsedevlist(int *np, int *vecp, int max, char *str) @@ -809,7 +812,7 @@ int sys_argparse(int argc, char **argv) sys_listplease = 1; argc--; argv++; } - else if (!strcmp(*argv, "-schedlib")) + else if (!strcmp(*argv, "-schedlib") && argc > 1) { sys_externalschedlib = 1; strncpy(sys_externalschedlibname, argv[1], @@ -817,7 +820,7 @@ int sys_argparse(int argc, char **argv) argv += 2; argc -= 2; } - else if (!strcmp(*argv, "-extraflags")) + else if (!strcmp(*argv, "-extraflags") && argc > 1) { sys_extraflags = 1; strncpy(sys_extraflagsstring, argv[1], diff --git a/src/s_midi_oss.c b/src/s_midi_oss.c index 354dc0d58457705c5d4a77365da03a8e7902cc0e..e1f7c8c63378013e44af685df71761597e6435d6 100644 --- a/src/s_midi_oss.c +++ b/src/s_midi_oss.c @@ -81,7 +81,7 @@ void sys_do_open_midi(int nmidiin, int *midiinvec, if (outdevindex >= 0 && fd >= 0) oss_midioutfd[outdevindex] = fd; } - if (devno == 1 && fd < 0) + if (devno == 0 && fd < 0) { sys_setalarm(1000000); fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG); @@ -116,7 +116,7 @@ void sys_do_open_midi(int nmidiin, int *midiinvec, int fd = oss_midioutfd[i]; char namebuf[80]; int devno = midioutvec[i]; - if (devno == 1 && fd < 0) + if (devno == 0 && fd < 0) { sys_setalarm(1000000); fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG); diff --git a/src/s_path.c b/src/s_path.c index f59f09c77cb1da0146d2ca1719d9318af28cb542..ef4411844a21d019ab8cde647b447147d256c9c2 100644 --- a/src/s_path.c +++ b/src/s_path.c @@ -69,6 +69,24 @@ void sys_unbashfilename(const char *from, char *to) *to = 0; } +/* test if path is absolute or relative, based on leading /, env vars, ~, etc */ +int sys_isabsolutepath(const char *dir) +{ + if (dir[0] == '/' || dir[0] == '~' +#ifdef MSW + || dir[0] == '%' || (dir[1] == ':' && dir[2] == '/') +#endif + ) + { + return 1; + } + else + { + return 0; + } +} + + /******************* Utility functions used below ******************/ /*! @@ -250,11 +268,7 @@ int sys_trytoopenone(const char *dir, const char *name, const char* ext, int sys_open_absolute(const char *name, const char* ext, char *dirresult, char **nameresult, unsigned int size, int bin, int *fdp) { - if (name[0] == '/' -#ifdef MSW - || (name[1] == ':' && name[2] == '/') -#endif - ) + if (sys_isabsolutepath(name)) { char dirbuf[MAXPDSTRING]; int dirlen = (strrchr(name, '/') - name); diff --git a/src/s_stuff.h b/src/s_stuff.h index a1f9026c4d336967b6a24ed20c2ad7ad57dd4ec8..e53d3edc9b918eac29342ee45b450a61e3b0ef95 100644 --- a/src/s_stuff.h +++ b/src/s_stuff.h @@ -325,3 +325,4 @@ EXTERN void inmidi_polyaftertouch(int portno, int pitch, int value); /* } jsarlo */ +extern t_widgetbehavior text_widgetbehavior; diff --git a/src/x_arithmetic.c b/src/x_arithmetic.c index f64c8cbd46bf9266b06798d1bfd23196cc1e65c0..0dd199372b260166e2b266b8d6cc81ed70c31ce4 100644 --- a/src/x_arithmetic.c +++ b/src/x_arithmetic.c @@ -623,7 +623,6 @@ static void log_float(t_object *x, t_float f) outlet_float(x->ob_outlet, r); } - static t_class *exp_class; /* ----------- exp --------------- */ static void *exp_new(void) @@ -659,6 +658,20 @@ static void abs_float(t_object *x, t_float f) outlet_float(x->ob_outlet, fabsf(f)); } +static t_class *wrap_class; /* ----------- wrap --------------- */ + +static void *wrap_new(void) +{ + t_object *x = (t_object *)pd_new(wrap_class); + outlet_new(x, &s_float); + return (x); +} + +static void wrap_float(t_object *x, t_float f) +{ + outlet_float(x->ob_outlet, f - floor(f)); +} + /* ------------------------ misc ------------------------ */ static t_class *clip_class; @@ -898,6 +911,11 @@ void x_arithmetic_setup(void) class_addfloat(abs_class, (t_method)abs_float); class_sethelpsymbol(abs_class, math_sym); + wrap_class = class_new(gensym("wrap"), wrap_new, 0, + sizeof(t_object), 0, 0); + class_addfloat(wrap_class, (t_method)wrap_float); + class_sethelpsymbol(wrap_class, math_sym); + /* ------------------------ misc ------------------------ */ clip_setup(); diff --git a/src/x_time.c b/src/x_time.c index 60dcf9a50ffe801adeaeea235112a7af96a2e134..5dc9d37ffeda5b2b867b379b6b73aba4206b2c08 100644 --- a/src/x_time.c +++ b/src/x_time.c @@ -334,7 +334,7 @@ static void *pipe_new(t_symbol *s, int argc, t_atom *argv) { char stupid[80]; atom_string(&argv[argc-1], stupid, 79); - post("pipe: %s: bad time delay value", stupid); + pd_error(x, "pipe: %s: bad time delay value", stupid); deltime = 0; } else deltime = argv[argc-1].a_w.w_float; @@ -385,7 +385,7 @@ static void *pipe_new(t_symbol *s, int argc, t_atom *argv) } else { - if (c != 'f') error("pack: %s: bad type", + if (c != 'f') pd_error(x, "pipe: %s: bad type", ap->a_w.w_symbol->s_name); SETFLOAT(&vp->p_atom, 0); vp->p_outlet = outlet_new(&x->x_obj, &s_float); @@ -437,7 +437,7 @@ static void hang_tick(t_hang *h) case A_POINTER: if (gpointer_check(w->w_gpointer, 1)) outlet_pointer(p->p_outlet, w->w_gpointer); - else post("pipe: stale pointer"); + else pd_error(x, "pipe: stale pointer"); break; } } @@ -454,7 +454,13 @@ static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) t_atom *ap; t_word *w; h->h_gp = (t_gpointer *)getbytes(x->x_nptr * sizeof(t_gpointer)); - if (ac > n) ac = n; + if (ac > n) + { + if (av[n].a_type == A_FLOAT) + x->x_deltime = av[n].a_w.w_float; + else pd_error(x, "pipe: symbol or pointer in time inlet"); + ac = n; + } for (i = 0, gp = x->x_gp, p = x->x_vec, ap = av; i < ac; i++, p++, ap++) { @@ -465,7 +471,7 @@ static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) case A_POINTER: gpointer_unset(gp); if (ap->a_type != A_POINTER) - post("pipe: bad pointer"); + pd_error(x, "pipe: bad pointer"); else { *gp = *(ap->a_w.w_gpointer);