summaryrefslogtreecommitdiffstats
path: root/apps/plugins/pdbox/PDa/src
diff options
context:
space:
mode:
authorPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
committerPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
commit513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch)
tree10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/src
parent95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff)
downloadrockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.gz
rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.bz2
rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.zip
Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin project of Wincent Balin. Stripped some non-sourcefiles and added a rockbox readme that needs a bit more info from Wincent. Is added to CATEGORIES and viewers, but not yet to SUBDIRS (ie doesn't build yet)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21044 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src')
-rw-r--r--apps/plugins/pdbox/PDa/src/build.ipod10
-rw-r--r--apps/plugins/pdbox/PDa/src/d_arithmetic.c1684
-rw-r--r--apps/plugins/pdbox/PDa/src/d_array.c2148
-rw-r--r--apps/plugins/pdbox/PDa/src/d_ctl.c1568
-rw-r--r--apps/plugins/pdbox/PDa/src/d_dac.c368
-rw-r--r--apps/plugins/pdbox/PDa/src/d_delay.c638
-rw-r--r--apps/plugins/pdbox/PDa/src/d_fft.c688
-rw-r--r--apps/plugins/pdbox/PDa/src/d_fftroutine.c2002
-rw-r--r--apps/plugins/pdbox/PDa/src/d_filter.c1094
-rw-r--r--apps/plugins/pdbox/PDa/src/d_global.c616
-rw-r--r--apps/plugins/pdbox/PDa/src/d_imayer_fft.c1032
-rw-r--r--apps/plugins/pdbox/PDa/src/d_imayer_tables.h100
-rw-r--r--apps/plugins/pdbox/PDa/src/d_math.c1146
-rw-r--r--apps/plugins/pdbox/PDa/src/d_mayer_fft.c838
-rw-r--r--apps/plugins/pdbox/PDa/src/d_misc.c524
-rw-r--r--apps/plugins/pdbox/PDa/src/d_osc.c1070
-rw-r--r--apps/plugins/pdbox/PDa/src/d_resample.c450
-rw-r--r--apps/plugins/pdbox/PDa/src/d_soundfile.c4734
-rw-r--r--apps/plugins/pdbox/PDa/src/d_ugen.c2252
-rw-r--r--apps/plugins/pdbox/PDa/src/delme.pd16
-rw-r--r--apps/plugins/pdbox/PDa/src/g_all_guis.c1324
-rw-r--r--apps/plugins/pdbox/PDa/src/g_all_guis.h658
-rw-r--r--apps/plugins/pdbox/PDa/src/g_array.c2734
-rw-r--r--apps/plugins/pdbox/PDa/src/g_bang.c1108
-rw-r--r--apps/plugins/pdbox/PDa/src/g_canvas.c2952
-rw-r--r--apps/plugins/pdbox/PDa/src/g_canvas.h1204
-rw-r--r--apps/plugins/pdbox/PDa/src/g_editor.c4548
-rw-r--r--apps/plugins/pdbox/PDa/src/g_graph.c2224
-rw-r--r--apps/plugins/pdbox/PDa/src/g_guiconnect.c188
-rw-r--r--apps/plugins/pdbox/PDa/src/g_hdial.c1470
-rw-r--r--apps/plugins/pdbox/PDa/src/g_hslider.c1308
-rw-r--r--apps/plugins/pdbox/PDa/src/g_io.c1224
-rw-r--r--apps/plugins/pdbox/PDa/src/g_mycanvas.c770
-rw-r--r--apps/plugins/pdbox/PDa/src/g_numbox.c1814
-rw-r--r--apps/plugins/pdbox/PDa/src/g_readwrite.c1446
-rw-r--r--apps/plugins/pdbox/PDa/src/g_rtext.c972
-rw-r--r--apps/plugins/pdbox/PDa/src/g_scalar.c802
-rw-r--r--apps/plugins/pdbox/PDa/src/g_template.c3358
-rw-r--r--apps/plugins/pdbox/PDa/src/g_text.c2632
-rw-r--r--apps/plugins/pdbox/PDa/src/g_toggle.c948
-rw-r--r--apps/plugins/pdbox/PDa/src/g_traversal.c2168
-rw-r--r--apps/plugins/pdbox/PDa/src/g_vdial.c1432
-rw-r--r--apps/plugins/pdbox/PDa/src/g_vslider.c1254
-rw-r--r--apps/plugins/pdbox/PDa/src/g_vumeter.c1426
-rw-r--r--apps/plugins/pdbox/PDa/src/m_atom.c258
-rw-r--r--apps/plugins/pdbox/PDa/src/m_binbuf.c2438
-rw-r--r--apps/plugins/pdbox/PDa/src/m_class.c1648
-rw-r--r--apps/plugins/pdbox/PDa/src/m_conf.c202
-rw-r--r--apps/plugins/pdbox/PDa/src/m_fixed.c252
-rw-r--r--apps/plugins/pdbox/PDa/src/m_fixed.h110
-rw-r--r--apps/plugins/pdbox/PDa/src/m_glob.c210
-rw-r--r--apps/plugins/pdbox/PDa/src/m_imp.h156
-rw-r--r--apps/plugins/pdbox/PDa/src/m_memory.c178
-rw-r--r--apps/plugins/pdbox/PDa/src/m_obj.c1394
-rw-r--r--apps/plugins/pdbox/PDa/src/m_pd.c612
-rw-r--r--apps/plugins/pdbox/PDa/src/m_pd.h1300
-rw-r--r--apps/plugins/pdbox/PDa/src/m_sched.c1162
-rw-r--r--apps/plugins/pdbox/PDa/src/makecostab.c50
-rw-r--r--apps/plugins/pdbox/PDa/src/makefile354
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio.c1746
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_alsa.c1890
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_mmio.c1588
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_oss.c1688
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_pa.c584
-rw-r--r--apps/plugins/pdbox/PDa/src/s_entry.c102
-rw-r--r--apps/plugins/pdbox/PDa/src/s_file.c110
-rw-r--r--apps/plugins/pdbox/PDa/src/s_inter.c2000
-rw-r--r--apps/plugins/pdbox/PDa/src/s_loader.c338
-rw-r--r--apps/plugins/pdbox/PDa/src/s_main.c1676
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi.c1282
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi_oss.c718
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi_pm.c332
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi_sgi.c376
-rw-r--r--apps/plugins/pdbox/PDa/src/s_path.c820
-rw-r--r--apps/plugins/pdbox/PDa/src/s_print.c300
-rw-r--r--apps/plugins/pdbox/PDa/src/s_stuff.h430
-rw-r--r--apps/plugins/pdbox/PDa/src/s_watchdog.c94
-rw-r--r--apps/plugins/pdbox/PDa/src/t_main.c240
-rw-r--r--apps/plugins/pdbox/PDa/src/t_tk.h20
-rw-r--r--apps/plugins/pdbox/PDa/src/t_tkcmd.c796
-rw-r--r--apps/plugins/pdbox/PDa/src/u_main.tk6734
-rw-r--r--apps/plugins/pdbox/PDa/src/u_pdreceive.c650
-rw-r--r--apps/plugins/pdbox/PDa/src/u_pdsend.c314
-rw-r--r--apps/plugins/pdbox/PDa/src/x_acoustics.c386
-rw-r--r--apps/plugins/pdbox/PDa/src/x_arithmetic.c1792
-rw-r--r--apps/plugins/pdbox/PDa/src/x_connective.c2904
-rw-r--r--apps/plugins/pdbox/PDa/src/x_gui.c754
-rw-r--r--apps/plugins/pdbox/PDa/src/x_interface.c156
-rw-r--r--apps/plugins/pdbox/PDa/src/x_midi.c2626
-rw-r--r--apps/plugins/pdbox/PDa/src/x_misc.c642
-rw-r--r--apps/plugins/pdbox/PDa/src/x_net.c726
-rw-r--r--apps/plugins/pdbox/PDa/src/x_qlist.c690
-rw-r--r--apps/plugins/pdbox/PDa/src/x_time.c1040
93 files changed, 109810 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/build.ipod b/apps/plugins/pdbox/PDa/src/build.ipod
new file mode 100644
index 0000000000..bb78632b2d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/build.ipod
@@ -0,0 +1,10 @@
+
+# The compiler for iPod has a bug with -O6, thats why we try to compile twice
+
+make CFLAGS="-O6 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi " -k ipod
+make CFLAGS="-O2 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi" ipod
+
+# The compiler for iPod has a bug with -O6, thats why we try to compile twice
+
+make CFLAGS="-O6 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi " -k ipod
+make CFLAGS="-O2 -ffast-math -fexpensive-optimizations -mcpu=arm7tdmi" ipod
diff --git a/apps/plugins/pdbox/PDa/src/d_arithmetic.c b/apps/plugins/pdbox/PDa/src/d_arithmetic.c
new file mode 100644
index 0000000000..72404ba50d
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_arithmetic.c
@@ -0,0 +1,1684 @@
+/* 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. */
+
+/* arithmetic binops (+, -, *, /).
+If no creation argument is given, there are two signal inlets for vector/vector
+operation; otherwise it's vector/scalar and the second inlet takes a float
+to reset the value.
+*/
+
+#include "m_pd.h"
+
+/* ----------------------------- plus ----------------------------- */
+static t_class *plus_class, *scalarplus_class;
+
+typedef struct _plus
+{
+ t_object x_obj;
+ float x_f;
+} t_plus;
+
+typedef struct _scalarplus
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g; /* inlet value */
+} t_scalarplus;
+
+static void *plus_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("+~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarplus *x = (t_scalarplus *)pd_new(scalarplus_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_plus *x = (t_plus *)pd_new(plus_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 *plus_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--) *out++ = *in1++ + *in2++;
+ return (w+5);
+}
+
+t_int *plus_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = f0 + g0; out[1] = f1 + g1; out[2] = f2 + g2; out[3] = f3 + g3;
+ out[4] = f4 + g4; out[5] = f5 + g5; out[6] = f6 + g6; out[7] = f7 + g7;
+ }
+ return (w+5);
+}
+
+t_int *scalarplus_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ + f;
+ return (w+5);
+}
+
+t_int *scalarplus_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 + g; out[1] = f1 + g; out[2] = f2 + g; out[3] = f3 + g;
+ out[4] = f4 + g; out[5] = f5 + g; out[6] = f6 + g; out[7] = f7 + g;
+ }
+ return (w+5);
+}
+
+void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(plus_perform, 4, in1, in2, out, n);
+ else
+ dsp_add(plus_perf8, 4, in1, in2, out, n);
+}
+
+static void plus_dsp(t_plus *x, t_signal **sp)
+{
+ dsp_add_plus(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarplus_dsp(t_scalarplus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarplus_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarplus_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void plus_setup(void)
+{
+ plus_class = class_new(gensym("+~"), (t_newmethod)plus_new, 0,
+ sizeof(t_plus), 0, A_GIMME, 0);
+ class_addmethod(plus_class, (t_method)plus_dsp, gensym("dsp"), 0);
+ CLASS_MAINSIGNALIN(plus_class, t_plus, x_f);
+ class_sethelpsymbol(plus_class, gensym("sigbinops"));
+ scalarplus_class = class_new(gensym("+~"), 0, 0,
+ sizeof(t_scalarplus), 0, 0);
+ CLASS_MAINSIGNALIN(scalarplus_class, t_scalarplus, x_f);
+ class_addmethod(scalarplus_class, (t_method)scalarplus_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarplus_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- minus ----------------------------- */
+static t_class *minus_class, *scalarminus_class;
+
+typedef struct _minus
+{
+ t_object x_obj;
+ float x_f;
+} t_minus;
+
+typedef struct _scalarminus
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarminus;
+
+static void *minus_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("-~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarminus *x = (t_scalarminus *)pd_new(scalarminus_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_minus *x = (t_minus *)pd_new(minus_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 *minus_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--) *out++ = *in1++ - *in2++;
+ return (w+5);
+}
+
+t_int *minus_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = f0 - g0; out[1] = f1 - g1; out[2] = f2 - g2; out[3] = f3 - g3;
+ out[4] = f4 - g4; out[5] = f5 - g5; out[6] = f6 - g6; out[7] = f7 - g7;
+ }
+ return (w+5);
+}
+
+t_int *scalarminus_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ - f;
+ return (w+5);
+}
+
+t_int *scalarminus_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 - g; out[1] = f1 - g; out[2] = f2 - g; out[3] = f3 - g;
+ out[4] = f4 - g; out[5] = f5 - g; out[6] = f6 - g; out[7] = f7 - g;
+ }
+ return (w+5);
+}
+
+static void minus_dsp(t_minus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(minus_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(minus_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarminus_dsp(t_scalarminus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarminus_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarminus_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void minus_setup(void)
+{
+ minus_class = class_new(gensym("-~"), (t_newmethod)minus_new, 0,
+ sizeof(t_minus), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(minus_class, t_minus, x_f);
+ class_addmethod(minus_class, (t_method)minus_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(minus_class, gensym("sigbinops"));
+ scalarminus_class = class_new(gensym("-~"), 0, 0,
+ sizeof(t_scalarminus), 0, 0);
+ CLASS_MAINSIGNALIN(scalarminus_class, t_scalarminus, x_f);
+ class_addmethod(scalarminus_class, (t_method)scalarminus_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarminus_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- times ----------------------------- */
+
+static t_class *times_class, *scalartimes_class;
+
+typedef struct _times
+{
+ t_object x_obj;
+ float x_f;
+} t_times;
+
+typedef struct _scalartimes
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalartimes;
+
+static void *times_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("*~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalartimes *x = (t_scalartimes *)pd_new(scalartimes_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_times *x = (t_times *)pd_new(times_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 *times_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--) *out++ = mult(*in1++,*in2++);
+ return (w+5);
+}
+
+t_int *times_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = mult(f0,g0); out[1] = mult(f1,g1); out[2] = mult(f2,g2); out[3] = mult(f3,g3);
+ out[4] = mult(f4,g4); out[5] = mult(f5,g5); out[6] = mult(f6,g6); out[7] = mult(f7,g7);
+ }
+ return (w+5);
+}
+
+t_int *scalartimes_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = mult(*in++,f);
+ return (w+5);
+}
+
+t_int *scalartimes_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
+ out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
+ }
+ return (w+5);
+}
+
+static void times_dsp(t_times *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(times_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(times_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalartimes_dsp(t_scalartimes *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalartimes_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalartimes_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void times_setup(void)
+{
+ times_class = class_new(gensym("*~"), (t_newmethod)times_new, 0,
+ sizeof(t_times), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(times_class, t_times, x_f);
+ class_addmethod(times_class, (t_method)times_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(times_class, gensym("sigbinops"));
+ scalartimes_class = class_new(gensym("*~"), 0, 0,
+ sizeof(t_scalartimes), 0, 0);
+ CLASS_MAINSIGNALIN(scalartimes_class, t_scalartimes, x_f);
+ class_addmethod(scalartimes_class, (t_method)scalartimes_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalartimes_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- over ----------------------------- */
+static t_class *over_class, *scalarover_class;
+
+typedef struct _over
+{
+ t_object x_obj;
+ float x_f;
+} t_over;
+
+typedef struct _scalarover
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarover;
+
+static void *over_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("/~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarover *x = (t_scalarover *)pd_new(scalarover_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_over *x = (t_over *)pd_new(over_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 *over_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 g = *in2++;
+ *out++ = (g ? *in1++ / g : 0);
+ }
+ return (w+5);
+}
+
+t_int *over_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (g0? idiv(f0,g0) : 0);
+ out[1] = (g1? idiv(f1,g1) : 0);
+ out[2] = (g2? idiv(f2,g2) : 0);
+ out[3] = (g3? idiv(f3,g3) : 0);
+ out[4] = (g4? idiv(f4,g4) : 0);
+ out[5] = (g5? idiv(f5,g5) : 0);
+ out[6] = (g6? idiv(f6,g6) : 0);
+ out[7] = (g7? idiv(f7,g7) : 0);
+ }
+ return (w+5);
+}
+
+t_int *scalarover_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = idiv(ftofix(1.),ftofix(*(t_float *)(w[2])));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = mult(*in++,f);
+ return (w+5);
+}
+
+t_int *scalarover_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ if (g) g = idiv(ftofix(1.f),g);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
+ out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
+ }
+ return (w+5);
+}
+
+static void over_dsp(t_over *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(over_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(over_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarover_dsp(t_scalarover *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarover_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarover_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void over_setup(void)
+{
+ over_class = class_new(gensym("/~"), (t_newmethod)over_new, 0,
+ sizeof(t_over), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(over_class, t_over, x_f);
+ class_addmethod(over_class, (t_method)over_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(over_class, gensym("sigbinops"));
+ scalarover_class = class_new(gensym("/~"), 0, 0,
+ sizeof(t_scalarover), 0, 0);
+ CLASS_MAINSIGNALIN(scalarover_class, t_scalarover, x_f);
+ class_addmethod(scalarover_class, (t_method)scalarover_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarover_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- max ----------------------------- */
+static t_class *max_class, *scalarmax_class;
+
+typedef struct _max
+{
+ t_object x_obj;
+ float x_f;
+} t_max;
+
+typedef struct _scalarmax
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarmax;
+
+static void *max_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("max~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarmax *x = (t_scalarmax *)pd_new(scalarmax_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_max *x = (t_max *)pd_new(max_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 *max_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--)
+ {
+ t_sample f = *in1++, g = *in2++;
+ *out++ = (f > g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *max_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (f0 > g0 ? f0 : g0); out[1] = (f1 > g1 ? f1 : g1);
+ out[2] = (f2 > g2 ? f2 : g2); out[3] = (f3 > g3 ? f3 : g3);
+ out[4] = (f4 > g4 ? f4 : g4); out[5] = (f5 > g5 ? f5 : g5);
+ out[6] = (f6 > g6 ? f6 : g6); out[7] = (f7 > g7 ? f7 : g7);
+ }
+ return (w+5);
+}
+
+t_int *scalarmax_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ t_sample g = *in++;
+ *out++ = (f > g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *scalarmax_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = (f0 > g ? f0 : g); out[1] = (f1 > g ? f1 : g);
+ out[2] = (f2 > g ? f2 : g); out[3] = (f3 > g ? f3 : g);
+ out[4] = (f4 > g ? f4 : g); out[5] = (f5 > g ? f5 : g);
+ out[6] = (f6 > g ? f6 : g); out[7] = (f7 > g ? f7 : g);
+ }
+ return (w+5);
+}
+
+static void max_dsp(t_max *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(max_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(max_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarmax_dsp(t_scalarmax *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarmax_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarmax_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void max_setup(void)
+{
+ max_class = class_new(gensym("max~"), (t_newmethod)max_new, 0,
+ sizeof(t_max), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(max_class, t_max, x_f);
+ class_addmethod(max_class, (t_method)max_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(max_class, gensym("sigbinops"));
+ scalarmax_class = class_new(gensym("max~"), 0, 0,
+ sizeof(t_scalarmax), 0, 0);
+ CLASS_MAINSIGNALIN(scalarmax_class, t_scalarmax, x_f);
+ class_addmethod(scalarmax_class, (t_method)scalarmax_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarmax_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- min ----------------------------- */
+static t_class *min_class, *scalarmin_class;
+
+typedef struct _min
+{
+ t_object x_obj;
+ float x_f;
+} t_min;
+
+typedef struct _scalarmin
+{
+ t_object x_obj;
+ t_float x_g;
+ float x_f;
+} t_scalarmin;
+
+static void *min_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("min~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarmin *x = (t_scalarmin *)pd_new(scalarmin_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_min *x = (t_min *)pd_new(min_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 *min_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--)
+ {
+ t_sample f = *in1++, g = *in2++;
+ *out++ = (f < g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *min_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (f0 < g0 ? f0 : g0); out[1] = (f1 < g1 ? f1 : g1);
+ out[2] = (f2 < g2 ? f2 : g2); out[3] = (f3 < g3 ? f3 : g3);
+ out[4] = (f4 < g4 ? f4 : g4); out[5] = (f5 < g5 ? f5 : g5);
+ out[6] = (f6 < g6 ? f6 : g6); out[7] = (f7 < g7 ? f7 : g7);
+ }
+ return (w+5);
+}
+
+t_int *scalarmin_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ t_sample g = *in++;
+ *out++ = (f < g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *scalarmin_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = (f0 < g ? f0 : g); out[1] = (f1 < g ? f1 : g);
+ out[2] = (f2 < g ? f2 : g); out[3] = (f3 < g ? f3 : g);
+ out[4] = (f4 < g ? f4 : g); out[5] = (f5 < g ? f5 : g);
+ out[6] = (f6 < g ? f6 : g); out[7] = (f7 < g ? f7 : g);
+ }
+ return (w+5);
+}
+
+static void min_dsp(t_min *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(min_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(min_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarmin_dsp(t_scalarmin *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarmin_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarmin_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void min_setup(void)
+{
+ min_class = class_new(gensym("min~"), (t_newmethod)min_new, 0,
+ sizeof(t_min), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(min_class, t_min, x_f);
+ class_addmethod(min_class, (t_method)min_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(min_class, gensym("sigbinops"));
+ scalarmin_class = class_new(gensym("min~"), 0, 0,
+ sizeof(t_scalarmin), 0, 0);
+ CLASS_MAINSIGNALIN(scalarmin_class, t_scalarmin, x_f);
+ class_addmethod(scalarmin_class, (t_method)scalarmin_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarmin_class, gensym("sigbinops"));
+}
+
+/* ----------------------- global setup routine ---------------- */
+void d_arithmetic_setup(void)
+{
+ plus_setup();
+ minus_setup();
+ times_setup();
+ over_setup();
+ max_setup();
+ min_setup();
+}
+
+/* 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. */
+
+/* arithmetic binops (+, -, *, /).
+If no creation argument is given, there are two signal inlets for vector/vector
+operation; otherwise it's vector/scalar and the second inlet takes a float
+to reset the value.
+*/
+
+#include "m_pd.h"
+
+/* ----------------------------- plus ----------------------------- */
+static t_class *plus_class, *scalarplus_class;
+
+typedef struct _plus
+{
+ t_object x_obj;
+ float x_f;
+} t_plus;
+
+typedef struct _scalarplus
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g; /* inlet value */
+} t_scalarplus;
+
+static void *plus_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("+~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarplus *x = (t_scalarplus *)pd_new(scalarplus_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_plus *x = (t_plus *)pd_new(plus_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 *plus_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--) *out++ = *in1++ + *in2++;
+ return (w+5);
+}
+
+t_int *plus_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = f0 + g0; out[1] = f1 + g1; out[2] = f2 + g2; out[3] = f3 + g3;
+ out[4] = f4 + g4; out[5] = f5 + g5; out[6] = f6 + g6; out[7] = f7 + g7;
+ }
+ return (w+5);
+}
+
+t_int *scalarplus_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ + f;
+ return (w+5);
+}
+
+t_int *scalarplus_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 + g; out[1] = f1 + g; out[2] = f2 + g; out[3] = f3 + g;
+ out[4] = f4 + g; out[5] = f5 + g; out[6] = f6 + g; out[7] = f7 + g;
+ }
+ return (w+5);
+}
+
+void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(plus_perform, 4, in1, in2, out, n);
+ else
+ dsp_add(plus_perf8, 4, in1, in2, out, n);
+}
+
+static void plus_dsp(t_plus *x, t_signal **sp)
+{
+ dsp_add_plus(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarplus_dsp(t_scalarplus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarplus_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarplus_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void plus_setup(void)
+{
+ plus_class = class_new(gensym("+~"), (t_newmethod)plus_new, 0,
+ sizeof(t_plus), 0, A_GIMME, 0);
+ class_addmethod(plus_class, (t_method)plus_dsp, gensym("dsp"), 0);
+ CLASS_MAINSIGNALIN(plus_class, t_plus, x_f);
+ class_sethelpsymbol(plus_class, gensym("sigbinops"));
+ scalarplus_class = class_new(gensym("+~"), 0, 0,
+ sizeof(t_scalarplus), 0, 0);
+ CLASS_MAINSIGNALIN(scalarplus_class, t_scalarplus, x_f);
+ class_addmethod(scalarplus_class, (t_method)scalarplus_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarplus_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- minus ----------------------------- */
+static t_class *minus_class, *scalarminus_class;
+
+typedef struct _minus
+{
+ t_object x_obj;
+ float x_f;
+} t_minus;
+
+typedef struct _scalarminus
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarminus;
+
+static void *minus_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("-~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarminus *x = (t_scalarminus *)pd_new(scalarminus_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_minus *x = (t_minus *)pd_new(minus_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 *minus_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--) *out++ = *in1++ - *in2++;
+ return (w+5);
+}
+
+t_int *minus_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = f0 - g0; out[1] = f1 - g1; out[2] = f2 - g2; out[3] = f3 - g3;
+ out[4] = f4 - g4; out[5] = f5 - g5; out[6] = f6 - g6; out[7] = f7 - g7;
+ }
+ return (w+5);
+}
+
+t_int *scalarminus_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ - f;
+ return (w+5);
+}
+
+t_int *scalarminus_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 - g; out[1] = f1 - g; out[2] = f2 - g; out[3] = f3 - g;
+ out[4] = f4 - g; out[5] = f5 - g; out[6] = f6 - g; out[7] = f7 - g;
+ }
+ return (w+5);
+}
+
+static void minus_dsp(t_minus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(minus_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(minus_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarminus_dsp(t_scalarminus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarminus_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarminus_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void minus_setup(void)
+{
+ minus_class = class_new(gensym("-~"), (t_newmethod)minus_new, 0,
+ sizeof(t_minus), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(minus_class, t_minus, x_f);
+ class_addmethod(minus_class, (t_method)minus_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(minus_class, gensym("sigbinops"));
+ scalarminus_class = class_new(gensym("-~"), 0, 0,
+ sizeof(t_scalarminus), 0, 0);
+ CLASS_MAINSIGNALIN(scalarminus_class, t_scalarminus, x_f);
+ class_addmethod(scalarminus_class, (t_method)scalarminus_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarminus_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- times ----------------------------- */
+
+static t_class *times_class, *scalartimes_class;
+
+typedef struct _times
+{
+ t_object x_obj;
+ float x_f;
+} t_times;
+
+typedef struct _scalartimes
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalartimes;
+
+static void *times_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("*~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalartimes *x = (t_scalartimes *)pd_new(scalartimes_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_times *x = (t_times *)pd_new(times_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 *times_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--) *out++ = mult(*in1++,*in2++);
+ return (w+5);
+}
+
+t_int *times_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = mult(f0,g0); out[1] = mult(f1,g1); out[2] = mult(f2,g2); out[3] = mult(f3,g3);
+ out[4] = mult(f4,g4); out[5] = mult(f5,g5); out[6] = mult(f6,g6); out[7] = mult(f7,g7);
+ }
+ return (w+5);
+}
+
+t_int *scalartimes_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = mult(*in++,f);
+ return (w+5);
+}
+
+t_int *scalartimes_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
+ out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
+ }
+ return (w+5);
+}
+
+static void times_dsp(t_times *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(times_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(times_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalartimes_dsp(t_scalartimes *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalartimes_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalartimes_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void times_setup(void)
+{
+ times_class = class_new(gensym("*~"), (t_newmethod)times_new, 0,
+ sizeof(t_times), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(times_class, t_times, x_f);
+ class_addmethod(times_class, (t_method)times_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(times_class, gensym("sigbinops"));
+ scalartimes_class = class_new(gensym("*~"), 0, 0,
+ sizeof(t_scalartimes), 0, 0);
+ CLASS_MAINSIGNALIN(scalartimes_class, t_scalartimes, x_f);
+ class_addmethod(scalartimes_class, (t_method)scalartimes_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalartimes_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- over ----------------------------- */
+static t_class *over_class, *scalarover_class;
+
+typedef struct _over
+{
+ t_object x_obj;
+ float x_f;
+} t_over;
+
+typedef struct _scalarover
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarover;
+
+static void *over_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("/~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarover *x = (t_scalarover *)pd_new(scalarover_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_over *x = (t_over *)pd_new(over_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 *over_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 g = *in2++;
+ *out++ = (g ? *in1++ / g : 0);
+ }
+ return (w+5);
+}
+
+t_int *over_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (g0? idiv(f0,g0) : 0);
+ out[1] = (g1? idiv(f1,g1) : 0);
+ out[2] = (g2? idiv(f2,g2) : 0);
+ out[3] = (g3? idiv(f3,g3) : 0);
+ out[4] = (g4? idiv(f4,g4) : 0);
+ out[5] = (g5? idiv(f5,g5) : 0);
+ out[6] = (g6? idiv(f6,g6) : 0);
+ out[7] = (g7? idiv(f7,g7) : 0);
+ }
+ return (w+5);
+}
+
+t_int *scalarover_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = idiv(ftofix(1.),ftofix(*(t_float *)(w[2])));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = mult(*in++,f);
+ return (w+5);
+}
+
+t_int *scalarover_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ if (g) g = idiv(ftofix(1.f),g);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = mult(f0,g); out[1] = mult(f1,g); out[2] = mult(f2,g); out[3] = mult(f3,g);
+ out[4] = mult(f4,g); out[5] = mult(f5,g); out[6] = mult(f6,g); out[7] = mult(f7,g);
+ }
+ return (w+5);
+}
+
+static void over_dsp(t_over *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(over_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(over_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarover_dsp(t_scalarover *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarover_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarover_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void over_setup(void)
+{
+ over_class = class_new(gensym("/~"), (t_newmethod)over_new, 0,
+ sizeof(t_over), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(over_class, t_over, x_f);
+ class_addmethod(over_class, (t_method)over_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(over_class, gensym("sigbinops"));
+ scalarover_class = class_new(gensym("/~"), 0, 0,
+ sizeof(t_scalarover), 0, 0);
+ CLASS_MAINSIGNALIN(scalarover_class, t_scalarover, x_f);
+ class_addmethod(scalarover_class, (t_method)scalarover_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarover_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- max ----------------------------- */
+static t_class *max_class, *scalarmax_class;
+
+typedef struct _max
+{
+ t_object x_obj;
+ float x_f;
+} t_max;
+
+typedef struct _scalarmax
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarmax;
+
+static void *max_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("max~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarmax *x = (t_scalarmax *)pd_new(scalarmax_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_max *x = (t_max *)pd_new(max_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 *max_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--)
+ {
+ t_sample f = *in1++, g = *in2++;
+ *out++ = (f > g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *max_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (f0 > g0 ? f0 : g0); out[1] = (f1 > g1 ? f1 : g1);
+ out[2] = (f2 > g2 ? f2 : g2); out[3] = (f3 > g3 ? f3 : g3);
+ out[4] = (f4 > g4 ? f4 : g4); out[5] = (f5 > g5 ? f5 : g5);
+ out[6] = (f6 > g6 ? f6 : g6); out[7] = (f7 > g7 ? f7 : g7);
+ }
+ return (w+5);
+}
+
+t_int *scalarmax_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ t_sample g = *in++;
+ *out++ = (f > g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *scalarmax_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = (f0 > g ? f0 : g); out[1] = (f1 > g ? f1 : g);
+ out[2] = (f2 > g ? f2 : g); out[3] = (f3 > g ? f3 : g);
+ out[4] = (f4 > g ? f4 : g); out[5] = (f5 > g ? f5 : g);
+ out[6] = (f6 > g ? f6 : g); out[7] = (f7 > g ? f7 : g);
+ }
+ return (w+5);
+}
+
+static void max_dsp(t_max *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(max_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(max_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarmax_dsp(t_scalarmax *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarmax_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarmax_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void max_setup(void)
+{
+ max_class = class_new(gensym("max~"), (t_newmethod)max_new, 0,
+ sizeof(t_max), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(max_class, t_max, x_f);
+ class_addmethod(max_class, (t_method)max_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(max_class, gensym("sigbinops"));
+ scalarmax_class = class_new(gensym("max~"), 0, 0,
+ sizeof(t_scalarmax), 0, 0);
+ CLASS_MAINSIGNALIN(scalarmax_class, t_scalarmax, x_f);
+ class_addmethod(scalarmax_class, (t_method)scalarmax_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarmax_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- min ----------------------------- */
+static t_class *min_class, *scalarmin_class;
+
+typedef struct _min
+{
+ t_object x_obj;
+ float x_f;
+} t_min;
+
+typedef struct _scalarmin
+{
+ t_object x_obj;
+ t_float x_g;
+ float x_f;
+} t_scalarmin;
+
+static void *min_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("min~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarmin *x = (t_scalarmin *)pd_new(scalarmin_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_min *x = (t_min *)pd_new(min_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 *min_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--)
+ {
+ t_sample f = *in1++, g = *in2++;
+ *out++ = (f < g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *min_perf8(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]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (f0 < g0 ? f0 : g0); out[1] = (f1 < g1 ? f1 : g1);
+ out[2] = (f2 < g2 ? f2 : g2); out[3] = (f3 < g3 ? f3 : g3);
+ out[4] = (f4 < g4 ? f4 : g4); out[5] = (f5 < g5 ? f5 : g5);
+ out[6] = (f6 < g6 ? f6 : g6); out[7] = (f7 < g7 ? f7 : g7);
+ }
+ return (w+5);
+}
+
+t_int *scalarmin_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample f = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ t_sample g = *in++;
+ *out++ = (f < g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *scalarmin_perf8(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample g = ftofix(*(t_float *)(w[2]));
+ t_sample *out = (t_sample *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = (f0 < g ? f0 : g); out[1] = (f1 < g ? f1 : g);
+ out[2] = (f2 < g ? f2 : g); out[3] = (f3 < g ? f3 : g);
+ out[4] = (f4 < g ? f4 : g); out[5] = (f5 < g ? f5 : g);
+ out[6] = (f6 < g ? f6 : g); out[7] = (f7 < g ? f7 : g);
+ }
+ return (w+5);
+}
+
+static void min_dsp(t_min *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(min_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(min_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarmin_dsp(t_scalarmin *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarmin_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarmin_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void min_setup(void)
+{
+ min_class = class_new(gensym("min~"), (t_newmethod)min_new, 0,
+ sizeof(t_min), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(min_class, t_min, x_f);
+ class_addmethod(min_class, (t_method)min_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(min_class, gensym("sigbinops"));
+ scalarmin_class = class_new(gensym("min~"), 0, 0,
+ sizeof(t_scalarmin), 0, 0);
+ CLASS_MAINSIGNALIN(scalarmin_class, t_scalarmin, x_f);
+ class_addmethod(scalarmin_class, (t_method)scalarmin_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarmin_class, gensym("sigbinops"));
+}
+
+/* ----------------------- global setup routine ---------------- */
+void d_arithmetic_setup(void)
+{
+ plus_setup();
+ minus_setup();
+ times_setup();
+ over_setup();
+ max_setup();
+ min_setup();
+}
+
diff --git a/apps/plugins/pdbox/PDa/src/d_array.c b/apps/plugins/pdbox/PDa/src/d_array.c
new file mode 100644
index 0000000000..14ae464b0b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_array.c
@@ -0,0 +1,2148 @@
+/* Copyright (c) 1997-1999 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. */
+
+/* sampling */
+
+/* LATER make tabread4 and tabread~ */
+
+#include "m_pd.h"
+
+
+/* ------------------------- tabwrite~ -------------------------- */
+
+static t_class *tabwrite_tilde_class;
+
+typedef struct _tabwrite_tilde
+{
+ t_object x_obj;
+ int x_phase;
+ int x_nsampsintab;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_f;
+} t_tabwrite_tilde;
+
+static void tabwrite_tilde_tick(t_tabwrite_tilde *x);
+
+static void *tabwrite_tilde_new(t_symbol *s)
+{
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
+ x->x_clock = clock_new(x, (t_method)tabwrite_tilde_tick);
+ x->x_phase = 0x7fffffff;
+ x->x_arrayname = s;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabwrite_tilde_perform(t_int *w)
+{
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]), phase = x->x_phase, endphase = x->x_nsampsintab;
+ if (!x->x_vec) goto bad;
+
+ if (endphase > phase)
+ {
+ int nxfer = endphase - phase;
+ float *fp = x->x_vec + phase;
+ if (nxfer > n) nxfer = n;
+ phase += nxfer;
+ while (nxfer--)
+ {
+ float f = *in++;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+ *fp++ = f;
+ }
+ if (phase >= endphase)
+ {
+ clock_delay(x->x_clock, 0);
+ phase = 0x7fffffff;
+ }
+ x->x_phase = phase;
+ }
+bad:
+ return (w+4);
+}
+
+void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name) pd_error(x, "tabwrite~: %s: no such array",
+ x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabwrite~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp)
+{
+ tabwrite_tilde_set(x, x->x_arrayname);
+ dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void tabwrite_tilde_bang(t_tabwrite_tilde *x)
+{
+ x->x_phase = 0;
+}
+
+static void tabwrite_tilde_stop(t_tabwrite_tilde *x)
+{
+ if (x->x_phase != 0x7fffffff)
+ {
+ tabwrite_tilde_tick(x);
+ x->x_phase = 0x7fffffff;
+ }
+}
+
+static void tabwrite_tilde_tick(t_tabwrite_tilde *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabwrite_tilde_tick");
+ else garray_redraw(a);
+}
+
+static void tabwrite_tilde_free(t_tabwrite_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabwrite_tilde_setup(void)
+{
+ tabwrite_tilde_class = class_new(gensym("tabwrite~"),
+ (t_newmethod)tabwrite_tilde_new, (t_method)tabwrite_tilde_free,
+ sizeof(t_tabwrite_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabwrite_tilde_class, t_tabwrite_tilde, x_f);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_stop,
+ gensym("stop"), 0);
+ class_addbang(tabwrite_tilde_class, tabwrite_tilde_bang);
+}
+
+/* ------------ tabplay~ - non-transposing sample playback --------------- */
+
+static t_class *tabplay_tilde_class;
+
+typedef struct _tabplay_tilde
+{
+ t_object x_obj;
+ t_outlet *x_bangout;
+ int x_phase;
+ int x_nsampsintab;
+ int x_limit;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+} t_tabplay_tilde;
+
+static void tabplay_tilde_tick(t_tabplay_tilde *x);
+
+static void *tabplay_tilde_new(t_symbol *s)
+{
+ t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
+ x->x_clock = clock_new(x, (t_method)tabplay_tilde_tick);
+ x->x_phase = 0x7fffffff;
+ x->x_limit = 0;
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+ return (x);
+}
+
+static t_int *tabplay_tilde_perform(t_int *w)
+{
+ t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]);
+ t_float *out = (t_float *)(w[2]), *fp;
+ int n = (int)(w[3]), phase = x->x_phase,
+ endphase = (x->x_nsampsintab < x->x_limit ?
+ x->x_nsampsintab : x->x_limit), nxfer, n3;
+ if (!x->x_vec || phase >= endphase)
+ goto zero;
+
+ nxfer = endphase - phase;
+ fp = x->x_vec + phase;
+ if (nxfer > n)
+ nxfer = n;
+ n3 = n - nxfer;
+ phase += nxfer;
+ while (nxfer--)
+ *out++ = *fp++;
+ if (phase >= endphase)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_phase = 0x7fffffff;
+ while (n3--)
+ *out++ = 0;
+ }
+ else x->x_phase = phase;
+
+ return (w+4);
+zero:
+ while (n--) *out++ = 0;
+ return (w+4);
+}
+
+void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name) pd_error(x, "tabplay~: %s: no such array",
+ x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabplay~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp)
+{
+ tabplay_tilde_set(x, x->x_arrayname);
+ dsp_add(tabplay_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ long start = atom_getfloatarg(0, argc, argv);
+ long length = atom_getfloatarg(1, argc, argv);
+ if (start < 0) start = 0;
+ if (length <= 0)
+ x->x_limit = 0x7fffffff;
+ else
+ x->x_limit = start + length;
+ x->x_phase = start;
+}
+
+static void tabplay_tilde_stop(t_tabplay_tilde *x)
+{
+ x->x_phase = 0x7fffffff;
+}
+
+static void tabplay_tilde_tick(t_tabplay_tilde *x)
+{
+ outlet_bang(x->x_bangout);
+}
+
+static void tabplay_tilde_free(t_tabplay_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabplay_tilde_setup(void)
+{
+ tabplay_tilde_class = class_new(gensym("tabplay~"),
+ (t_newmethod)tabplay_tilde_new, (t_method)tabplay_tilde_free,
+ sizeof(t_tabplay_tilde), 0, A_DEFSYM, 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_stop,
+ gensym("stop"), 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_set,
+ gensym("set"), A_DEFSYM, 0);
+ class_addlist(tabplay_tilde_class, tabplay_tilde_list);
+}
+
+/******************** tabread~ ***********************/
+
+static t_class *tabread_tilde_class;
+
+typedef struct _tabread_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+} t_tabread_tilde;
+
+static void *tabread_tilde_new(t_symbol *s)
+{
+ t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabread_tilde_perform(t_int *w)
+{
+ t_tabread_tilde *x = (t_tabread_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int maxindex;
+ float *buf = x->x_vec, *fp;
+ int i;
+
+ maxindex = x->x_npoints - 1;
+ if (!buf) goto zero;
+
+ for (i = 0; i < n; i++)
+ {
+ int index = *in++;
+ if (index < 0)
+ index = 0;
+ else if (index > maxindex)
+ index = maxindex;
+ *out++ = buf[index];
+ }
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ pd_error(x, "tabread~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabread~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp)
+{
+ tabread_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabread_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void tabread_tilde_free(t_tabread_tilde *x)
+{
+}
+
+static void tabread_tilde_setup(void)
+{
+ tabread_tilde_class = class_new(gensym("tabread~"),
+ (t_newmethod)tabread_tilde_new, (t_method)tabread_tilde_free,
+ sizeof(t_tabread_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabread_tilde_class, t_tabread_tilde, x_f);
+ class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+}
+
+/******************** tabread4~ ***********************/
+
+static t_class *tabread4_tilde_class;
+
+typedef struct _tabread4_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+} t_tabread4_tilde;
+
+static void *tabread4_tilde_new(t_symbol *s)
+{
+ t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabread4_tilde_perform(t_int *w)
+{
+ t_tabread4_tilde *x = (t_tabread4_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int maxindex;
+ float *buf = x->x_vec, *fp;
+ int i;
+
+ maxindex = x->x_npoints - 3;
+
+ if (!buf) goto zero;
+
+#if 0 /* test for spam -- I'm not ready to deal with this */
+ for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++)
+ {
+ float f = *in1;
+ if (f < xmin) xmin = f;
+ else if (f > xmax) xmax = f;
+ }
+ if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent;
+ for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent,
+ fp = in1; i < n; i++, fp++)
+ {
+ float f = *in1;
+ if (f > splitlo && f < splithi) goto zero;
+ }
+#endif
+
+ for (i = 0; i < n; i++)
+ {
+ float findex = *in++;
+ int index = findex;
+ float frac, a, b, c, d, cminusb;
+ static int count;
+ if (index < 1)
+ index = 1, frac = 0;
+ else if (index > maxindex)
+ index = maxindex, frac = 1;
+ else frac = findex - index;
+ fp = buf + index;
+ a = fp[-1];
+ b = fp[0];
+ c = fp[1];
+ d = fp[2];
+ /* if (!i && !(count++ & 1023))
+ post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
+ 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+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ pd_error(x, "tabread4~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabread4~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp)
+{
+ tabread4_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabread4_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void tabread4_tilde_free(t_tabread4_tilde *x)
+{
+}
+
+static void tabread4_tilde_setup(void)
+{
+ tabread4_tilde_class = class_new(gensym("tabread4~"),
+ (t_newmethod)tabread4_tilde_new, (t_method)tabread4_tilde_free,
+ sizeof(t_tabread4_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabread4_tilde_class, t_tabread4_tilde, x_f);
+ class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+}
+
+/******************** tabosc4~ ***********************/
+
+/* this is all copied from d_osc.c... what include file could this go in? */
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+ /* machine-dependent definitions. These ifdefs really
+ should have been by CPU type and not by operating system! */
+#ifdef IRIX
+ /* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef MSW
+ /* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+
+#ifdef __linux__
+#include <endian.h>
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef MACOSX
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* MACOSX */
+#endif /* __linux__ */
+#endif /* MSW */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+static t_class *tabosc4_tilde_class;
+
+typedef struct _tabosc4_tilde
+{
+ t_object x_obj;
+ float x_fnpoints;
+ float x_finvnpoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+ double x_phase;
+ float x_conv;
+} t_tabosc4_tilde;
+
+static void *tabosc4_tilde_new(t_symbol *s)
+{
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ x->x_fnpoints = 512.;
+ x->x_finvnpoints = (1./512.);
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabosc4_tilde_perform(t_int *w)
+{
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int normhipart;
+ union tabfudge tf;
+ float fnpoints = x->x_fnpoints;
+ int mask = fnpoints - 1;
+ float conv = fnpoints * x->x_conv;
+ int maxindex;
+ float *tab = x->x_vec, *addr;
+ int i;
+ double dphase = fnpoints * x->x_phase + UNITBIT32;
+
+ if (!tab) goto zero;
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+#if 1
+ while (n--)
+ {
+ float frac, a, b, c, d, cminusb;
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & mask);
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ a = addr[0];
+ b = addr[1];
+ c = addr[2];
+ d = addr[3];
+ cminusb = c-b;
+ *out++ = b + frac * (
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
+ )
+ );
+ }
+#endif
+
+ tf.tf_d = UNITBIT32 * fnpoints;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase + (UNITBIT32 * fnpoints - UNITBIT32);
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = (tf.tf_d - UNITBIT32 * fnpoints) * x->x_finvnpoints;
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+ int npoints, pointsinarray;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ pd_error(x, "tabosc4~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &pointsinarray, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabosc4~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3)))
+ {
+ pd_error(x, "%s: number of points (%d) not a power of 2 plus three",
+ x->x_arrayname->s_name, pointsinarray);
+ x->x_vec = 0;
+ garray_usedindsp(a);
+ }
+ else
+ {
+ x->x_fnpoints = npoints;
+ x->x_finvnpoints = 1./npoints;
+ garray_usedindsp(a);
+ }
+}
+
+static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f)
+{
+ x->x_phase = f;
+}
+
+static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp)
+{
+ x->x_conv = 1. / sp[0]->s_sr;
+ tabosc4_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabosc4_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void tabosc4_tilde_setup(void)
+{
+ tabosc4_tilde_class = class_new(gensym("tabosc4~"),
+ (t_newmethod)tabosc4_tilde_new, 0,
+ sizeof(t_tabosc4_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabosc4_tilde_class, t_tabosc4_tilde, x_f);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+/* ------------------------ tabsend~ ------------------------- */
+
+static t_class *tabsend_class;
+
+typedef struct _tabsend
+{
+ t_object x_obj;
+ float *x_vec;
+ int x_graphperiod;
+ int x_graphcount;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_f;
+} t_tabsend;
+
+static void tabsend_tick(t_tabsend *x);
+
+static void *tabsend_new(t_symbol *s)
+{
+ t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
+ x->x_graphcount = 0;
+ x->x_arrayname = s;
+ x->x_clock = clock_new(x, (t_method)tabsend_tick);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabsend_perform(t_int *w)
+{
+ t_tabsend *x = (t_tabsend *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = w[3];
+ t_float *dest = x->x_vec;
+ int i = x->x_graphcount;
+ if (!x->x_vec) goto bad;
+
+ while (n--)
+ {
+ float f = *in++;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+ *dest++ = f;
+ }
+ if (!i--)
+ {
+ clock_delay(x->x_clock, 0);
+ i = x->x_graphperiod;
+ }
+ x->x_graphcount = i;
+bad:
+ return (w+4);
+}
+
+static void tabsend_dsp(t_tabsend *x, t_signal **sp)
+{
+ int i, vecsize;
+ t_garray *a;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*x->x_arrayname->s_name)
+ pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
+ }
+ else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
+ pd_error(x, "%s: bad template for tabsend~", x->x_arrayname->s_name);
+ else
+ {
+ int n = sp[0]->s_n;
+ int ticksper = sp[0]->s_sr/n;
+ if (ticksper < 1) ticksper = 1;
+ x->x_graphperiod = ticksper;
+ if (x->x_graphcount > ticksper) x->x_graphcount = ticksper;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ dsp_add(tabsend_perform, 3, x, sp[0]->s_vec, vecsize);
+ }
+}
+
+static void tabsend_tick(t_tabsend *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabsend_tick");
+ else garray_redraw(a);
+}
+
+static void tabsend_free(t_tabsend *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabsend_setup(void)
+{
+ tabsend_class = class_new(gensym("tabsend~"), (t_newmethod)tabsend_new,
+ (t_method)tabsend_free, sizeof(t_tabsend), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, x_f);
+ class_addmethod(tabsend_class, (t_method)tabsend_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------ tabreceive~ ------------------------- */
+
+static t_class *tabreceive_class;
+
+typedef struct _tabreceive
+{
+ t_object x_obj;
+ float *x_vec;
+ t_symbol *x_arrayname;
+} t_tabreceive;
+
+static t_int *tabreceive_perform(t_int *w)
+{
+ t_tabreceive *x = (t_tabreceive *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = w[3];
+ t_float *from = x->x_vec;
+ if (from) while (n--) *out++ = *from++;
+ else while (n--) *out++ = 0;
+ return (w+4);
+}
+
+static void tabreceive_dsp(t_tabreceive *x, t_signal **sp)
+{
+ t_garray *a;
+ int vecsize;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*x->x_arrayname->s_name)
+ pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
+ }
+ else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
+ pd_error(x, "%s: bad template for tabreceive~", x->x_arrayname->s_name);
+ else
+ {
+ int n = sp[0]->s_n;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ dsp_add(tabreceive_perform, 3, x, sp[0]->s_vec, vecsize);
+ }
+}
+
+static void *tabreceive_new(t_symbol *s)
+{
+ t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static void tabreceive_setup(void)
+{
+ tabreceive_class = class_new(gensym("tabreceive~"),
+ (t_newmethod)tabreceive_new, 0,
+ sizeof(t_tabreceive), 0, A_DEFSYM, 0);
+ class_addmethod(tabreceive_class, (t_method)tabreceive_dsp,
+ gensym("dsp"), 0);
+}
+
+
+/* ---------- tabread: control, non-interpolating ------------------------ */
+
+static t_class *tabread_class;
+
+typedef struct _tabread
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+} t_tabread;
+
+static void tabread_float(t_tabread *x, t_float f)
+{
+ t_garray *a;
+ int npoints;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ pd_error(x, "%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &npoints, &vec))
+ pd_error(x, "%s: bad template for tabread", x->x_arrayname->s_name);
+ else
+ {
+ int n = f;
+ if (n < 0) n = 0;
+ else if (n >= npoints) n = npoints - 1;
+ outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n] : 0));
+ }
+}
+
+static void tabread_set(t_tabread *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void *tabread_new(t_symbol *s)
+{
+ t_tabread *x = (t_tabread *)pd_new(tabread_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void tabread_setup(void)
+{
+ tabread_class = class_new(gensym("tabread"), (t_newmethod)tabread_new,
+ 0, sizeof(t_tabread), 0, A_DEFSYM, 0);
+ class_addfloat(tabread_class, (t_method)tabread_float);
+ class_addmethod(tabread_class, (t_method)tabread_set, gensym("set"),
+ A_SYMBOL, 0);
+}
+
+/* ---------- tabread4: control, non-interpolating ------------------------ */
+
+static t_class *tabread4_class;
+
+typedef struct _tabread4
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+} t_tabread4;
+
+static void tabread4_float(t_tabread4 *x, t_float f)
+{
+ t_garray *a;
+ int npoints;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ pd_error(x, "%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &npoints, &vec))
+ pd_error(x, "%s: bad template for tabread4", x->x_arrayname->s_name);
+ else if (npoints < 4)
+ outlet_float(x->x_obj.ob_outlet, 0);
+ else if (f <= 1)
+ outlet_float(x->x_obj.ob_outlet, vec[1]);
+ else if (f >= npoints - 2)
+ outlet_float(x->x_obj.ob_outlet, vec[npoints - 2]);
+ else
+ {
+ int n = f;
+ float a, b, c, d, cminusb, frac, *fp;
+ if (n >= npoints - 2)
+ n = npoints - 3;
+ fp = vec + n;
+ frac = f - n;
+ a = fp[-1];
+ b = fp[0];
+ c = fp[1];
+ d = fp[2];
+ cminusb = c-b;
+ outlet_float(x->x_obj.ob_outlet, b + frac * (
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))));
+ }
+}
+
+static void tabread4_set(t_tabread4 *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void *tabread4_new(t_symbol *s)
+{
+ t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void tabread4_setup(void)
+{
+ tabread4_class = class_new(gensym("tabread4"), (t_newmethod)tabread4_new,
+ 0, sizeof(t_tabread4), 0, A_DEFSYM, 0);
+ class_addfloat(tabread4_class, (t_method)tabread4_float);
+ class_addmethod(tabread4_class, (t_method)tabread4_set, gensym("set"),
+ A_SYMBOL, 0);
+}
+
+/* ------------------ tabwrite: control ------------------------ */
+
+static t_class *tabwrite_class;
+
+typedef struct _tabwrite
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_ft1;
+ double x_updtime;
+ int x_set;
+} t_tabwrite;
+
+static void tabwrite_tick(t_tabwrite *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabwrite_tick");
+ else garray_redraw(a);
+ x->x_set = 0;
+ x->x_updtime = clock_getsystime();
+}
+
+static void tabwrite_float(t_tabwrite *x, t_float f)
+{
+ int i, vecsize;
+ t_garray *a;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ pd_error(x, "%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &vecsize, &vec))
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname->s_name);
+ else
+ {
+ int n = x->x_ft1;
+ double timesince = clock_gettimesince(x->x_updtime);
+ if (n < 0) n = 0;
+ else if (n >= vecsize) n = vecsize-1;
+ vec[n] = f;
+ if (timesince > 1000)
+ {
+ tabwrite_tick(x);
+ }
+ else
+ {
+ if (x->x_set == 0)
+ {
+ clock_delay(x->x_clock, 1000 - timesince);
+ x->x_set = 1;
+ }
+ }
+ }
+}
+
+static void tabwrite_set(t_tabwrite *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void tabwrite_free(t_tabwrite *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *tabwrite_new(t_symbol *s)
+{
+ t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
+ x->x_ft1 = 0;
+ x->x_arrayname = s;
+ x->x_updtime = clock_getsystime();
+ x->x_clock = clock_new(x, (t_method)tabwrite_tick);
+ floatinlet_new(&x->x_obj, &x->x_ft1);
+ return (x);
+}
+
+void tabwrite_setup(void)
+{
+ tabwrite_class = class_new(gensym("tabwrite"), (t_newmethod)tabwrite_new,
+ (t_method)tabwrite_free, sizeof(t_tabwrite), 0, A_DEFSYM, 0);
+ class_addfloat(tabwrite_class, (t_method)tabwrite_float);
+ class_addmethod(tabwrite_class, (t_method)tabwrite_set, gensym("set"), A_SYMBOL, 0);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_array_setup(void)
+{
+ tabwrite_tilde_setup();
+ tabplay_tilde_setup();
+ tabread_tilde_setup();
+ tabread4_tilde_setup();
+ tabosc4_tilde_setup();
+ tabsend_setup();
+ tabreceive_setup();
+ tabread_setup();
+ tabread4_setup();
+ tabwrite_setup();
+}
+
+/* Copyright (c) 1997-1999 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. */
+
+/* sampling */
+
+/* LATER make tabread4 and tabread~ */
+
+#include "m_pd.h"
+
+
+/* ------------------------- tabwrite~ -------------------------- */
+
+static t_class *tabwrite_tilde_class;
+
+typedef struct _tabwrite_tilde
+{
+ t_object x_obj;
+ int x_phase;
+ int x_nsampsintab;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_f;
+} t_tabwrite_tilde;
+
+static void tabwrite_tilde_tick(t_tabwrite_tilde *x);
+
+static void *tabwrite_tilde_new(t_symbol *s)
+{
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
+ x->x_clock = clock_new(x, (t_method)tabwrite_tilde_tick);
+ x->x_phase = 0x7fffffff;
+ x->x_arrayname = s;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabwrite_tilde_perform(t_int *w)
+{
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]), phase = x->x_phase, endphase = x->x_nsampsintab;
+ if (!x->x_vec) goto bad;
+
+ if (endphase > phase)
+ {
+ int nxfer = endphase - phase;
+ float *fp = x->x_vec + phase;
+ if (nxfer > n) nxfer = n;
+ phase += nxfer;
+ while (nxfer--)
+ {
+ float f = *in++;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+ *fp++ = f;
+ }
+ if (phase >= endphase)
+ {
+ clock_delay(x->x_clock, 0);
+ phase = 0x7fffffff;
+ }
+ x->x_phase = phase;
+ }
+bad:
+ return (w+4);
+}
+
+void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name) pd_error(x, "tabwrite~: %s: no such array",
+ x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabwrite~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp)
+{
+ tabwrite_tilde_set(x, x->x_arrayname);
+ dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void tabwrite_tilde_bang(t_tabwrite_tilde *x)
+{
+ x->x_phase = 0;
+}
+
+static void tabwrite_tilde_stop(t_tabwrite_tilde *x)
+{
+ if (x->x_phase != 0x7fffffff)
+ {
+ tabwrite_tilde_tick(x);
+ x->x_phase = 0x7fffffff;
+ }
+}
+
+static void tabwrite_tilde_tick(t_tabwrite_tilde *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabwrite_tilde_tick");
+ else garray_redraw(a);
+}
+
+static void tabwrite_tilde_free(t_tabwrite_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabwrite_tilde_setup(void)
+{
+ tabwrite_tilde_class = class_new(gensym("tabwrite~"),
+ (t_newmethod)tabwrite_tilde_new, (t_method)tabwrite_tilde_free,
+ sizeof(t_tabwrite_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabwrite_tilde_class, t_tabwrite_tilde, x_f);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_stop,
+ gensym("stop"), 0);
+ class_addbang(tabwrite_tilde_class, tabwrite_tilde_bang);
+}
+
+/* ------------ tabplay~ - non-transposing sample playback --------------- */
+
+static t_class *tabplay_tilde_class;
+
+typedef struct _tabplay_tilde
+{
+ t_object x_obj;
+ t_outlet *x_bangout;
+ int x_phase;
+ int x_nsampsintab;
+ int x_limit;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+} t_tabplay_tilde;
+
+static void tabplay_tilde_tick(t_tabplay_tilde *x);
+
+static void *tabplay_tilde_new(t_symbol *s)
+{
+ t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
+ x->x_clock = clock_new(x, (t_method)tabplay_tilde_tick);
+ x->x_phase = 0x7fffffff;
+ x->x_limit = 0;
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+ return (x);
+}
+
+static t_int *tabplay_tilde_perform(t_int *w)
+{
+ t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]);
+ t_float *out = (t_float *)(w[2]), *fp;
+ int n = (int)(w[3]), phase = x->x_phase,
+ endphase = (x->x_nsampsintab < x->x_limit ?
+ x->x_nsampsintab : x->x_limit), nxfer, n3;
+ if (!x->x_vec || phase >= endphase)
+ goto zero;
+
+ nxfer = endphase - phase;
+ fp = x->x_vec + phase;
+ if (nxfer > n)
+ nxfer = n;
+ n3 = n - nxfer;
+ phase += nxfer;
+ while (nxfer--)
+ *out++ = *fp++;
+ if (phase >= endphase)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_phase = 0x7fffffff;
+ while (n3--)
+ *out++ = 0;
+ }
+ else x->x_phase = phase;
+
+ return (w+4);
+zero:
+ while (n--) *out++ = 0;
+ return (w+4);
+}
+
+void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name) pd_error(x, "tabplay~: %s: no such array",
+ x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabplay~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp)
+{
+ tabplay_tilde_set(x, x->x_arrayname);
+ dsp_add(tabplay_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ long start = atom_getfloatarg(0, argc, argv);
+ long length = atom_getfloatarg(1, argc, argv);
+ if (start < 0) start = 0;
+ if (length <= 0)
+ x->x_limit = 0x7fffffff;
+ else
+ x->x_limit = start + length;
+ x->x_phase = start;
+}
+
+static void tabplay_tilde_stop(t_tabplay_tilde *x)
+{
+ x->x_phase = 0x7fffffff;
+}
+
+static void tabplay_tilde_tick(t_tabplay_tilde *x)
+{
+ outlet_bang(x->x_bangout);
+}
+
+static void tabplay_tilde_free(t_tabplay_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabplay_tilde_setup(void)
+{
+ tabplay_tilde_class = class_new(gensym("tabplay~"),
+ (t_newmethod)tabplay_tilde_new, (t_method)tabplay_tilde_free,
+ sizeof(t_tabplay_tilde), 0, A_DEFSYM, 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_stop,
+ gensym("stop"), 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_set,
+ gensym("set"), A_DEFSYM, 0);
+ class_addlist(tabplay_tilde_class, tabplay_tilde_list);
+}
+
+/******************** tabread~ ***********************/
+
+static t_class *tabread_tilde_class;
+
+typedef struct _tabread_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+} t_tabread_tilde;
+
+static void *tabread_tilde_new(t_symbol *s)
+{
+ t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabread_tilde_perform(t_int *w)
+{
+ t_tabread_tilde *x = (t_tabread_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int maxindex;
+ float *buf = x->x_vec, *fp;
+ int i;
+
+ maxindex = x->x_npoints - 1;
+ if (!buf) goto zero;
+
+ for (i = 0; i < n; i++)
+ {
+ int index = *in++;
+ if (index < 0)
+ index = 0;
+ else if (index > maxindex)
+ index = maxindex;
+ *out++ = buf[index];
+ }
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ pd_error(x, "tabread~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabread~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp)
+{
+ tabread_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabread_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void tabread_tilde_free(t_tabread_tilde *x)
+{
+}
+
+static void tabread_tilde_setup(void)
+{
+ tabread_tilde_class = class_new(gensym("tabread~"),
+ (t_newmethod)tabread_tilde_new, (t_method)tabread_tilde_free,
+ sizeof(t_tabread_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabread_tilde_class, t_tabread_tilde, x_f);
+ class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+}
+
+/******************** tabread4~ ***********************/
+
+static t_class *tabread4_tilde_class;
+
+typedef struct _tabread4_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+} t_tabread4_tilde;
+
+static void *tabread4_tilde_new(t_symbol *s)
+{
+ t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabread4_tilde_perform(t_int *w)
+{
+ t_tabread4_tilde *x = (t_tabread4_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int maxindex;
+ float *buf = x->x_vec, *fp;
+ int i;
+
+ maxindex = x->x_npoints - 3;
+
+ if (!buf) goto zero;
+
+#if 0 /* test for spam -- I'm not ready to deal with this */
+ for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++)
+ {
+ float f = *in1;
+ if (f < xmin) xmin = f;
+ else if (f > xmax) xmax = f;
+ }
+ if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent;
+ for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent,
+ fp = in1; i < n; i++, fp++)
+ {
+ float f = *in1;
+ if (f > splitlo && f < splithi) goto zero;
+ }
+#endif
+
+ for (i = 0; i < n; i++)
+ {
+ float findex = *in++;
+ int index = findex;
+ float frac, a, b, c, d, cminusb;
+ static int count;
+ if (index < 1)
+ index = 1, frac = 0;
+ else if (index > maxindex)
+ index = maxindex, frac = 1;
+ else frac = findex - index;
+ fp = buf + index;
+ a = fp[-1];
+ b = fp[0];
+ c = fp[1];
+ d = fp[2];
+ /* if (!i && !(count++ & 1023))
+ post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
+ 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+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ pd_error(x, "tabread4~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabread4~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp)
+{
+ tabread4_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabread4_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void tabread4_tilde_free(t_tabread4_tilde *x)
+{
+}
+
+static void tabread4_tilde_setup(void)
+{
+ tabread4_tilde_class = class_new(gensym("tabread4~"),
+ (t_newmethod)tabread4_tilde_new, (t_method)tabread4_tilde_free,
+ sizeof(t_tabread4_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabread4_tilde_class, t_tabread4_tilde, x_f);
+ class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+}
+
+/******************** tabosc4~ ***********************/
+
+/* this is all copied from d_osc.c... what include file could this go in? */
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+ /* machine-dependent definitions. These ifdefs really
+ should have been by CPU type and not by operating system! */
+#ifdef IRIX
+ /* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef MSW
+ /* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+
+#ifdef __linux__
+#include <endian.h>
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef MACOSX
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* MACOSX */
+#endif /* __linux__ */
+#endif /* MSW */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+static t_class *tabosc4_tilde_class;
+
+typedef struct _tabosc4_tilde
+{
+ t_object x_obj;
+ float x_fnpoints;
+ float x_finvnpoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+ double x_phase;
+ float x_conv;
+} t_tabosc4_tilde;
+
+static void *tabosc4_tilde_new(t_symbol *s)
+{
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ x->x_fnpoints = 512.;
+ x->x_finvnpoints = (1./512.);
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabosc4_tilde_perform(t_int *w)
+{
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int normhipart;
+ union tabfudge tf;
+ float fnpoints = x->x_fnpoints;
+ int mask = fnpoints - 1;
+ float conv = fnpoints * x->x_conv;
+ int maxindex;
+ float *tab = x->x_vec, *addr;
+ int i;
+ double dphase = fnpoints * x->x_phase + UNITBIT32;
+
+ if (!tab) goto zero;
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+#if 1
+ while (n--)
+ {
+ float frac, a, b, c, d, cminusb;
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & mask);
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ a = addr[0];
+ b = addr[1];
+ c = addr[2];
+ d = addr[3];
+ cminusb = c-b;
+ *out++ = b + frac * (
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
+ )
+ );
+ }
+#endif
+
+ tf.tf_d = UNITBIT32 * fnpoints;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase + (UNITBIT32 * fnpoints - UNITBIT32);
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = (tf.tf_d - UNITBIT32 * fnpoints) * x->x_finvnpoints;
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+ int npoints, pointsinarray;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ pd_error(x, "tabosc4~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &pointsinarray, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabosc4~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3)))
+ {
+ pd_error(x, "%s: number of points (%d) not a power of 2 plus three",
+ x->x_arrayname->s_name, pointsinarray);
+ x->x_vec = 0;
+ garray_usedindsp(a);
+ }
+ else
+ {
+ x->x_fnpoints = npoints;
+ x->x_finvnpoints = 1./npoints;
+ garray_usedindsp(a);
+ }
+}
+
+static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f)
+{
+ x->x_phase = f;
+}
+
+static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp)
+{
+ x->x_conv = 1. / sp[0]->s_sr;
+ tabosc4_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabosc4_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void tabosc4_tilde_setup(void)
+{
+ tabosc4_tilde_class = class_new(gensym("tabosc4~"),
+ (t_newmethod)tabosc4_tilde_new, 0,
+ sizeof(t_tabosc4_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabosc4_tilde_class, t_tabosc4_tilde, x_f);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+/* ------------------------ tabsend~ ------------------------- */
+
+static t_class *tabsend_class;
+
+typedef struct _tabsend
+{
+ t_object x_obj;
+ float *x_vec;
+ int x_graphperiod;
+ int x_graphcount;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_f;
+} t_tabsend;
+
+static void tabsend_tick(t_tabsend *x);
+
+static void *tabsend_new(t_symbol *s)
+{
+ t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
+ x->x_graphcount = 0;
+ x->x_arrayname = s;
+ x->x_clock = clock_new(x, (t_method)tabsend_tick);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabsend_perform(t_int *w)
+{
+ t_tabsend *x = (t_tabsend *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = w[3];
+ t_float *dest = x->x_vec;
+ int i = x->x_graphcount;
+ if (!x->x_vec) goto bad;
+
+ while (n--)
+ {
+ float f = *in++;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+ *dest++ = f;
+ }
+ if (!i--)
+ {
+ clock_delay(x->x_clock, 0);
+ i = x->x_graphperiod;
+ }
+ x->x_graphcount = i;
+bad:
+ return (w+4);
+}
+
+static void tabsend_dsp(t_tabsend *x, t_signal **sp)
+{
+ int i, vecsize;
+ t_garray *a;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*x->x_arrayname->s_name)
+ pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
+ }
+ else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
+ pd_error(x, "%s: bad template for tabsend~", x->x_arrayname->s_name);
+ else
+ {
+ int n = sp[0]->s_n;
+ int ticksper = sp[0]->s_sr/n;
+ if (ticksper < 1) ticksper = 1;
+ x->x_graphperiod = ticksper;
+ if (x->x_graphcount > ticksper) x->x_graphcount = ticksper;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ dsp_add(tabsend_perform, 3, x, sp[0]->s_vec, vecsize);
+ }
+}
+
+static void tabsend_tick(t_tabsend *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabsend_tick");
+ else garray_redraw(a);
+}
+
+static void tabsend_free(t_tabsend *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabsend_setup(void)
+{
+ tabsend_class = class_new(gensym("tabsend~"), (t_newmethod)tabsend_new,
+ (t_method)tabsend_free, sizeof(t_tabsend), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, x_f);
+ class_addmethod(tabsend_class, (t_method)tabsend_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------ tabreceive~ ------------------------- */
+
+static t_class *tabreceive_class;
+
+typedef struct _tabreceive
+{
+ t_object x_obj;
+ float *x_vec;
+ t_symbol *x_arrayname;
+} t_tabreceive;
+
+static t_int *tabreceive_perform(t_int *w)
+{
+ t_tabreceive *x = (t_tabreceive *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = w[3];
+ t_float *from = x->x_vec;
+ if (from) while (n--) *out++ = *from++;
+ else while (n--) *out++ = 0;
+ return (w+4);
+}
+
+static void tabreceive_dsp(t_tabreceive *x, t_signal **sp)
+{
+ t_garray *a;
+ int vecsize;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*x->x_arrayname->s_name)
+ pd_error(x, "tabsend~: %s: no such array", x->x_arrayname->s_name);
+ }
+ else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
+ pd_error(x, "%s: bad template for tabreceive~", x->x_arrayname->s_name);
+ else
+ {
+ int n = sp[0]->s_n;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ dsp_add(tabreceive_perform, 3, x, sp[0]->s_vec, vecsize);
+ }
+}
+
+static void *tabreceive_new(t_symbol *s)
+{
+ t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static void tabreceive_setup(void)
+{
+ tabreceive_class = class_new(gensym("tabreceive~"),
+ (t_newmethod)tabreceive_new, 0,
+ sizeof(t_tabreceive), 0, A_DEFSYM, 0);
+ class_addmethod(tabreceive_class, (t_method)tabreceive_dsp,
+ gensym("dsp"), 0);
+}
+
+
+/* ---------- tabread: control, non-interpolating ------------------------ */
+
+static t_class *tabread_class;
+
+typedef struct _tabread
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+} t_tabread;
+
+static void tabread_float(t_tabread *x, t_float f)
+{
+ t_garray *a;
+ int npoints;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ pd_error(x, "%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &npoints, &vec))
+ pd_error(x, "%s: bad template for tabread", x->x_arrayname->s_name);
+ else
+ {
+ int n = f;
+ if (n < 0) n = 0;
+ else if (n >= npoints) n = npoints - 1;
+ outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n] : 0));
+ }
+}
+
+static void tabread_set(t_tabread *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void *tabread_new(t_symbol *s)
+{
+ t_tabread *x = (t_tabread *)pd_new(tabread_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void tabread_setup(void)
+{
+ tabread_class = class_new(gensym("tabread"), (t_newmethod)tabread_new,
+ 0, sizeof(t_tabread), 0, A_DEFSYM, 0);
+ class_addfloat(tabread_class, (t_method)tabread_float);
+ class_addmethod(tabread_class, (t_method)tabread_set, gensym("set"),
+ A_SYMBOL, 0);
+}
+
+/* ---------- tabread4: control, non-interpolating ------------------------ */
+
+static t_class *tabread4_class;
+
+typedef struct _tabread4
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+} t_tabread4;
+
+static void tabread4_float(t_tabread4 *x, t_float f)
+{
+ t_garray *a;
+ int npoints;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ pd_error(x, "%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &npoints, &vec))
+ pd_error(x, "%s: bad template for tabread4", x->x_arrayname->s_name);
+ else if (npoints < 4)
+ outlet_float(x->x_obj.ob_outlet, 0);
+ else if (f <= 1)
+ outlet_float(x->x_obj.ob_outlet, vec[1]);
+ else if (f >= npoints - 2)
+ outlet_float(x->x_obj.ob_outlet, vec[npoints - 2]);
+ else
+ {
+ int n = f;
+ float a, b, c, d, cminusb, frac, *fp;
+ if (n >= npoints - 2)
+ n = npoints - 3;
+ fp = vec + n;
+ frac = f - n;
+ a = fp[-1];
+ b = fp[0];
+ c = fp[1];
+ d = fp[2];
+ cminusb = c-b;
+ outlet_float(x->x_obj.ob_outlet, b + frac * (
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))));
+ }
+}
+
+static void tabread4_set(t_tabread4 *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void *tabread4_new(t_symbol *s)
+{
+ t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void tabread4_setup(void)
+{
+ tabread4_class = class_new(gensym("tabread4"), (t_newmethod)tabread4_new,
+ 0, sizeof(t_tabread4), 0, A_DEFSYM, 0);
+ class_addfloat(tabread4_class, (t_method)tabread4_float);
+ class_addmethod(tabread4_class, (t_method)tabread4_set, gensym("set"),
+ A_SYMBOL, 0);
+}
+
+/* ------------------ tabwrite: control ------------------------ */
+
+static t_class *tabwrite_class;
+
+typedef struct _tabwrite
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_ft1;
+ double x_updtime;
+ int x_set;
+} t_tabwrite;
+
+static void tabwrite_tick(t_tabwrite *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabwrite_tick");
+ else garray_redraw(a);
+ x->x_set = 0;
+ x->x_updtime = clock_getsystime();
+}
+
+static void tabwrite_float(t_tabwrite *x, t_float f)
+{
+ int i, vecsize;
+ t_garray *a;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ pd_error(x, "%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &vecsize, &vec))
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname->s_name);
+ else
+ {
+ int n = x->x_ft1;
+ double timesince = clock_gettimesince(x->x_updtime);
+ if (n < 0) n = 0;
+ else if (n >= vecsize) n = vecsize-1;
+ vec[n] = f;
+ if (timesince > 1000)
+ {
+ tabwrite_tick(x);
+ }
+ else
+ {
+ if (x->x_set == 0)
+ {
+ clock_delay(x->x_clock, 1000 - timesince);
+ x->x_set = 1;
+ }
+ }
+ }
+}
+
+static void tabwrite_set(t_tabwrite *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void tabwrite_free(t_tabwrite *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *tabwrite_new(t_symbol *s)
+{
+ t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
+ x->x_ft1 = 0;
+ x->x_arrayname = s;
+ x->x_updtime = clock_getsystime();
+ x->x_clock = clock_new(x, (t_method)tabwrite_tick);
+ floatinlet_new(&x->x_obj, &x->x_ft1);
+ return (x);
+}
+
+void tabwrite_setup(void)
+{
+ tabwrite_class = class_new(gensym("tabwrite"), (t_newmethod)tabwrite_new,
+ (t_method)tabwrite_free, sizeof(t_tabwrite), 0, A_DEFSYM, 0);
+ class_addfloat(tabwrite_class, (t_method)tabwrite_float);
+ class_addmethod(tabwrite_class, (t_method)tabwrite_set, gensym("set"), A_SYMBOL, 0);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_array_setup(void)
+{
+ tabwrite_tilde_setup();
+ tabplay_tilde_setup();
+ tabread_tilde_setup();
+ tabread4_tilde_setup();
+ tabosc4_tilde_setup();
+ tabsend_setup();
+ tabreceive_setup();
+ tabread_setup();
+ tabread4_setup();
+ tabwrite_setup();
+}
+
diff --git a/apps/plugins/pdbox/PDa/src/d_ctl.c b/apps/plugins/pdbox/PDa/src/d_ctl.c
new file mode 100644
index 0000000000..d3262af800
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_ctl.c
@@ -0,0 +1,1568 @@
+/* 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. */
+
+/* sig~ and line~ control-to-signal converters;
+ snapshot~ signal-to-control converter.
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+/* -------------------------- sig~ ------------------------------ */
+static t_class *sig_tilde_class;
+
+typedef struct _sig
+{
+ t_object x_obj;
+ float x_f;
+} t_sig;
+
+static t_int *sig_tilde_perform(t_int *w)
+{
+ t_float f = *(t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--)
+ *out++ = f;
+ return (w+4);
+}
+
+static t_int *sig_tilde_perf8(t_int *w)
+{
+ t_float f = *(t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+
+ for (; n; n -= 8, out += 8)
+ {
+ out[0] = f;
+ out[1] = f;
+ out[2] = f;
+ out[3] = f;
+ out[4] = f;
+ out[5] = f;
+ out[6] = f;
+ out[7] = f;
+ }
+ return (w+4);
+}
+
+void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(sig_tilde_perform, 3, in, out, n);
+ else
+ dsp_add(sig_tilde_perf8, 3, in, out, n);
+}
+
+static void sig_tilde_float(t_sig *x, t_float f)
+{
+ x->x_f = f;
+}
+
+static void sig_tilde_dsp(t_sig *x, t_signal **sp)
+{
+ dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void *sig_tilde_new(t_floatarg f)
+{
+ t_sig *x = (t_sig *)pd_new(sig_tilde_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static void sig_tilde_setup(void)
+{
+ sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
+ sizeof(t_sig), 0, A_DEFFLOAT, 0);
+ class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
+ class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
+}
+
+
+#ifndef FIXEDPOINT
+
+/* -------------------------- line~ ------------------------------ */
+static t_class *line_tilde_class;
+
+typedef struct _line
+{
+ t_object x_obj;
+ float x_target;
+ float x_value;
+ float x_biginc;
+ float x_inc;
+ float x_1overn;
+ float x_dspticktomsec;
+ float x_inletvalue;
+ float x_inletwas;
+ int x_ticksleft;
+ int x_retarget;
+} t_line;
+
+static t_int *line_tilde_perform(t_int *w)
+{
+ t_line *x = (t_line *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ float f = x->x_value;
+
+ if (PD_BIGORSMALL(f))
+ x->x_value = f = 0;
+ if (x->x_retarget)
+ {
+ int nticks = x->x_inletwas * x->x_dspticktomsec;
+ if (!nticks) nticks = 1;
+ x->x_ticksleft = nticks;
+ x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
+ x->x_inc = x->x_1overn * x->x_biginc;
+ x->x_retarget = 0;
+ }
+ if (x->x_ticksleft)
+ {
+ float f = x->x_value;
+ while (n--) *out++ = f, f += x->x_inc;
+ x->x_value += x->x_biginc;
+ x->x_ticksleft--;
+ }
+ else
+ {
+ x->x_value = x->x_target;
+ while (n--) *out++ = x->x_value;
+ }
+ return (w+4);
+}
+
+static void line_tilde_float(t_line *x, t_float f)
+{
+ if (x->x_inletvalue <= 0)
+ {
+ x->x_target = x->x_value = f;
+ x->x_ticksleft = x->x_retarget = 0;
+ }
+ else
+ {
+ x->x_target = f;
+ x->x_retarget = 1;
+ x->x_inletwas = x->x_inletvalue;
+ x->x_inletvalue = 0;
+ }
+}
+
+static void line_tilde_stop(t_line *x)
+{
+ x->x_target = x->x_value;
+ x->x_ticksleft = x->x_retarget = 0;
+}
+
+static void line_tilde_dsp(t_line *x, t_signal **sp)
+{
+ dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ x->x_1overn = 1./sp[0]->s_n;
+ x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
+}
+
+static void *line_tilde_new(void)
+{
+ t_line *x = (t_line *)pd_new(line_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_inletvalue);
+ x->x_ticksleft = x->x_retarget = 0;
+ x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
+ return (x);
+}
+
+static void line_tilde_setup(void)
+{
+ line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
+ sizeof(t_line), 0, 0);
+ class_addfloat(line_tilde_class, (t_method)line_tilde_float);
+ class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
+ gensym("stop"), 0);
+}
+
+/* -------------------------- vline~ ------------------------------ */
+static t_class *vline_tilde_class;
+
+typedef struct _vseg
+{
+ double s_targettime;
+ double s_starttime;
+ float s_target;
+ struct _vseg *s_next;
+} t_vseg;
+
+typedef struct _vline
+{
+ t_object x_obj;
+ double x_value;
+ double x_inc;
+ double x_referencetime;
+ double x_samppermsec;
+ double x_msecpersamp;
+ double x_targettime;
+ float x_target;
+ float x_inlet1;
+ float x_inlet2;
+ t_vseg *x_list;
+} t_vline;
+
+static t_int *vline_tilde_perform(t_int *w)
+{
+ t_vline *x = (t_vline *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]), i;
+ double f = x->x_value;
+ double inc = x->x_inc;
+ double msecpersamp = x->x_msecpersamp;
+ double samppermsec = x->x_samppermsec;
+ double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
+ t_vseg *s = x->x_list;
+ for (i = 0; i < n; i++)
+ {
+ double timenext = timenow + msecpersamp;
+ checknext:
+ if (s)
+ {
+ /* has starttime elapsed? If so update value and increment */
+ if (s->s_starttime < timenext)
+ {
+ if (x->x_targettime <= timenext)
+ f = x->x_target, inc = 0;
+ /* if zero-length segment bash output value */
+ if (s->s_targettime <= s->s_starttime)
+ {
+ f = s->s_target;
+ inc = 0;
+ }
+ else
+ {
+ double incpermsec = (s->s_target - f)/
+ (s->s_targettime - s->s_starttime);
+ f = f + incpermsec * (timenext - s->s_starttime);
+ inc = incpermsec * msecpersamp;
+ }
+ x->x_inc = inc;
+ x->x_target = s->s_target;
+ x->x_targettime = s->s_targettime;
+ x->x_list = s->s_next;
+ t_freebytes(s, sizeof(*s));
+ s = x->x_list;
+ goto checknext;
+ }
+ }
+ if (x->x_targettime <= timenext)
+ f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20;
+ *out++ = f;
+ f = f + inc;
+ timenow = timenext;
+ }
+ x->x_value = f;
+ return (w+4);
+}
+
+static void vline_tilde_stop(t_vline *x)
+{
+ t_vseg *s1, *s2;
+ for (s1 = x->x_list; s1; s1 = s2)
+ s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
+ x->x_list = 0;
+ x->x_inc = 0;
+ x->x_inlet1 = x->x_inlet2 = 0;
+ x->x_target = x->x_value;
+ x->x_targettime = 1e20;
+}
+
+static void vline_tilde_float(t_vline *x, t_float f)
+{
+ double timenow = clock_gettimesince(x->x_referencetime);
+ float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
+ float inlet2 = x->x_inlet2;
+ double starttime = timenow + inlet2;
+ t_vseg *s1, *s2, *deletefrom = 0, *snew;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+
+ /* negative delay input means stop and jump immediately to new value */
+ if (inlet2 < 0)
+ {
+ x->x_value = f;
+ vline_tilde_stop(x);
+ return;
+ }
+ snew = (t_vseg *)t_getbytes(sizeof(*snew));
+ /* check if we supplant the first item in the list. We supplant
+ an item by having an earlier starttime, or an equal starttime unless
+ the equal one was instantaneous and the new one isn't (in which case
+ we'll do a jump-and-slide starting at that time.) */
+ if (!x->x_list || x->x_list->s_starttime > starttime ||
+ (x->x_list->s_starttime == starttime &&
+ (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
+ {
+ deletefrom = x->x_list;
+ x->x_list = snew;
+ }
+ else
+ {
+ for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
+ {
+ if (s2->s_starttime > starttime ||
+ (s2->s_starttime == starttime &&
+ (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
+ {
+ deletefrom = s2;
+ s1->s_next = snew;
+ goto didit;
+ }
+ }
+ s1->s_next = snew;
+ deletefrom = 0;
+ didit: ;
+ }
+ while (deletefrom)
+ {
+ s1 = deletefrom->s_next;
+ t_freebytes(deletefrom, sizeof(*deletefrom));
+ deletefrom = s1;
+ }
+ snew->s_next = 0;
+ snew->s_target = f;
+ snew->s_starttime = starttime;
+ snew->s_targettime = starttime + inlet1;
+ x->x_inlet1 = x->x_inlet2 = 0;
+}
+
+static void vline_tilde_dsp(t_vline *x, t_signal **sp)
+{
+ dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
+ x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
+}
+
+static void *vline_tilde_new(void)
+{
+ t_vline *x = (t_vline *)pd_new(vline_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_inlet1);
+ floatinlet_new(&x->x_obj, &x->x_inlet2);
+ x->x_inlet1 = x->x_inlet2 = 0;
+ x->x_value = x->x_inc = 0;
+ x->x_referencetime = clock_getlogicaltime();
+ x->x_list = 0;
+ x->x_samppermsec = 0;
+ x->x_targettime = 1e20;
+ return (x);
+}
+
+static void vline_tilde_setup(void)
+{
+ vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
+ (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
+ class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
+ class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
+ gensym("stop"), 0);
+}
+
+/* -------------------------- snapshot~ ------------------------------ */
+static t_class *snapshot_tilde_class;
+
+typedef struct _snapshot
+{
+ t_object x_obj;
+ t_sample x_value;
+ float x_f;
+} t_snapshot;
+
+static void *snapshot_tilde_new(void)
+{
+ t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
+ x->x_value = 0;
+ outlet_new(&x->x_obj, &s_float);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *snapshot_tilde_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ *out = *in;
+ return (w+3);
+}
+
+static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
+{
+ dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
+ &x->x_value);
+}
+
+static void snapshot_tilde_bang(t_snapshot *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_value);
+}
+
+static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
+{
+ x->x_value = f;
+}
+
+static void snapshot_tilde_setup(void)
+{
+ snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
+ sizeof(t_snapshot), 0, 0);
+ CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
+ class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
+ gensym("set"), A_DEFFLOAT, 0);
+ class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
+}
+
+/* -------------------------- vsnapshot~ ------------------------------ */
+static t_class *vsnapshot_tilde_class;
+
+typedef struct _vsnapshot
+{
+ t_object x_obj;
+ int x_n;
+ int x_gotone;
+ t_sample *x_vec;
+ float x_f;
+ float x_sampspermsec;
+ double x_time;
+} t_vsnapshot;
+
+static void *vsnapshot_tilde_new(void)
+{
+ t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_f = 0;
+ x->x_n = 0;
+ x->x_vec = 0;
+ x->x_gotone = 0;
+ return (x);
+}
+
+static t_int *vsnapshot_tilde_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_vsnapshot *x = (t_vsnapshot *)(w[2]);
+ t_float *out = x->x_vec;
+ int n = x->x_n, i;
+ for (i = 0; i < n; i++)
+ out[i] = in[i];
+ x->x_time = clock_getlogicaltime();
+ x->x_gotone = 1;
+ return (w+3);
+}
+
+static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ if (n != x->x_n)
+ {
+ if (x->x_vec)
+ t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
+ x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
+ x->x_gotone = 0;
+ x->x_n = n;
+ }
+ x->x_sampspermsec = sp[0]->s_sr / 1000;
+ dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
+}
+
+static void vsnapshot_tilde_bang(t_vsnapshot *x)
+{
+ float val;
+ if (x->x_gotone)
+ {
+ int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
+ if (indx < 0)
+ indx = 0;
+ else if (indx >= x->x_n)
+ indx = x->x_n - 1;
+ val = x->x_vec[indx];
+ }
+ else val = 0;
+ outlet_float(x->x_obj.ob_outlet, val);
+}
+
+static void vsnapshot_tilde_ff(t_vsnapshot *x)
+{
+ if (x->x_vec)
+ t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
+}
+
+static void vsnapshot_tilde_setup(void)
+{
+ vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
+ vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
+ sizeof(t_vsnapshot), 0, 0);
+ CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
+ class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
+ class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
+}
+
+
+/* ---------------- env~ - simple envelope follower. ----------------- */
+
+#define MAXOVERLAP 10
+#define MAXVSTAKEN 64
+
+typedef struct sigenv
+{
+ t_object x_obj; /* header */
+ void *x_outlet; /* a "float" outlet */
+ void *x_clock; /* a "clock" object */
+ float *x_buf; /* a Hanning window */
+ int x_phase; /* number of points since last output */
+ int x_period; /* requested period of output */
+ int x_realperiod; /* period rounded up to vecsize multiple */
+ int x_npoints; /* analysis window size in samples */
+ float x_result; /* result to output */
+ float x_sumbuf[MAXOVERLAP]; /* summing buffer */
+ float x_f;
+} t_sigenv;
+
+t_class *env_tilde_class;
+static void env_tilde_tick(t_sigenv *x);
+
+static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
+{
+ int npoints = fnpoints;
+ int period = fperiod;
+ t_sigenv *x;
+ float *buf;
+ int i;
+
+ if (npoints < 1) npoints = 1024;
+ if (period < 1) period = npoints/2;
+ if (period < npoints / MAXOVERLAP + 1)
+ period = npoints / MAXOVERLAP + 1;
+ if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
+ {
+ error("env: couldn't allocate buffer");
+ return (0);
+ }
+ x = (t_sigenv *)pd_new(env_tilde_class);
+ x->x_buf = buf;
+ x->x_npoints = npoints;
+ x->x_phase = 0;
+ x->x_period = period;
+ for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
+ for (i = 0; i < npoints; i++)
+ buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
+ for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
+ x->x_clock = clock_new(x, (t_method)env_tilde_tick);
+ x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *env_tilde_perform(t_int *w)
+{
+ t_sigenv *x = (t_sigenv *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ int count;
+ float *sump;
+ in += n;
+ for (count = x->x_phase, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ {
+ float *hp = x->x_buf + count;
+ float *fp = in;
+ float sum = *sump;
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ fp--;
+ sum += *hp++ * (*fp * *fp);
+ }
+ *sump = sum;
+ }
+ sump[0] = 0;
+ x->x_phase -= n;
+ if (x->x_phase < 0)
+ {
+ x->x_result = x->x_sumbuf[0];
+ for (count = x->x_realperiod, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ sump[0] = sump[1];
+ sump[0] = 0;
+ x->x_phase = x->x_realperiod - n;
+ clock_delay(x->x_clock, 0L);
+ }
+ return (w+4);
+}
+
+static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
+{
+ if (x->x_period % sp[0]->s_n) x->x_realperiod =
+ x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
+ else x->x_realperiod = x->x_period;
+ dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
+}
+
+static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
+{
+ outlet_float(x->x_outlet, powtodb(x->x_result));
+}
+
+static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
+{
+ clock_free(x->x_clock);
+ freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
+}
+
+
+void env_tilde_setup(void )
+{
+ env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
+ (t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
+ class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* --------------------- threshold~ ----------------------------- */
+
+static t_class *threshold_tilde_class;
+
+typedef struct _threshold_tilde
+{
+ t_object x_obj;
+ t_outlet *x_outlet1; /* bang out for high thresh */
+ t_outlet *x_outlet2; /* bang out for low thresh */
+ t_clock *x_clock; /* wakeup for message output */
+ float x_f; /* scalar inlet */
+ int x_state; /* 1 = high, 0 = low */
+ float x_hithresh; /* value of high threshold */
+ float x_lothresh; /* value of low threshold */
+ float x_deadwait; /* msec remaining in dead period */
+ float x_msecpertick; /* msec per DSP tick */
+ float x_hideadtime; /* hi dead time in msec */
+ float x_lodeadtime; /* lo dead time in msec */
+} t_threshold_tilde;
+
+static void threshold_tilde_tick(t_threshold_tilde *x);
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime);
+
+static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
+ t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
+{
+ t_threshold_tilde *x = (t_threshold_tilde *)
+ pd_new(threshold_tilde_class);
+ x->x_state = 0; /* low state */
+ x->x_deadwait = 0; /* no dead time */
+ x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_msecpertick = 0.;
+ x->x_f = 0;
+ threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
+ return (x);
+}
+
+ /* "set" message to specify thresholds and dead times */
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime)
+{
+ if (lothresh > hithresh)
+ lothresh = hithresh;
+ x->x_hithresh = hithresh;
+ x->x_hideadtime = hideadtime;
+ x->x_lothresh = lothresh;
+ x->x_lodeadtime = lodeadtime;
+}
+
+ /* number in inlet sets state -- note incompatible with JMAX which used
+ "int" message for this, impossible here because of auto signal conversion */
+static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
+{
+ x->x_state = (f != 0);
+ x->x_deadwait = 0;
+}
+
+static void threshold_tilde_tick(t_threshold_tilde *x)
+{
+ if (x->x_state)
+ outlet_bang(x->x_outlet1);
+ else outlet_bang(x->x_outlet2);
+}
+
+static t_int *threshold_tilde_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
+ int n = (t_int)(w[3]);
+ if (x->x_deadwait > 0)
+ x->x_deadwait -= x->x_msecpertick;
+ else if (x->x_state)
+ {
+ /* we're high; look for low sample */
+ for (; n--; in1++)
+ {
+ if (*in1 < x->x_lothresh)
+ {
+ clock_delay(x->x_clock, 0L);
+ x->x_state = 0;
+ x->x_deadwait = x->x_lodeadtime;
+ goto done;
+ }
+ }
+ }
+ else
+ {
+ /* we're low; look for high sample */
+ for (; n--; in1++)
+ {
+ if (*in1 >= x->x_hithresh)
+ {
+ clock_delay(x->x_clock, 0L);
+ x->x_state = 1;
+ x->x_deadwait = x->x_hideadtime;
+ goto done;
+ }
+ }
+ }
+done:
+ return (w+4);
+}
+
+void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
+{
+ x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
+ dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
+}
+
+static void threshold_tilde_ff(t_threshold_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void threshold_tilde_setup( void)
+{
+ threshold_tilde_class = class_new(gensym("threshold~"),
+ (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
+ sizeof(t_threshold_tilde), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
+ gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_ctl_setup(void)
+{
+ sig_tilde_setup();
+ line_tilde_setup();
+ vline_tilde_setup();
+ snapshot_tilde_setup();
+ vsnapshot_tilde_setup();
+ env_tilde_setup();
+ threshold_tilde_setup();
+}
+
+#endif
+/* 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. */
+
+/* sig~ and line~ control-to-signal converters;
+ snapshot~ signal-to-control converter.
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+/* -------------------------- sig~ ------------------------------ */
+static t_class *sig_tilde_class;
+
+typedef struct _sig
+{
+ t_object x_obj;
+ float x_f;
+} t_sig;
+
+static t_int *sig_tilde_perform(t_int *w)
+{
+ t_float f = *(t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--)
+ *out++ = f;
+ return (w+4);
+}
+
+static t_int *sig_tilde_perf8(t_int *w)
+{
+ t_float f = *(t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+
+ for (; n; n -= 8, out += 8)
+ {
+ out[0] = f;
+ out[1] = f;
+ out[2] = f;
+ out[3] = f;
+ out[4] = f;
+ out[5] = f;
+ out[6] = f;
+ out[7] = f;
+ }
+ return (w+4);
+}
+
+void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(sig_tilde_perform, 3, in, out, n);
+ else
+ dsp_add(sig_tilde_perf8, 3, in, out, n);
+}
+
+static void sig_tilde_float(t_sig *x, t_float f)
+{
+ x->x_f = f;
+}
+
+static void sig_tilde_dsp(t_sig *x, t_signal **sp)
+{
+ dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void *sig_tilde_new(t_floatarg f)
+{
+ t_sig *x = (t_sig *)pd_new(sig_tilde_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static void sig_tilde_setup(void)
+{
+ sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
+ sizeof(t_sig), 0, A_DEFFLOAT, 0);
+ class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
+ class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
+}
+
+
+#ifndef FIXEDPOINT
+
+/* -------------------------- line~ ------------------------------ */
+static t_class *line_tilde_class;
+
+typedef struct _line
+{
+ t_object x_obj;
+ float x_target;
+ float x_value;
+ float x_biginc;
+ float x_inc;
+ float x_1overn;
+ float x_dspticktomsec;
+ float x_inletvalue;
+ float x_inletwas;
+ int x_ticksleft;
+ int x_retarget;
+} t_line;
+
+static t_int *line_tilde_perform(t_int *w)
+{
+ t_line *x = (t_line *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ float f = x->x_value;
+
+ if (PD_BIGORSMALL(f))
+ x->x_value = f = 0;
+ if (x->x_retarget)
+ {
+ int nticks = x->x_inletwas * x->x_dspticktomsec;
+ if (!nticks) nticks = 1;
+ x->x_ticksleft = nticks;
+ x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
+ x->x_inc = x->x_1overn * x->x_biginc;
+ x->x_retarget = 0;
+ }
+ if (x->x_ticksleft)
+ {
+ float f = x->x_value;
+ while (n--) *out++ = f, f += x->x_inc;
+ x->x_value += x->x_biginc;
+ x->x_ticksleft--;
+ }
+ else
+ {
+ x->x_value = x->x_target;
+ while (n--) *out++ = x->x_value;
+ }
+ return (w+4);
+}
+
+static void line_tilde_float(t_line *x, t_float f)
+{
+ if (x->x_inletvalue <= 0)
+ {
+ x->x_target = x->x_value = f;
+ x->x_ticksleft = x->x_retarget = 0;
+ }
+ else
+ {
+ x->x_target = f;
+ x->x_retarget = 1;
+ x->x_inletwas = x->x_inletvalue;
+ x->x_inletvalue = 0;
+ }
+}
+
+static void line_tilde_stop(t_line *x)
+{
+ x->x_target = x->x_value;
+ x->x_ticksleft = x->x_retarget = 0;
+}
+
+static void line_tilde_dsp(t_line *x, t_signal **sp)
+{
+ dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ x->x_1overn = 1./sp[0]->s_n;
+ x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
+}
+
+static void *line_tilde_new(void)
+{
+ t_line *x = (t_line *)pd_new(line_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_inletvalue);
+ x->x_ticksleft = x->x_retarget = 0;
+ x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
+ return (x);
+}
+
+static void line_tilde_setup(void)
+{
+ line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
+ sizeof(t_line), 0, 0);
+ class_addfloat(line_tilde_class, (t_method)line_tilde_float);
+ class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
+ gensym("stop"), 0);
+}
+
+/* -------------------------- vline~ ------------------------------ */
+static t_class *vline_tilde_class;
+
+typedef struct _vseg
+{
+ double s_targettime;
+ double s_starttime;
+ float s_target;
+ struct _vseg *s_next;
+} t_vseg;
+
+typedef struct _vline
+{
+ t_object x_obj;
+ double x_value;
+ double x_inc;
+ double x_referencetime;
+ double x_samppermsec;
+ double x_msecpersamp;
+ double x_targettime;
+ float x_target;
+ float x_inlet1;
+ float x_inlet2;
+ t_vseg *x_list;
+} t_vline;
+
+static t_int *vline_tilde_perform(t_int *w)
+{
+ t_vline *x = (t_vline *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]), i;
+ double f = x->x_value;
+ double inc = x->x_inc;
+ double msecpersamp = x->x_msecpersamp;
+ double samppermsec = x->x_samppermsec;
+ double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
+ t_vseg *s = x->x_list;
+ for (i = 0; i < n; i++)
+ {
+ double timenext = timenow + msecpersamp;
+ checknext:
+ if (s)
+ {
+ /* has starttime elapsed? If so update value and increment */
+ if (s->s_starttime < timenext)
+ {
+ if (x->x_targettime <= timenext)
+ f = x->x_target, inc = 0;
+ /* if zero-length segment bash output value */
+ if (s->s_targettime <= s->s_starttime)
+ {
+ f = s->s_target;
+ inc = 0;
+ }
+ else
+ {
+ double incpermsec = (s->s_target - f)/
+ (s->s_targettime - s->s_starttime);
+ f = f + incpermsec * (timenext - s->s_starttime);
+ inc = incpermsec * msecpersamp;
+ }
+ x->x_inc = inc;
+ x->x_target = s->s_target;
+ x->x_targettime = s->s_targettime;
+ x->x_list = s->s_next;
+ t_freebytes(s, sizeof(*s));
+ s = x->x_list;
+ goto checknext;
+ }
+ }
+ if (x->x_targettime <= timenext)
+ f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20;
+ *out++ = f;
+ f = f + inc;
+ timenow = timenext;
+ }
+ x->x_value = f;
+ return (w+4);
+}
+
+static void vline_tilde_stop(t_vline *x)
+{
+ t_vseg *s1, *s2;
+ for (s1 = x->x_list; s1; s1 = s2)
+ s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
+ x->x_list = 0;
+ x->x_inc = 0;
+ x->x_inlet1 = x->x_inlet2 = 0;
+ x->x_target = x->x_value;
+ x->x_targettime = 1e20;
+}
+
+static void vline_tilde_float(t_vline *x, t_float f)
+{
+ double timenow = clock_gettimesince(x->x_referencetime);
+ float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
+ float inlet2 = x->x_inlet2;
+ double starttime = timenow + inlet2;
+ t_vseg *s1, *s2, *deletefrom = 0, *snew;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+
+ /* negative delay input means stop and jump immediately to new value */
+ if (inlet2 < 0)
+ {
+ x->x_value = f;
+ vline_tilde_stop(x);
+ return;
+ }
+ snew = (t_vseg *)t_getbytes(sizeof(*snew));
+ /* check if we supplant the first item in the list. We supplant
+ an item by having an earlier starttime, or an equal starttime unless
+ the equal one was instantaneous and the new one isn't (in which case
+ we'll do a jump-and-slide starting at that time.) */
+ if (!x->x_list || x->x_list->s_starttime > starttime ||
+ (x->x_list->s_starttime == starttime &&
+ (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
+ {
+ deletefrom = x->x_list;
+ x->x_list = snew;
+ }
+ else
+ {
+ for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
+ {
+ if (s2->s_starttime > starttime ||
+ (s2->s_starttime == starttime &&
+ (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
+ {
+ deletefrom = s2;
+ s1->s_next = snew;
+ goto didit;
+ }
+ }
+ s1->s_next = snew;
+ deletefrom = 0;
+ didit: ;
+ }
+ while (deletefrom)
+ {
+ s1 = deletefrom->s_next;
+ t_freebytes(deletefrom, sizeof(*deletefrom));
+ deletefrom = s1;
+ }
+ snew->s_next = 0;
+ snew->s_target = f;
+ snew->s_starttime = starttime;
+ snew->s_targettime = starttime + inlet1;
+ x->x_inlet1 = x->x_inlet2 = 0;
+}
+
+static void vline_tilde_dsp(t_vline *x, t_signal **sp)
+{
+ dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
+ x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
+}
+
+static void *vline_tilde_new(void)
+{
+ t_vline *x = (t_vline *)pd_new(vline_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_inlet1);
+ floatinlet_new(&x->x_obj, &x->x_inlet2);
+ x->x_inlet1 = x->x_inlet2 = 0;
+ x->x_value = x->x_inc = 0;
+ x->x_referencetime = clock_getlogicaltime();
+ x->x_list = 0;
+ x->x_samppermsec = 0;
+ x->x_targettime = 1e20;
+ return (x);
+}
+
+static void vline_tilde_setup(void)
+{
+ vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
+ (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
+ class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
+ class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
+ gensym("stop"), 0);
+}
+
+/* -------------------------- snapshot~ ------------------------------ */
+static t_class *snapshot_tilde_class;
+
+typedef struct _snapshot
+{
+ t_object x_obj;
+ t_sample x_value;
+ float x_f;
+} t_snapshot;
+
+static void *snapshot_tilde_new(void)
+{
+ t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
+ x->x_value = 0;
+ outlet_new(&x->x_obj, &s_float);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *snapshot_tilde_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ *out = *in;
+ return (w+3);
+}
+
+static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
+{
+ dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
+ &x->x_value);
+}
+
+static void snapshot_tilde_bang(t_snapshot *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_value);
+}
+
+static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
+{
+ x->x_value = f;
+}
+
+static void snapshot_tilde_setup(void)
+{
+ snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
+ sizeof(t_snapshot), 0, 0);
+ CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
+ class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
+ gensym("set"), A_DEFFLOAT, 0);
+ class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
+}
+
+/* -------------------------- vsnapshot~ ------------------------------ */
+static t_class *vsnapshot_tilde_class;
+
+typedef struct _vsnapshot
+{
+ t_object x_obj;
+ int x_n;
+ int x_gotone;
+ t_sample *x_vec;
+ float x_f;
+ float x_sampspermsec;
+ double x_time;
+} t_vsnapshot;
+
+static void *vsnapshot_tilde_new(void)
+{
+ t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_f = 0;
+ x->x_n = 0;
+ x->x_vec = 0;
+ x->x_gotone = 0;
+ return (x);
+}
+
+static t_int *vsnapshot_tilde_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_vsnapshot *x = (t_vsnapshot *)(w[2]);
+ t_float *out = x->x_vec;
+ int n = x->x_n, i;
+ for (i = 0; i < n; i++)
+ out[i] = in[i];
+ x->x_time = clock_getlogicaltime();
+ x->x_gotone = 1;
+ return (w+3);
+}
+
+static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ if (n != x->x_n)
+ {
+ if (x->x_vec)
+ t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
+ x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
+ x->x_gotone = 0;
+ x->x_n = n;
+ }
+ x->x_sampspermsec = sp[0]->s_sr / 1000;
+ dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
+}
+
+static void vsnapshot_tilde_bang(t_vsnapshot *x)
+{
+ float val;
+ if (x->x_gotone)
+ {
+ int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
+ if (indx < 0)
+ indx = 0;
+ else if (indx >= x->x_n)
+ indx = x->x_n - 1;
+ val = x->x_vec[indx];
+ }
+ else val = 0;
+ outlet_float(x->x_obj.ob_outlet, val);
+}
+
+static void vsnapshot_tilde_ff(t_vsnapshot *x)
+{
+ if (x->x_vec)
+ t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
+}
+
+static void vsnapshot_tilde_setup(void)
+{
+ vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
+ vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
+ sizeof(t_vsnapshot), 0, 0);
+ CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
+ class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
+ class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
+}
+
+
+/* ---------------- env~ - simple envelope follower. ----------------- */
+
+#define MAXOVERLAP 10
+#define MAXVSTAKEN 64
+
+typedef struct sigenv
+{
+ t_object x_obj; /* header */
+ void *x_outlet; /* a "float" outlet */
+ void *x_clock; /* a "clock" object */
+ float *x_buf; /* a Hanning window */
+ int x_phase; /* number of points since last output */
+ int x_period; /* requested period of output */
+ int x_realperiod; /* period rounded up to vecsize multiple */
+ int x_npoints; /* analysis window size in samples */
+ float x_result; /* result to output */
+ float x_sumbuf[MAXOVERLAP]; /* summing buffer */
+ float x_f;
+} t_sigenv;
+
+t_class *env_tilde_class;
+static void env_tilde_tick(t_sigenv *x);
+
+static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
+{
+ int npoints = fnpoints;
+ int period = fperiod;
+ t_sigenv *x;
+ float *buf;
+ int i;
+
+ if (npoints < 1) npoints = 1024;
+ if (period < 1) period = npoints/2;
+ if (period < npoints / MAXOVERLAP + 1)
+ period = npoints / MAXOVERLAP + 1;
+ if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
+ {
+ error("env: couldn't allocate buffer");
+ return (0);
+ }
+ x = (t_sigenv *)pd_new(env_tilde_class);
+ x->x_buf = buf;
+ x->x_npoints = npoints;
+ x->x_phase = 0;
+ x->x_period = period;
+ for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
+ for (i = 0; i < npoints; i++)
+ buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
+ for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
+ x->x_clock = clock_new(x, (t_method)env_tilde_tick);
+ x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *env_tilde_perform(t_int *w)
+{
+ t_sigenv *x = (t_sigenv *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ int count;
+ float *sump;
+ in += n;
+ for (count = x->x_phase, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ {
+ float *hp = x->x_buf + count;
+ float *fp = in;
+ float sum = *sump;
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ fp--;
+ sum += *hp++ * (*fp * *fp);
+ }
+ *sump = sum;
+ }
+ sump[0] = 0;
+ x->x_phase -= n;
+ if (x->x_phase < 0)
+ {
+ x->x_result = x->x_sumbuf[0];
+ for (count = x->x_realperiod, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ sump[0] = sump[1];
+ sump[0] = 0;
+ x->x_phase = x->x_realperiod - n;
+ clock_delay(x->x_clock, 0L);
+ }
+ return (w+4);
+}
+
+static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
+{
+ if (x->x_period % sp[0]->s_n) x->x_realperiod =
+ x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
+ else x->x_realperiod = x->x_period;
+ dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
+}
+
+static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
+{
+ outlet_float(x->x_outlet, powtodb(x->x_result));
+}
+
+static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
+{
+ clock_free(x->x_clock);
+ freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
+}
+
+
+void env_tilde_setup(void )
+{
+ env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
+ (t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
+ class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* --------------------- threshold~ ----------------------------- */
+
+static t_class *threshold_tilde_class;
+
+typedef struct _threshold_tilde
+{
+ t_object x_obj;
+ t_outlet *x_outlet1; /* bang out for high thresh */
+ t_outlet *x_outlet2; /* bang out for low thresh */
+ t_clock *x_clock; /* wakeup for message output */
+ float x_f; /* scalar inlet */
+ int x_state; /* 1 = high, 0 = low */
+ float x_hithresh; /* value of high threshold */
+ float x_lothresh; /* value of low threshold */
+ float x_deadwait; /* msec remaining in dead period */
+ float x_msecpertick; /* msec per DSP tick */
+ float x_hideadtime; /* hi dead time in msec */
+ float x_lodeadtime; /* lo dead time in msec */
+} t_threshold_tilde;
+
+static void threshold_tilde_tick(t_threshold_tilde *x);
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime);
+
+static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
+ t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
+{
+ t_threshold_tilde *x = (t_threshold_tilde *)
+ pd_new(threshold_tilde_class);
+ x->x_state = 0; /* low state */
+ x->x_deadwait = 0; /* no dead time */
+ x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_msecpertick = 0.;
+ x->x_f = 0;
+ threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
+ return (x);
+}
+
+ /* "set" message to specify thresholds and dead times */
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime)
+{
+ if (lothresh > hithresh)
+ lothresh = hithresh;
+ x->x_hithresh = hithresh;
+ x->x_hideadtime = hideadtime;
+ x->x_lothresh = lothresh;
+ x->x_lodeadtime = lodeadtime;
+}
+
+ /* number in inlet sets state -- note incompatible with JMAX which used
+ "int" message for this, impossible here because of auto signal conversion */
+static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
+{
+ x->x_state = (f != 0);
+ x->x_deadwait = 0;
+}
+
+static void threshold_tilde_tick(t_threshold_tilde *x)
+{
+ if (x->x_state)
+ outlet_bang(x->x_outlet1);
+ else outlet_bang(x->x_outlet2);
+}
+
+static t_int *threshold_tilde_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
+ int n = (t_int)(w[3]);
+ if (x->x_deadwait > 0)
+ x->x_deadwait -= x->x_msecpertick;
+ else if (x->x_state)
+ {
+ /* we're high; look for low sample */
+ for (; n--; in1++)
+ {
+ if (*in1 < x->x_lothresh)
+ {
+ clock_delay(x->x_clock, 0L);
+ x->x_state = 0;
+ x->x_deadwait = x->x_lodeadtime;
+ goto done;
+ }
+ }
+ }
+ else
+ {
+ /* we're low; look for high sample */
+ for (; n--; in1++)
+ {
+ if (*in1 >= x->x_hithresh)
+ {
+ clock_delay(x->x_clock, 0L);
+ x->x_state = 1;
+ x->x_deadwait = x->x_hideadtime;
+ goto done;
+ }
+ }
+ }
+done:
+ return (w+4);
+}
+
+void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
+{
+ x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
+ dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
+}
+
+static void threshold_tilde_ff(t_threshold_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void threshold_tilde_setup( void)
+{
+ threshold_tilde_class = class_new(gensym("threshold~"),
+ (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
+ sizeof(t_threshold_tilde), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
+ gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_ctl_setup(void)
+{
+ sig_tilde_setup();
+ line_tilde_setup();
+ vline_tilde_setup();
+ snapshot_tilde_setup();
+ vsnapshot_tilde_setup();
+ env_tilde_setup();
+ threshold_tilde_setup();
+}
+
+#endif
diff --git a/apps/plugins/pdbox/PDa/src/d_dac.c b/apps/plugins/pdbox/PDa/src/d_dac.c
new file mode 100644
index 0000000000..ce7c7127f0
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_dac.c
@@ -0,0 +1,368 @@
+/* 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. */
+
+/* The dac~ and adc~ routines.
+*/
+
+#include "m_pd.h"
+#include "s_stuff.h"
+
+/* ----------------------------- dac~ --------------------------- */
+static t_class *dac_class;
+
+typedef struct _dac
+{
+ t_object x_obj;
+ t_int x_n;
+ t_int *x_vec;
+ float x_f;
+} t_dac;
+
+static void *dac_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_dac *x = (t_dac *)pd_new(dac_class);
+ t_atom defarg[2], *ap;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0; i < argc; i++)
+ x->x_vec[i] = atom_getintarg(i, argc, argv);
+ for (i = 1; i < argc; i++)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static void dac_dsp(t_dac *x, t_signal **sp)
+{
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
+ {
+ int ch = *ip - 1;
+ if ((*sp2)->s_n != DEFDACBLKSIZE)
+ error("dac~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_outchannels())
+ dsp_add(plus_perform, 4, sys_soundout + DEFDACBLKSIZE*ch,
+ (*sp2)->s_vec, sys_soundout + DEFDACBLKSIZE*ch, DEFDACBLKSIZE);
+ }
+}
+
+static void dac_free(t_dac *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void dac_setup(void)
+{
+ dac_class = class_new(gensym("dac~"), (t_newmethod)dac_new,
+ (t_method)dac_free, sizeof(t_dac), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(dac_class, t_dac, x_f);
+ class_addmethod(dac_class, (t_method)dac_dsp, gensym("dsp"), A_CANT, 0);
+ class_sethelpsymbol(dac_class, gensym("adc~_dac~"));
+}
+
+/* ----------------------------- adc~ --------------------------- */
+static t_class *adc_class;
+
+typedef struct _adc
+{
+ t_object x_obj;
+ t_int x_n;
+ t_int *x_vec;
+} t_adc;
+
+static void *adc_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_adc *x = (t_adc *)pd_new(adc_class);
+ t_atom defarg[2], *ap;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0; i < argc; i++)
+ x->x_vec[i] = atom_getintarg(i, argc, argv);
+ for (i = 0; i < argc; i++)
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+t_int *copy_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--) *out++ = *in1++;
+ return (w+4);
+}
+
+t_int *copy_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+
+ for (; n; n -= 8, in1 += 8, out += 8)
+ {
+ float f0 = in1[0];
+ float f1 = in1[1];
+ float f2 = in1[2];
+ float f3 = in1[3];
+ float f4 = in1[4];
+ float f5 = in1[5];
+ float f6 = in1[6];
+ float f7 = in1[7];
+
+ out[0] = f0;
+ out[1] = f1;
+ out[2] = f2;
+ out[3] = f3;
+ out[4] = f4;
+ out[5] = f5;
+ out[6] = f6;
+ out[7] = f7;
+ }
+ return (w+4);
+}
+
+void dsp_add_copy(t_sample *in, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(copy_perform, 3, in, out, n);
+ else
+ dsp_add(copy_perf8, 3, in, out, n);
+}
+
+static void adc_dsp(t_adc *x, t_signal **sp)
+{
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
+ {
+ int ch = *ip - 1;
+ if ((*sp2)->s_n != DEFDACBLKSIZE)
+ error("adc~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_inchannels())
+ dsp_add_copy(sys_soundin + DEFDACBLKSIZE*ch,
+ (*sp2)->s_vec, DEFDACBLKSIZE);
+ else dsp_add_zero((*sp2)->s_vec, DEFDACBLKSIZE);
+ }
+}
+
+static void adc_free(t_adc *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void adc_setup(void)
+{
+ adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new,
+ (t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0);
+ class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0);
+ class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
+}
+
+void d_dac_setup(void)
+{
+ dac_setup();
+ adc_setup();
+}
+
+/* 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. */
+
+/* The dac~ and adc~ routines.
+*/
+
+#include "m_pd.h"
+#include "s_stuff.h"
+
+/* ----------------------------- dac~ --------------------------- */
+static t_class *dac_class;
+
+typedef struct _dac
+{
+ t_object x_obj;
+ t_int x_n;
+ t_int *x_vec;
+ float x_f;
+} t_dac;
+
+static void *dac_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_dac *x = (t_dac *)pd_new(dac_class);
+ t_atom defarg[2], *ap;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0; i < argc; i++)
+ x->x_vec[i] = atom_getintarg(i, argc, argv);
+ for (i = 1; i < argc; i++)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static void dac_dsp(t_dac *x, t_signal **sp)
+{
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
+ {
+ int ch = *ip - 1;
+ if ((*sp2)->s_n != DEFDACBLKSIZE)
+ error("dac~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_outchannels())
+ dsp_add(plus_perform, 4, sys_soundout + DEFDACBLKSIZE*ch,
+ (*sp2)->s_vec, sys_soundout + DEFDACBLKSIZE*ch, DEFDACBLKSIZE);
+ }
+}
+
+static void dac_free(t_dac *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void dac_setup(void)
+{
+ dac_class = class_new(gensym("dac~"), (t_newmethod)dac_new,
+ (t_method)dac_free, sizeof(t_dac), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(dac_class, t_dac, x_f);
+ class_addmethod(dac_class, (t_method)dac_dsp, gensym("dsp"), A_CANT, 0);
+ class_sethelpsymbol(dac_class, gensym("adc~_dac~"));
+}
+
+/* ----------------------------- adc~ --------------------------- */
+static t_class *adc_class;
+
+typedef struct _adc
+{
+ t_object x_obj;
+ t_int x_n;
+ t_int *x_vec;
+} t_adc;
+
+static void *adc_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_adc *x = (t_adc *)pd_new(adc_class);
+ t_atom defarg[2], *ap;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0; i < argc; i++)
+ x->x_vec[i] = atom_getintarg(i, argc, argv);
+ for (i = 0; i < argc; i++)
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+t_int *copy_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--) *out++ = *in1++;
+ return (w+4);
+}
+
+t_int *copy_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+
+ for (; n; n -= 8, in1 += 8, out += 8)
+ {
+ float f0 = in1[0];
+ float f1 = in1[1];
+ float f2 = in1[2];
+ float f3 = in1[3];
+ float f4 = in1[4];
+ float f5 = in1[5];
+ float f6 = in1[6];
+ float f7 = in1[7];
+
+ out[0] = f0;
+ out[1] = f1;
+ out[2] = f2;
+ out[3] = f3;
+ out[4] = f4;
+ out[5] = f5;
+ out[6] = f6;
+ out[7] = f7;
+ }
+ return (w+4);
+}
+
+void dsp_add_copy(t_sample *in, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(copy_perform, 3, in, out, n);
+ else
+ dsp_add(copy_perf8, 3, in, out, n);
+}
+
+static void adc_dsp(t_adc *x, t_signal **sp)
+{
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
+ {
+ int ch = *ip - 1;
+ if ((*sp2)->s_n != DEFDACBLKSIZE)
+ error("adc~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_inchannels())
+ dsp_add_copy(sys_soundin + DEFDACBLKSIZE*ch,
+ (*sp2)->s_vec, DEFDACBLKSIZE);
+ else dsp_add_zero((*sp2)->s_vec, DEFDACBLKSIZE);
+ }
+}
+
+static void adc_free(t_adc *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void adc_setup(void)
+{
+ adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new,
+ (t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0);
+ class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0);
+ class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
+}
+
+void d_dac_setup(void)
+{
+ dac_setup();
+ adc_setup();
+}
+
diff --git a/apps/plugins/pdbox/PDa/src/d_delay.c b/apps/plugins/pdbox/PDa/src/d_delay.c
new file mode 100644
index 0000000000..37fb90ea5b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_delay.c
@@ -0,0 +1,638 @@
+/* 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;
+ float *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 */
+ 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)
+{
+ /*
+ 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
+ if (x->x_rsortno != ugen_getsortno())
+ {
+ x->x_vecsize = vecsize;
+ x->x_rsortno = ugen_getsortno();
+ }
+ else if (vecsize != x->x_vecsize)
+ pd_error(x, "delread/delwrite/vd vector size mismatch");
+#endif
+}
+
+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;
+ nsamps = msec * sys_getsr() * (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 =
+ (float *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
+ 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_float *in = (t_float *)(w[1]);
+ t_delwritectl *c = (t_delwritectl *)(w[2]);
+ int n = (int)(w[3]);
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ while (n--)
+ {
+ float 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;
+ }
+ }
+ 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(float));
+}
+
+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_float *out = (t_float *)(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;
+ float *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 */
+ 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_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(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;
+ float limit = nsamps - n - 1;
+ float fn = n-1;
+ float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
+ float zerodel = x->x_zerodel;
+ while (n--)
+ {
+ float delsamps = x->x_sr * *in++ - zerodel, frac;
+ int idelsamps;
+ float 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 - (float)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();
+}
+
+/* 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;
+ float *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 */
+ 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)
+{
+ /*
+ 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
+ if (x->x_rsortno != ugen_getsortno())
+ {
+ x->x_vecsize = vecsize;
+ x->x_rsortno = ugen_getsortno();
+ }
+ else if (vecsize != x->x_vecsize)
+ pd_error(x, "delread/delwrite/vd vector size mismatch");
+#endif
+}
+
+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;
+ nsamps = msec * sys_getsr() * (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 =
+ (float *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
+ 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_float *in = (t_float *)(w[1]);
+ t_delwritectl *c = (t_delwritectl *)(w[2]);
+ int n = (int)(w[3]);
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ while (n--)
+ {
+ float 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;
+ }
+ }
+ 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(float));
+}
+
+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_float *out = (t_float *)(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;
+ float *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 */
+ 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_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(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;
+ float limit = nsamps - n - 1;
+ float fn = n-1;
+ float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
+ float zerodel = x->x_zerodel;
+ while (n--)
+ {
+ float delsamps = x->x_sr * *in++ - zerodel, frac;
+ int idelsamps;
+ float 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 - (float)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/apps/plugins/pdbox/PDa/src/d_fft.c b/apps/plugins/pdbox/PDa/src/d_fft.c
new file mode 100644
index 0000000000..9916fdcb88
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_fft.c
@@ -0,0 +1,688 @@
+/* Copyright (c) 1997-1999 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. */
+
+#include "m_pd.h"
+
+/* ------------------------ fft~ and ifft~ -------------------------------- */
+static t_class *sigfft_class, *sigifft_class;
+
+typedef struct fft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigfft;
+
+static void *sigfft_new(void)
+{
+ t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static void *sigifft_new(void)
+{
+ t_sigfft *x = (t_sigfft *)pd_new(sigifft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigfft_swap(t_int *w)
+{
+ t_sample *in1 = (t_sample *)(w[1]);
+ t_sample *in2 = (t_sample *)(w[2]);
+ int n = w[3];
+ for (;n--; in1++, in2++)
+ {
+ float f = *in1;
+ *in1 = *in2;
+ *in2 = f;
+ }
+ return (w+4);
+}
+
+static t_int *sigfft_perform(t_int *w)
+{
+ t_sample *in1 = (t_sample *)(w[1]);
+ t_sample *in2 = (t_sample *)(w[2]);
+ int n = w[3];
+ mayer_fft(n, in1, in2);
+ return (w+4);
+}
+
+static t_int *sigifft_perform(t_int *w)
+{
+ t_sample *in1 = (t_sample *)(w[1]);
+ t_sample *in2 = (t_sample *)(w[2]);
+ int n = w[3];
+ mayer_ifft(n, in1, in2);
+ return (w+4);
+}
+
+static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w))
+{
+ int n = sp[0]->s_n;
+ t_sample *in1 = sp[0]->s_vec;
+ t_sample *in2 = sp[1]->s_vec;
+ t_sample *out1 = sp[2]->s_vec;
+ t_sample *out2 = sp[3]->s_vec;
+ if (out1 == in2 && out2 == in1)
+ dsp_add(sigfft_swap, 3, out1, out2, n);
+ else if (out1 == in2)
+ {
+ dsp_add(copy_perform, 3, in2, out2, n);
+ dsp_add(copy_perform, 3, in1, out1, n);
+ }
+ else
+ {
+ if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
+ if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
+ }
+ dsp_add(f, 3, sp[2]->s_vec, sp[3]->s_vec, n);
+}
+
+static void sigfft_dsp(t_sigfft *x, t_signal **sp)
+{
+ sigfft_dspx(x, sp, sigfft_perform);
+}
+
+static void sigifft_dsp(t_sigfft *x, t_signal **sp)
+{
+ sigfft_dspx(x, sp, sigifft_perform);
+}
+
+static void sigfft_setup(void)
+{
+ sigfft_class = class_new(gensym("fft~"), sigfft_new, 0,
+ sizeof(t_sigfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, x_f);
+ class_addmethod(sigfft_class, (t_method)sigfft_dsp, gensym("dsp"), 0);
+
+ sigifft_class = class_new(gensym("ifft~"), sigifft_new, 0,
+ sizeof(t_sigfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, x_f);
+ class_addmethod(sigifft_class, (t_method)sigifft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigifft_class, gensym("fft~"));
+}
+
+/* ----------------------- rfft~ -------------------------------- */
+
+static t_class *sigrfft_class;
+
+typedef struct rfft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrfft;
+
+static void *sigrfft_new(void)
+{
+ t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrfft_flip(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = w[3];
+ while (n--) *(--out) = *in++;
+ *(--out) = 0; /* to hell with it */
+ return (w+4);
+}
+
+static t_int *sigrfft_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ int n = w[2];
+ mayer_realfft(n, in);
+ return (w+3);
+}
+
+static void sigrfft_dsp(t_sigrfft *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ t_sample *in1 = sp[0]->s_vec;
+ t_sample *out1 = sp[1]->s_vec;
+ t_sample *out2 = sp[2]->s_vec;
+ if (n < 4)
+ {
+ error("fft: minimum 4 points");
+ return;
+ }
+ if (in1 == out2) /* this probably never happens */
+ {
+ dsp_add(sigrfft_perform, 2, out2, n);
+ dsp_add(copy_perform, 3, out2, out1, n2);
+ dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1);
+ }
+ else
+ {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n);
+ dsp_add(sigrfft_perform, 2, out1, n);
+ dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
+ }
+ dsp_add_zero(out1 + n2, n2);
+ dsp_add_zero(out2 + n2, n2);
+}
+
+static void sigrfft_setup(void)
+{
+ sigrfft_class = class_new(gensym("rfft~"), sigrfft_new, 0,
+ sizeof(t_sigrfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, x_f);
+ class_addmethod(sigrfft_class, (t_method)sigrfft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigrfft_class, gensym("fft~"));
+}
+
+/* ----------------------- rifft~ -------------------------------- */
+
+static t_class *sigrifft_class;
+
+typedef struct rifft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrifft;
+
+static void *sigrifft_new(void)
+{
+ t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrifft_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ int n = w[2];
+ mayer_realifft(n, in);
+ return (w+3);
+}
+
+static void sigrifft_dsp(t_sigrifft *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ t_sample *in1 = sp[0]->s_vec;
+ t_sample *in2 = sp[1]->s_vec;
+ t_sample *out1 = sp[2]->s_vec;
+ if (n < 4)
+ {
+ error("fft: minimum 4 points");
+ return;
+ }
+ if (in2 == out1)
+ {
+ dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1));
+ dsp_add(copy_perform, 3, in1, out1, n2);
+ }
+ else
+ {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2);
+ dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
+ }
+ dsp_add(sigrifft_perform, 2, out1, n);
+}
+
+static void sigrifft_setup(void)
+{
+ sigrifft_class = class_new(gensym("rifft~"), sigrifft_new, 0,
+ sizeof(t_sigrifft), 0, 0);
+ CLASS_MAINSIGNALIN(sigrifft_class, t_sigrifft, x_f);
+ class_addmethod(sigrifft_class, (t_method)sigrifft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigrifft_class, gensym("fft~"));
+}
+
+/* ----------------------- framp~ -------------------------------- */
+
+#if 0
+static t_class *sigframp_class;
+
+typedef struct framp
+{
+ t_object x_obj;
+ float x_f;
+} t_sigframp;
+
+static void *sigframp_new(void)
+{
+ t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
+ 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"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigframp_perform(t_int *w)
+{
+ float *inreal = (t_float *)(w[1]);
+ float *inimag = (t_float *)(w[2]);
+ float *outfreq = (t_float *)(w[3]);
+ float *outamp = (t_float *)(w[4]);
+ float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
+ float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
+ int n = w[5];
+ int m = n + 1;
+ float fbin = 1, oneovern2 = 1.f/((float)n * (float)n);
+
+ inreal += 2;
+ inimag += 2;
+ *outamp++ = *outfreq++ = 0;
+ n -= 2;
+ while (n--)
+ {
+ float re, im, pow, freq;
+ lastreal = currentreal;
+ currentreal = nextreal;
+ nextreal = *inreal++;
+ lastimag = currentimag;
+ currentimag = nextimag;
+ nextimag = *inimag++;
+ re = currentreal - 0.5f * (lastreal + nextreal);
+ im = currentimag - 0.5f * (lastimag + nextimag);
+ pow = re * re + im * im;
+ if (pow > 1e-19)
+ {
+ float detune = ((lastreal - nextreal) * re +
+ (lastimag - nextimag) * im) / (2.0f * pow);
+ if (detune > 2 || detune < -2) freq = pow = 0;
+ else freq = fbin + detune;
+ }
+ else freq = pow = 0;
+ *outfreq++ = freq;
+ *outamp++ = oneovern2 * pow;
+ fbin += 1.0f;
+ }
+ while (m--) *outamp++ = *outfreq++ = 0;
+ return (w+6);
+}
+
+t_int *sigsqrt_perform(t_int *w);
+
+static void sigframp_dsp(t_sigframp *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ if (n < 4)
+ {
+ error("framp: minimum 4 points");
+ return;
+ }
+ dsp_add(sigframp_perform, 5, sp[0]->s_vec, sp[1]->s_vec,
+ sp[2]->s_vec, sp[3]->s_vec, n2);
+ dsp_add(sigsqrt_perform, 3, sp[3]->s_vec, sp[3]->s_vec, n2);
+}
+
+static void sigframp_setup(void)
+{
+ sigframp_class = class_new(gensym("framp~"), sigframp_new, 0,
+ sizeof(t_sigframp), 0, 0);
+ CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, x_f);
+ class_addmethod(sigframp_class, (t_method)sigframp_dsp, gensym("dsp"), 0);
+}
+#endif
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_fft_setup(void)
+{
+ sigfft_setup();
+ sigrfft_setup();
+ sigrifft_setup();
+// sigframp_setup();
+}
+/* Copyright (c) 1997-1999 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. */
+
+#include "m_pd.h"
+
+/* ------------------------ fft~ and ifft~ -------------------------------- */
+static t_class *sigfft_class, *sigifft_class;
+
+typedef struct fft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigfft;
+
+static void *sigfft_new(void)
+{
+ t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static void *sigifft_new(void)
+{
+ t_sigfft *x = (t_sigfft *)pd_new(sigifft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigfft_swap(t_int *w)
+{
+ t_sample *in1 = (t_sample *)(w[1]);
+ t_sample *in2 = (t_sample *)(w[2]);
+ int n = w[3];
+ for (;n--; in1++, in2++)
+ {
+ float f = *in1;
+ *in1 = *in2;
+ *in2 = f;
+ }
+ return (w+4);
+}
+
+static t_int *sigfft_perform(t_int *w)
+{
+ t_sample *in1 = (t_sample *)(w[1]);
+ t_sample *in2 = (t_sample *)(w[2]);
+ int n = w[3];
+ mayer_fft(n, in1, in2);
+ return (w+4);
+}
+
+static t_int *sigifft_perform(t_int *w)
+{
+ t_sample *in1 = (t_sample *)(w[1]);
+ t_sample *in2 = (t_sample *)(w[2]);
+ int n = w[3];
+ mayer_ifft(n, in1, in2);
+ return (w+4);
+}
+
+static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w))
+{
+ int n = sp[0]->s_n;
+ t_sample *in1 = sp[0]->s_vec;
+ t_sample *in2 = sp[1]->s_vec;
+ t_sample *out1 = sp[2]->s_vec;
+ t_sample *out2 = sp[3]->s_vec;
+ if (out1 == in2 && out2 == in1)
+ dsp_add(sigfft_swap, 3, out1, out2, n);
+ else if (out1 == in2)
+ {
+ dsp_add(copy_perform, 3, in2, out2, n);
+ dsp_add(copy_perform, 3, in1, out1, n);
+ }
+ else
+ {
+ if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
+ if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
+ }
+ dsp_add(f, 3, sp[2]->s_vec, sp[3]->s_vec, n);
+}
+
+static void sigfft_dsp(t_sigfft *x, t_signal **sp)
+{
+ sigfft_dspx(x, sp, sigfft_perform);
+}
+
+static void sigifft_dsp(t_sigfft *x, t_signal **sp)
+{
+ sigfft_dspx(x, sp, sigifft_perform);
+}
+
+static void sigfft_setup(void)
+{
+ sigfft_class = class_new(gensym("fft~"), sigfft_new, 0,
+ sizeof(t_sigfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, x_f);
+ class_addmethod(sigfft_class, (t_method)sigfft_dsp, gensym("dsp"), 0);
+
+ sigifft_class = class_new(gensym("ifft~"), sigifft_new, 0,
+ sizeof(t_sigfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, x_f);
+ class_addmethod(sigifft_class, (t_method)sigifft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigifft_class, gensym("fft~"));
+}
+
+/* ----------------------- rfft~ -------------------------------- */
+
+static t_class *sigrfft_class;
+
+typedef struct rfft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrfft;
+
+static void *sigrfft_new(void)
+{
+ t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrfft_flip(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = w[3];
+ while (n--) *(--out) = *in++;
+ *(--out) = 0; /* to hell with it */
+ return (w+4);
+}
+
+static t_int *sigrfft_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ int n = w[2];
+ mayer_realfft(n, in);
+ return (w+3);
+}
+
+static void sigrfft_dsp(t_sigrfft *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ t_sample *in1 = sp[0]->s_vec;
+ t_sample *out1 = sp[1]->s_vec;
+ t_sample *out2 = sp[2]->s_vec;
+ if (n < 4)
+ {
+ error("fft: minimum 4 points");
+ return;
+ }
+ if (in1 == out2) /* this probably never happens */
+ {
+ dsp_add(sigrfft_perform, 2, out2, n);
+ dsp_add(copy_perform, 3, out2, out1, n2);
+ dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1);
+ }
+ else
+ {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n);
+ dsp_add(sigrfft_perform, 2, out1, n);
+ dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
+ }
+ dsp_add_zero(out1 + n2, n2);
+ dsp_add_zero(out2 + n2, n2);
+}
+
+static void sigrfft_setup(void)
+{
+ sigrfft_class = class_new(gensym("rfft~"), sigrfft_new, 0,
+ sizeof(t_sigrfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, x_f);
+ class_addmethod(sigrfft_class, (t_method)sigrfft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigrfft_class, gensym("fft~"));
+}
+
+/* ----------------------- rifft~ -------------------------------- */
+
+static t_class *sigrifft_class;
+
+typedef struct rifft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrifft;
+
+static void *sigrifft_new(void)
+{
+ t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrifft_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ int n = w[2];
+ mayer_realifft(n, in);
+ return (w+3);
+}
+
+static void sigrifft_dsp(t_sigrifft *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ t_sample *in1 = sp[0]->s_vec;
+ t_sample *in2 = sp[1]->s_vec;
+ t_sample *out1 = sp[2]->s_vec;
+ if (n < 4)
+ {
+ error("fft: minimum 4 points");
+ return;
+ }
+ if (in2 == out1)
+ {
+ dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1));
+ dsp_add(copy_perform, 3, in1, out1, n2);
+ }
+ else
+ {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2);
+ dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
+ }
+ dsp_add(sigrifft_perform, 2, out1, n);
+}
+
+static void sigrifft_setup(void)
+{
+ sigrifft_class = class_new(gensym("rifft~"), sigrifft_new, 0,
+ sizeof(t_sigrifft), 0, 0);
+ CLASS_MAINSIGNALIN(sigrifft_class, t_sigrifft, x_f);
+ class_addmethod(sigrifft_class, (t_method)sigrifft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigrifft_class, gensym("fft~"));
+}
+
+/* ----------------------- framp~ -------------------------------- */
+
+#if 0
+static t_class *sigframp_class;
+
+typedef struct framp
+{
+ t_object x_obj;
+ float x_f;
+} t_sigframp;
+
+static void *sigframp_new(void)
+{
+ t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
+ 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"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigframp_perform(t_int *w)
+{
+ float *inreal = (t_float *)(w[1]);
+ float *inimag = (t_float *)(w[2]);
+ float *outfreq = (t_float *)(w[3]);
+ float *outamp = (t_float *)(w[4]);
+ float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
+ float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
+ int n = w[5];
+ int m = n + 1;
+ float fbin = 1, oneovern2 = 1.f/((float)n * (float)n);
+
+ inreal += 2;
+ inimag += 2;
+ *outamp++ = *outfreq++ = 0;
+ n -= 2;
+ while (n--)
+ {
+ float re, im, pow, freq;
+ lastreal = currentreal;
+ currentreal = nextreal;
+ nextreal = *inreal++;
+ lastimag = currentimag;
+ currentimag = nextimag;
+ nextimag = *inimag++;
+ re = currentreal - 0.5f * (lastreal + nextreal);
+ im = currentimag - 0.5f * (lastimag + nextimag);
+ pow = re * re + im * im;
+ if (pow > 1e-19)
+ {
+ float detune = ((lastreal - nextreal) * re +
+ (lastimag - nextimag) * im) / (2.0f * pow);
+ if (detune > 2 || detune < -2) freq = pow = 0;
+ else freq = fbin + detune;
+ }
+ else freq = pow = 0;
+ *outfreq++ = freq;
+ *outamp++ = oneovern2 * pow;
+ fbin += 1.0f;
+ }
+ while (m--) *outamp++ = *outfreq++ = 0;
+ return (w+6);
+}
+
+t_int *sigsqrt_perform(t_int *w);
+
+static void sigframp_dsp(t_sigframp *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ if (n < 4)
+ {
+ error("framp: minimum 4 points");
+ return;
+ }
+ dsp_add(sigframp_perform, 5, sp[0]->s_vec, sp[1]->s_vec,
+ sp[2]->s_vec, sp[3]->s_vec, n2);
+ dsp_add(sigsqrt_perform, 3, sp[3]->s_vec, sp[3]->s_vec, n2);
+}
+
+static void sigframp_setup(void)
+{
+ sigframp_class = class_new(gensym("framp~"), sigframp_new, 0,
+ sizeof(t_sigframp), 0, 0);
+ CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, x_f);
+ class_addmethod(sigframp_class, (t_method)sigframp_dsp, gensym("dsp"), 0);
+}
+#endif
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_fft_setup(void)
+{
+ sigfft_setup();
+ sigrfft_setup();
+ sigrifft_setup();
+// sigframp_setup();
+}
diff --git a/apps/plugins/pdbox/PDa/src/d_fftroutine.c b/apps/plugins/pdbox/PDa/src/d_fftroutine.c
new file mode 100644
index 0000000000..dde24fa358
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_fftroutine.c
@@ -0,0 +1,2002 @@
+/*****************************************************************************/
+/* */
+/* Fast Fourier Transform */
+/* Network Abstraction, Definitions */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - To incorporate link list of different sized networks */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* added debug option 5/91 brown@nadia */
+/* change sign at AAA */
+/* */
+/* Fast Fourier Transform */
+/* FFT Network Interaction and Support Modules */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - Generalized to one procedure call with typed I/O */
+/* */
+/*****************************************************************************/
+
+/* Overview:
+
+ My realization of the FFT involves a representation of a network of
+ "butterfly" elements that takes a set of 'N' sound samples as input and
+ computes the discrete Fourier transform. This network consists of a
+ series of stages (log2 N), each stage consisting of N/2 parallel butterfly
+ elements. Consecutive stages are connected by specific, predetermined flow
+ paths, (see Oppenheim, Schafer for details) and each butterfly element has
+ an associated multiplicative coefficient.
+
+ FFT NETWORK:
+ -----------
+ ____ _ ____ _ ____ _ ____ _ ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg1| | | |W^r1| | | |reg1| | | |W^r1| | | |reg1|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg2| | | |W^r2| | | |reg2| | | |W^r2| | | |reg2|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg | | | |W^r | | | |reg | | | |W^r | | | |reg |
+ | N/2| | | | N/2| | | | N/2| | | | N/2| | | | N/2| .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|--o
+
+ ^ ^ ^ ^
+ Initial | Bttrfly | Rd/Wrt | Bttrfly | Rd/Wrt
+ Buffer | | Register | | Register
+ |____________|____________|____________|
+ |
+ |
+ Interconnect
+ Paths
+
+ The use of "in-place" computation permits one to use only one set of
+ registers realized by an array of complex number structures. To describe
+ the coefficients for each butterfly I am using a two dimensional array
+ (stage, butterfly) of complex numbers. The predetermined stage connections
+ will be described in a two dimensional array of indicies. These indicies
+ will be used to determine the order of reading at each stage of the
+ computation.
+*/
+
+
+/*****************************************************************************/
+/* INCLUDE FILES */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+ /* the following is needed only to declare pd_fft() as exportable in MSW */
+#include "m_pd.h"
+
+/* some basic definitions */
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define SAMPLE float /* data type used in calculation */
+
+#define SHORT_SIZE sizeof(short)
+#define INT_SIZE sizeof(int)
+#define FLOAT_SIZE sizeof(float)
+#define SAMPLE_SIZE sizeof(SAMPLE)
+#define PNTR_SIZE sizeof(char *)
+
+#define PI 3.1415927
+#define TWO_PI 6.2831854
+
+/* type definitions for I/O buffers */
+#define REAL 0 /* real only */
+#define IMAG 2 /* imaginary only */
+#define RECT 8 /* real and imaginary */
+#define MAG 16 /* magnitude only */
+#define PHASE 32 /* phase only */
+#define POLAR 64 /* magnitude and phase*/
+
+/* scale definitions for I/O buffers */
+#define LINEAR 0
+#define DB 1 /* 20log10 */
+
+/* transform direction definition */
+#define FORWARD 1 /* Forward FFT */
+#define INVERSE 2 /* Inverse FFT */
+
+/* window type definitions */
+#define HANNING 1
+#define RECTANGULAR 0
+
+
+
+/* network structure definition */
+
+typedef struct Tfft_net {
+ int n;
+ int stages;
+ int bps;
+ int direction;
+ int window_type;
+ int *load_index;
+ SAMPLE *window, *inv_window;
+ SAMPLE *regr;
+ SAMPLE *regi;
+ SAMPLE **indexpr;
+ SAMPLE **indexpi;
+ SAMPLE **indexqr;
+ SAMPLE **indexqi;
+ SAMPLE *coeffr, *inv_coeffr;
+ SAMPLE *coeffi, *inv_coeffi;
+ struct Tfft_net *next;
+} FFT_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);
+
+
+/*****************************************************************************/
+/* GLOBAL DECLARATIONS */
+/*****************************************************************************/
+
+static FFT_NET *firstnet;
+
+/* prototypes */
+
+void net_alloc(FFT_NET *fft_net);
+void net_dealloc(FFT_NET *fft_net);
+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,
+ 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,
+ int buf_scale, int debug);
+void build_fft_network(FFT_NET *fft_net, int n, int window_type);
+
+/*****************************************************************************/
+/* GENERALIZED FAST FOURIER TRANSFORM MODULE */
+/*****************************************************************************/
+
+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)
+
+/* modifies: result_buf
+ effects: Computes npnt FFT specified by form, scale, and dir parameters.
+ Source samples (single precision float) are taken from soure_buf and
+ the transfrmd representation is stored in result_buf (single precision
+ float). The parameters are defined as follows:
+
+ trnsfrm_dir = FORWARD | INVERSE
+ npnt = 2^k for some any positive integer k
+ window = HANNING | RECTANGULAR
+ (RECT = real and imag parts, POLAR = magnitude and phase)
+ source_form = REAL | IMAG | RECT | POLAR
+ result_form = REAL | IMAG | RECT | MAG | PHASE | POLAR
+ xxxxxx_scale= LINEAR | DB ( 20log10 |mag| )
+
+ The input/output buffers are stored in a form appropriate to the type.
+ For example: REAL => {real, real, real ...},
+ MAG => {mag, mag, mag, ... },
+ RECT => {real, imag, real, imag, ... },
+ POLAR => {mag, phase, mag, phase, ... }.
+
+ To look at the magnitude (in db) of a 1024 point FFT of a real time
+ signal we have:
+
+ fft(FORWARD, 1024, RECTANGULAR, input, REAL, LINEAR, output, MAG, DB)
+
+ All possible input and output combinations are possible given the
+ choice of type and scale parameters.
+*/
+
+{
+ FFT_NET *thisnet = (FFT_NET *)0;
+ FFT_NET *lastnet = (FFT_NET *)0;
+
+ /* A linked list of fft networks of different sizes is maintained to
+ avoid building with every call. The network is built on the first
+ call but reused for subsequent calls requesting the same size
+ transformation.
+ */
+
+ thisnet=firstnet;
+ while (thisnet) {
+ if (!(thisnet->n == npnt) || !(thisnet->window_type == window)) {
+ /* current net doesn't match size or window type */
+ lastnet=thisnet;
+ thisnet=thisnet->next;
+ continue; /* keep looking */
+ }
+
+ else { /* network matches desired size */
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet); /* do transformation */
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+ }
+ }
+
+ /* none of existing networks match required size*/
+
+ if (lastnet) { /* add new network to end of list */
+ thisnet = (FFT_NET *)malloc(sizeof(FFT_NET)); /* allocate */
+ thisnet->next = 0;
+ lastnet->next = thisnet; /* add to end of list */
+ }
+ else { /* first network to be created */
+ thisnet=firstnet=(FFT_NET *)malloc(sizeof(FFT_NET)); /* alloc. */
+ thisnet->next = 0;
+ }
+
+ /* build new network and compute transformation */
+ build_fft_network(thisnet, npnt, window);
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet);
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+}
+
+void fft_clear(void)
+
+/* effects: Deallocates all preserved FFT networks. Should be used when
+ finished with all computations.
+*/
+
+{
+ FFT_NET *thisnet, *nextnet;
+
+ if (firstnet) {
+ thisnet=firstnet;
+ do {
+ nextnet = thisnet->next;
+ net_dealloc(thisnet);
+ free((char *)thisnet);
+ } while (thisnet = nextnet);
+ }
+}
+
+
+/*****************************************************************************/
+/* NETWORK CONSTRUCTION */
+/*****************************************************************************/
+
+void build_fft_network(FFT_NET *fft_net, int n, int window_type)
+
+
+/* modifies:fft_net
+ effects: Constructs the fft network as described in fft.h. Butterfly
+ coefficients, read/write indicies, bit reversed load indicies,
+ and array allocations are computed.
+*/
+
+{
+ int cntr, i, j, s;
+ int stages, bps;
+ int **p, **q, *pp, *qp;
+ SAMPLE two_pi_div_n = TWO_PI / n;
+
+
+ /* network definition */
+ fft_net->n = n;
+ fft_net->bps = bps = n/2;
+ for (i = 0, j = n; j > 1; j >>= 1, i++);
+ fft_net->stages = stages = i;
+ fft_net->direction = FORWARD;
+ fft_net->window_type = window_type;
+ fft_net->next = (FFT_NET *)0;
+
+ /* allocate registers, index, coefficient arrays */
+ net_alloc(fft_net);
+
+
+ /* create appropriate windows */
+ if (window_type==HANNING) {
+ create_hanning(fft_net->window, n, 1.);
+ create_hanning(fft_net->inv_window, n, 1./n);
+ }
+ else {
+ create_rectangular(fft_net->window, n, 1.);
+ create_rectangular(fft_net->inv_window, n, 1./n);
+ }
+
+
+ /* calculate butterfly coefficients */ {
+
+ int num_diff_coeffs, power_inc, power;
+ SAMPLE *coeffpr = fft_net->coeffr;
+ SAMPLE *coeffpi = fft_net->coeffi;
+ SAMPLE *inv_coeffpr = fft_net->inv_coeffr;
+ SAMPLE *inv_coeffpi = fft_net->inv_coeffi;
+
+ /* stage one coeffs are 1 + 0j */
+ for (i = 0; i < bps; i++) {
+ *coeffpr = *inv_coeffpr = 1.;
+ *coeffpi = *inv_coeffpi = 0.;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+
+ /* stage 2 to last stage coeffs need calculation */
+ /* (1<<r <=> 2^r */
+ for (s = 2; s <= stages; s++) {
+
+ num_diff_coeffs = n / (1 << (stages - s + 1));
+ power_inc = 1 << (stages -s);
+ cntr = 0;
+
+ for (i = bps/num_diff_coeffs; i > 0; i--) {
+
+ power = 0;
+
+ for (j = num_diff_coeffs; j > 0; j--) {
+ *coeffpr = cos(two_pi_div_n*power);
+ *inv_coeffpr = cos(two_pi_div_n*power);
+/* AAA change these signs */ *coeffpi = -sin(two_pi_div_n*power);
+/* change back */ *inv_coeffpi = sin(two_pi_div_n*power);
+ power += power_inc;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+ }
+ }
+ }
+
+ /* calculate network indicies: stage exchange indicies are
+ calculated and then used as offset values from the base
+ register locations. The final addresses are then stored in
+ fft_net.
+ */ {
+
+ int index, inc;
+ SAMPLE **indexpr = fft_net->indexpr;
+ SAMPLE **indexpi = fft_net->indexpi;
+ SAMPLE **indexqr = fft_net->indexqr;
+ SAMPLE **indexqi = fft_net->indexqi;
+ SAMPLE *regr = fft_net->regr;
+ SAMPLE *regi = fft_net->regi;
+
+
+ /* allocate temporary 2d stage exchange index, 1d temp
+ load index */
+ p = (int **)malloc(stages * PNTR_SIZE);
+ q = (int **)malloc(stages * PNTR_SIZE);
+
+ for (s = 0; s < stages; s++) {
+ p[s] = (int *)malloc(bps * INT_SIZE);
+ q[s] = (int *)malloc(bps * INT_SIZE);
+ }
+
+ /* calculate stage exchange indicies: */
+ for (s = 0; s < stages; s++) {
+ pp = p[s];
+ qp = q[s];
+ inc = 1 << s;
+ cntr = 1 << (stages-s-1);
+ i = j = index = 0;
+
+ do {
+ do {
+ qp[i] = index + inc;
+ pp[i++] = index++;
+ } while (++j < inc);
+ index = qp[i-1] + 1;
+ j = 0;
+ } while (--cntr);
+ }
+
+ /* compute actual address values using indicies as offsets */
+ for (s = 0; s < stages; s++) {
+ for (i = 0; i < bps; i++) {
+ *indexpr++ = regr + p[s][i];
+ *indexpi++ = regi + p[s][i];
+ *indexqr++ = regr + q[s][i];
+ *indexqi++ = regi + q[s][i];
+ }
+ }
+ }
+
+
+ /* calculate load indicies (bit reverse ordering) */
+ /* bit reverse ordering achieved by passing normal
+ order indicies backwards through the network */
+
+ /* init to normal order indicies */ {
+ int *load_index,*load_indexp;
+ int *temp_indexp, *temp_index;
+ temp_index=temp_indexp=(int *)malloc(n * INT_SIZE);
+
+ i = 0; j = n;
+ load_index = load_indexp = fft_net->load_index;
+
+ while (j--)
+ *load_indexp++ = i++;
+
+ /* pass indicies backwards through net */
+ for (s = stages - 1; s > 0; s--) {
+ pp = p[s];
+ qp = q[s];
+
+ for (i = 0; i < bps; i++) {
+ temp_index[pp[i]]=load_index[2*i];
+ temp_index[qp[i]]=load_index[2*i+1];
+ }
+ j = n;
+ load_indexp = load_index;
+ temp_indexp = temp_index;
+ while (j--)
+ *load_indexp++ = *temp_indexp++;
+ }
+
+ /* free all temporary arrays */
+ free((char *)temp_index);
+ for (s = 0; s < stages; s++) {
+ free((char *)p[s]);free((char *)q[s]);
+ }
+ free((char *)p);free((char *)q);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* REGISTER LOAD AND STORE */
+/*****************************************************************************/
+
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir)
+
+/* effects: Multiplies the input buffer with the appropriate window and
+ stores the resulting values in the initial registers of the
+ network. Input buffer must contain values appropriate to form.
+ For RECT, the buffer contains real num. followed by imag num,
+ and for POLAR, it contains magnitude followed by phase. Pure
+ inputs are listed normally. Both LINEAR and DB scales are
+ interpreted.
+*/
+
+{
+ int *load_index = fft_net->load_index;
+ SAMPLE *window;
+ int index, i = 0, n = fft_net->n;
+
+ if (trnsfrm_dir==FORWARD) window = fft_net->window;
+ else if (trnsfrm_dir==INVERSE) window = fft_net->inv_window;
+ else {
+ fprintf(stderr, "load_registers:illegal transform direction\n");
+ exit(0);
+ }
+ fft_net->direction = trnsfrm_dir;
+
+ switch(buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index] * window[index];
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0;
+ fft_net->regi[i]=(SAMPLE)buf[index] * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index*2] * window[index];
+ fft_net->regi[i]=(SAMPLE)buf[index*2+1] * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* magnitude followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(buf[index*2] * cos(buf[index*2+1]))
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)(buf[index*2] * sin(buf[index*2+1]))
+ * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* log pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index]; /* window scaling after linearization */
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* log pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0.;
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* log REAL and log IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2])
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2+1])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* log mag followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * cos(buf[index*2+1])) * window[index];
+ fft_net->regi[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * sin(buf[index*2+1])) * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug)
+
+/* modifies: buf
+ effects: Writes the final contents of the network registers into buf in
+ either linear or db scale, polar or rectangular form. If any of
+ the pure forms(REAL, IMAG, MAG, or PHASE) are used then only the
+ corresponding part of the registers is stored in buf.
+*/
+
+{
+ int i;
+ SAMPLE real, imag, mag, phase;
+ int n;
+
+ i = 0;
+ n = fft_net->n;
+
+ switch (buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real > .00001)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0){ *buf++ = PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag > 0\n");}
+ else if (imag < 0){ *buf++ = -PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag < 0\n");}
+ else { *buf++ = 0;
+ if(debug) fprintf(stderr,"real=0 and imag=0\n");}
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ if (real) /* a hack to avoid div by zero */
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* real only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* imag only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* real and imag */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* COMPUTE TRANSFORMATION */
+/*****************************************************************************/
+
+void compute_fft(FFT_NET *fft_net)
+
+
+/* modifies: fft_net
+ effects: Passes the values (already loaded) in the registers through
+ the network, multiplying with appropriate coefficients at each
+ stage. The fft result will be in the registers at the end of
+ the computation. The direction of the transformation is indicated
+ by the network flag 'direction'. The form of the computation is:
+
+ X(pn) = X(p) + C*X(q)
+ X(qn) = X(p) - C*X(q)
+
+ where X(pn,qn) represents the output of the registers at each stage.
+ The calculations are actually done in place. Register pointers are
+ used to speed up the calculations.
+
+ Register and coefficient addresses involved in the calculations
+ are stored sequentially and are accessed as such. fft_net->indexp,
+ indexq contain pointers to the relevant addresses, and fft_net->coeffs,
+ inv_coeffs points to the appropriate coefficients at each stage of the
+ computation.
+*/
+
+{
+ SAMPLE **xpr, **xpi, **xqr, **xqi, *cr, *ci;
+ int i;
+ SAMPLE tpr, tpi, tqr, tqi;
+ int bps = fft_net->bps;
+ int cnt = bps * (fft_net->stages - 1);
+
+ /* predetermined register addresses and coefficients */
+ xpr = fft_net->indexpr;
+ xpi = fft_net->indexpi;
+ xqr = fft_net->indexqr;
+ xqi = fft_net->indexqi;
+
+ if (fft_net->direction==FORWARD) { /* FORWARD FFT coefficients */
+ cr = fft_net->coeffr;
+ ci = fft_net->coeffi;
+ }
+ else { /* INVERSE FFT coefficients */
+ cr = fft_net->inv_coeffr;
+ ci = fft_net->inv_coeffi;
+ }
+
+ /* stage one coefficients are 1 + 0j so C*X(q)=X(q) */
+ /* bps mults can be avoided */
+
+ for (i = 0; i < bps; i++) {
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+
+ }
+
+ for (i = 0; i < cnt; i++) {
+
+ /* mult X(q) by coeff C */
+ tqr = **xqr * *cr - **xqi * *ci;
+ tqi = **xqr * *ci + **xqi * *cr;
+
+ /* exchange register with temp */
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+ }
+}
+
+
+/****************************************************************************/
+/* SUPPORT MODULES */
+/****************************************************************************/
+
+void net_alloc(FFT_NET *fft_net)
+
+
+/* effects: Allocates appropriate two dimensional arrays and assigns
+ correct internal pointers.
+*/
+
+{
+
+ int stages, bps, n;
+
+ n = fft_net->n;
+ stages = fft_net->stages;
+ bps = fft_net->bps;
+
+
+ /* two dimensional arrays with elements stored sequentially */
+
+ fft_net->load_index = (int *)malloc(n * INT_SIZE);
+ fft_net->regr = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->regi = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->indexpr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexpi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+
+ /* one dimensional load window */
+ fft_net->window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->inv_window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+}
+
+void net_dealloc(FFT_NET *fft_net)
+
+
+/* effects: Deallocates given FFT network.
+*/
+
+{
+
+ free((char *)fft_net->load_index);
+ free((char *)fft_net->regr);
+ free((char *)fft_net->regi);
+ free((char *)fft_net->coeffr);
+ free((char *)fft_net->coeffi);
+ free((char *)fft_net->inv_coeffr);
+ free((char *)fft_net->inv_coeffi);
+ free((char *)fft_net->indexpr);
+ free((char *)fft_net->indexpi);
+ free((char *)fft_net->indexqr);
+ free((char *)fft_net->indexqi);
+ free((char *)fft_net->window);
+ free((char *)fft_net->inv_window);
+}
+
+
+BOOL power_of_two(n)
+
+int n;
+
+/* effects: Returns TRUE if n is a power of two, otherwise FALSE.
+*/
+
+{
+ int i;
+
+ for (i = n; i > 1; i >>= 1)
+ if (i & 1) return FALSE; /* more than one bit high */
+ return TRUE;
+}
+
+
+void create_hanning(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a hanning window of the appropriate
+ size scaled by scale.
+*/
+
+{
+ SAMPLE a, pi_div_n = PI/n;
+ int k;
+
+ for (k=1; k <= n; k++) {
+ a = sin(k * pi_div_n);
+ *window++ = scale * a * a;
+ }
+}
+
+
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a rectangular window of the
+ appropriate size of height scale.
+*/
+
+{
+ while (n--)
+ *window++ = scale;
+}
+
+
+void short_to_float(short *short_buf, float *float_buf, int n)
+
+/* effects; Converts short_buf to floats and stores them in float_buf.
+*/
+
+{
+ while (n--) {
+ *float_buf++ = (float)*short_buf++;
+ }
+}
+
+
+/* here's the meat: */
+
+void pd_fft(float *buf, int npoints, int inverse)
+{
+ double renorm;
+ float *fp, *fp2;
+ int i;
+ renorm = (inverse ? npoints : 1.);
+ cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR,
+ buf, RECT, LINEAR, buf, RECT, LINEAR, 0);
+ for (i = npoints << 1, fp = buf; i--; fp++) *fp *= renorm;
+}
+/*****************************************************************************/
+/* */
+/* Fast Fourier Transform */
+/* Network Abstraction, Definitions */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - To incorporate link list of different sized networks */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* added debug option 5/91 brown@nadia */
+/* change sign at AAA */
+/* */
+/* Fast Fourier Transform */
+/* FFT Network Interaction and Support Modules */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - Generalized to one procedure call with typed I/O */
+/* */
+/*****************************************************************************/
+
+/* Overview:
+
+ My realization of the FFT involves a representation of a network of
+ "butterfly" elements that takes a set of 'N' sound samples as input and
+ computes the discrete Fourier transform. This network consists of a
+ series of stages (log2 N), each stage consisting of N/2 parallel butterfly
+ elements. Consecutive stages are connected by specific, predetermined flow
+ paths, (see Oppenheim, Schafer for details) and each butterfly element has
+ an associated multiplicative coefficient.
+
+ FFT NETWORK:
+ -----------
+ ____ _ ____ _ ____ _ ____ _ ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg1| | | |W^r1| | | |reg1| | | |W^r1| | | |reg1|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg2| | | |W^r2| | | |reg2| | | |W^r2| | | |reg2|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg | | | |W^r | | | |reg | | | |W^r | | | |reg |
+ | N/2| | | | N/2| | | | N/2| | | | N/2| | | | N/2| .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|--o
+
+ ^ ^ ^ ^
+ Initial | Bttrfly | Rd/Wrt | Bttrfly | Rd/Wrt
+ Buffer | | Register | | Register
+ |____________|____________|____________|
+ |
+ |
+ Interconnect
+ Paths
+
+ The use of "in-place" computation permits one to use only one set of
+ registers realized by an array of complex number structures. To describe
+ the coefficients for each butterfly I am using a two dimensional array
+ (stage, butterfly) of complex numbers. The predetermined stage connections
+ will be described in a two dimensional array of indicies. These indicies
+ will be used to determine the order of reading at each stage of the
+ computation.
+*/
+
+
+/*****************************************************************************/
+/* INCLUDE FILES */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+ /* the following is needed only to declare pd_fft() as exportable in MSW */
+#include "m_pd.h"
+
+/* some basic definitions */
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define SAMPLE float /* data type used in calculation */
+
+#define SHORT_SIZE sizeof(short)
+#define INT_SIZE sizeof(int)
+#define FLOAT_SIZE sizeof(float)
+#define SAMPLE_SIZE sizeof(SAMPLE)
+#define PNTR_SIZE sizeof(char *)
+
+#define PI 3.1415927
+#define TWO_PI 6.2831854
+
+/* type definitions for I/O buffers */
+#define REAL 0 /* real only */
+#define IMAG 2 /* imaginary only */
+#define RECT 8 /* real and imaginary */
+#define MAG 16 /* magnitude only */
+#define PHASE 32 /* phase only */
+#define POLAR 64 /* magnitude and phase*/
+
+/* scale definitions for I/O buffers */
+#define LINEAR 0
+#define DB 1 /* 20log10 */
+
+/* transform direction definition */
+#define FORWARD 1 /* Forward FFT */
+#define INVERSE 2 /* Inverse FFT */
+
+/* window type definitions */
+#define HANNING 1
+#define RECTANGULAR 0
+
+
+
+/* network structure definition */
+
+typedef struct Tfft_net {
+ int n;
+ int stages;
+ int bps;
+ int direction;
+ int window_type;
+ int *load_index;
+ SAMPLE *window, *inv_window;
+ SAMPLE *regr;
+ SAMPLE *regi;
+ SAMPLE **indexpr;
+ SAMPLE **indexpi;
+ SAMPLE **indexqr;
+ SAMPLE **indexqi;
+ SAMPLE *coeffr, *inv_coeffr;
+ SAMPLE *coeffi, *inv_coeffi;
+ struct Tfft_net *next;
+} FFT_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);
+
+
+/*****************************************************************************/
+/* GLOBAL DECLARATIONS */
+/*****************************************************************************/
+
+static FFT_NET *firstnet;
+
+/* prototypes */
+
+void net_alloc(FFT_NET *fft_net);
+void net_dealloc(FFT_NET *fft_net);
+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,
+ 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,
+ int buf_scale, int debug);
+void build_fft_network(FFT_NET *fft_net, int n, int window_type);
+
+/*****************************************************************************/
+/* GENERALIZED FAST FOURIER TRANSFORM MODULE */
+/*****************************************************************************/
+
+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)
+
+/* modifies: result_buf
+ effects: Computes npnt FFT specified by form, scale, and dir parameters.
+ Source samples (single precision float) are taken from soure_buf and
+ the transfrmd representation is stored in result_buf (single precision
+ float). The parameters are defined as follows:
+
+ trnsfrm_dir = FORWARD | INVERSE
+ npnt = 2^k for some any positive integer k
+ window = HANNING | RECTANGULAR
+ (RECT = real and imag parts, POLAR = magnitude and phase)
+ source_form = REAL | IMAG | RECT | POLAR
+ result_form = REAL | IMAG | RECT | MAG | PHASE | POLAR
+ xxxxxx_scale= LINEAR | DB ( 20log10 |mag| )
+
+ The input/output buffers are stored in a form appropriate to the type.
+ For example: REAL => {real, real, real ...},
+ MAG => {mag, mag, mag, ... },
+ RECT => {real, imag, real, imag, ... },
+ POLAR => {mag, phase, mag, phase, ... }.
+
+ To look at the magnitude (in db) of a 1024 point FFT of a real time
+ signal we have:
+
+ fft(FORWARD, 1024, RECTANGULAR, input, REAL, LINEAR, output, MAG, DB)
+
+ All possible input and output combinations are possible given the
+ choice of type and scale parameters.
+*/
+
+{
+ FFT_NET *thisnet = (FFT_NET *)0;
+ FFT_NET *lastnet = (FFT_NET *)0;
+
+ /* A linked list of fft networks of different sizes is maintained to
+ avoid building with every call. The network is built on the first
+ call but reused for subsequent calls requesting the same size
+ transformation.
+ */
+
+ thisnet=firstnet;
+ while (thisnet) {
+ if (!(thisnet->n == npnt) || !(thisnet->window_type == window)) {
+ /* current net doesn't match size or window type */
+ lastnet=thisnet;
+ thisnet=thisnet->next;
+ continue; /* keep looking */
+ }
+
+ else { /* network matches desired size */
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet); /* do transformation */
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+ }
+ }
+
+ /* none of existing networks match required size*/
+
+ if (lastnet) { /* add new network to end of list */
+ thisnet = (FFT_NET *)malloc(sizeof(FFT_NET)); /* allocate */
+ thisnet->next = 0;
+ lastnet->next = thisnet; /* add to end of list */
+ }
+ else { /* first network to be created */
+ thisnet=firstnet=(FFT_NET *)malloc(sizeof(FFT_NET)); /* alloc. */
+ thisnet->next = 0;
+ }
+
+ /* build new network and compute transformation */
+ build_fft_network(thisnet, npnt, window);
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet);
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+}
+
+void fft_clear(void)
+
+/* effects: Deallocates all preserved FFT networks. Should be used when
+ finished with all computations.
+*/
+
+{
+ FFT_NET *thisnet, *nextnet;
+
+ if (firstnet) {
+ thisnet=firstnet;
+ do {
+ nextnet = thisnet->next;
+ net_dealloc(thisnet);
+ free((char *)thisnet);
+ } while (thisnet = nextnet);
+ }
+}
+
+
+/*****************************************************************************/
+/* NETWORK CONSTRUCTION */
+/*****************************************************************************/
+
+void build_fft_network(FFT_NET *fft_net, int n, int window_type)
+
+
+/* modifies:fft_net
+ effects: Constructs the fft network as described in fft.h. Butterfly
+ coefficients, read/write indicies, bit reversed load indicies,
+ and array allocations are computed.
+*/
+
+{
+ int cntr, i, j, s;
+ int stages, bps;
+ int **p, **q, *pp, *qp;
+ SAMPLE two_pi_div_n = TWO_PI / n;
+
+
+ /* network definition */
+ fft_net->n = n;
+ fft_net->bps = bps = n/2;
+ for (i = 0, j = n; j > 1; j >>= 1, i++);
+ fft_net->stages = stages = i;
+ fft_net->direction = FORWARD;
+ fft_net->window_type = window_type;
+ fft_net->next = (FFT_NET *)0;
+
+ /* allocate registers, index, coefficient arrays */
+ net_alloc(fft_net);
+
+
+ /* create appropriate windows */
+ if (window_type==HANNING) {
+ create_hanning(fft_net->window, n, 1.);
+ create_hanning(fft_net->inv_window, n, 1./n);
+ }
+ else {
+ create_rectangular(fft_net->window, n, 1.);
+ create_rectangular(fft_net->inv_window, n, 1./n);
+ }
+
+
+ /* calculate butterfly coefficients */ {
+
+ int num_diff_coeffs, power_inc, power;
+ SAMPLE *coeffpr = fft_net->coeffr;
+ SAMPLE *coeffpi = fft_net->coeffi;
+ SAMPLE *inv_coeffpr = fft_net->inv_coeffr;
+ SAMPLE *inv_coeffpi = fft_net->inv_coeffi;
+
+ /* stage one coeffs are 1 + 0j */
+ for (i = 0; i < bps; i++) {
+ *coeffpr = *inv_coeffpr = 1.;
+ *coeffpi = *inv_coeffpi = 0.;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+
+ /* stage 2 to last stage coeffs need calculation */
+ /* (1<<r <=> 2^r */
+ for (s = 2; s <= stages; s++) {
+
+ num_diff_coeffs = n / (1 << (stages - s + 1));
+ power_inc = 1 << (stages -s);
+ cntr = 0;
+
+ for (i = bps/num_diff_coeffs; i > 0; i--) {
+
+ power = 0;
+
+ for (j = num_diff_coeffs; j > 0; j--) {
+ *coeffpr = cos(two_pi_div_n*power);
+ *inv_coeffpr = cos(two_pi_div_n*power);
+/* AAA change these signs */ *coeffpi = -sin(two_pi_div_n*power);
+/* change back */ *inv_coeffpi = sin(two_pi_div_n*power);
+ power += power_inc;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+ }
+ }
+ }
+
+ /* calculate network indicies: stage exchange indicies are
+ calculated and then used as offset values from the base
+ register locations. The final addresses are then stored in
+ fft_net.
+ */ {
+
+ int index, inc;
+ SAMPLE **indexpr = fft_net->indexpr;
+ SAMPLE **indexpi = fft_net->indexpi;
+ SAMPLE **indexqr = fft_net->indexqr;
+ SAMPLE **indexqi = fft_net->indexqi;
+ SAMPLE *regr = fft_net->regr;
+ SAMPLE *regi = fft_net->regi;
+
+
+ /* allocate temporary 2d stage exchange index, 1d temp
+ load index */
+ p = (int **)malloc(stages * PNTR_SIZE);
+ q = (int **)malloc(stages * PNTR_SIZE);
+
+ for (s = 0; s < stages; s++) {
+ p[s] = (int *)malloc(bps * INT_SIZE);
+ q[s] = (int *)malloc(bps * INT_SIZE);
+ }
+
+ /* calculate stage exchange indicies: */
+ for (s = 0; s < stages; s++) {
+ pp = p[s];
+ qp = q[s];
+ inc = 1 << s;
+ cntr = 1 << (stages-s-1);
+ i = j = index = 0;
+
+ do {
+ do {
+ qp[i] = index + inc;
+ pp[i++] = index++;
+ } while (++j < inc);
+ index = qp[i-1] + 1;
+ j = 0;
+ } while (--cntr);
+ }
+
+ /* compute actual address values using indicies as offsets */
+ for (s = 0; s < stages; s++) {
+ for (i = 0; i < bps; i++) {
+ *indexpr++ = regr + p[s][i];
+ *indexpi++ = regi + p[s][i];
+ *indexqr++ = regr + q[s][i];
+ *indexqi++ = regi + q[s][i];
+ }
+ }
+ }
+
+
+ /* calculate load indicies (bit reverse ordering) */
+ /* bit reverse ordering achieved by passing normal
+ order indicies backwards through the network */
+
+ /* init to normal order indicies */ {
+ int *load_index,*load_indexp;
+ int *temp_indexp, *temp_index;
+ temp_index=temp_indexp=(int *)malloc(n * INT_SIZE);
+
+ i = 0; j = n;
+ load_index = load_indexp = fft_net->load_index;
+
+ while (j--)
+ *load_indexp++ = i++;
+
+ /* pass indicies backwards through net */
+ for (s = stages - 1; s > 0; s--) {
+ pp = p[s];
+ qp = q[s];
+
+ for (i = 0; i < bps; i++) {
+ temp_index[pp[i]]=load_index[2*i];
+ temp_index[qp[i]]=load_index[2*i+1];
+ }
+ j = n;
+ load_indexp = load_index;
+ temp_indexp = temp_index;
+ while (j--)
+ *load_indexp++ = *temp_indexp++;
+ }
+
+ /* free all temporary arrays */
+ free((char *)temp_index);
+ for (s = 0; s < stages; s++) {
+ free((char *)p[s]);free((char *)q[s]);
+ }
+ free((char *)p);free((char *)q);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* REGISTER LOAD AND STORE */
+/*****************************************************************************/
+
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir)
+
+/* effects: Multiplies the input buffer with the appropriate window and
+ stores the resulting values in the initial registers of the
+ network. Input buffer must contain values appropriate to form.
+ For RECT, the buffer contains real num. followed by imag num,
+ and for POLAR, it contains magnitude followed by phase. Pure
+ inputs are listed normally. Both LINEAR and DB scales are
+ interpreted.
+*/
+
+{
+ int *load_index = fft_net->load_index;
+ SAMPLE *window;
+ int index, i = 0, n = fft_net->n;
+
+ if (trnsfrm_dir==FORWARD) window = fft_net->window;
+ else if (trnsfrm_dir==INVERSE) window = fft_net->inv_window;
+ else {
+ fprintf(stderr, "load_registers:illegal transform direction\n");
+ exit(0);
+ }
+ fft_net->direction = trnsfrm_dir;
+
+ switch(buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index] * window[index];
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0;
+ fft_net->regi[i]=(SAMPLE)buf[index] * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index*2] * window[index];
+ fft_net->regi[i]=(SAMPLE)buf[index*2+1] * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* magnitude followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(buf[index*2] * cos(buf[index*2+1]))
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)(buf[index*2] * sin(buf[index*2+1]))
+ * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* log pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index]; /* window scaling after linearization */
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* log pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0.;
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* log REAL and log IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2])
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2+1])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* log mag followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * cos(buf[index*2+1])) * window[index];
+ fft_net->regi[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * sin(buf[index*2+1])) * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug)
+
+/* modifies: buf
+ effects: Writes the final contents of the network registers into buf in
+ either linear or db scale, polar or rectangular form. If any of
+ the pure forms(REAL, IMAG, MAG, or PHASE) are used then only the
+ corresponding part of the registers is stored in buf.
+*/
+
+{
+ int i;
+ SAMPLE real, imag, mag, phase;
+ int n;
+
+ i = 0;
+ n = fft_net->n;
+
+ switch (buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real > .00001)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0){ *buf++ = PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag > 0\n");}
+ else if (imag < 0){ *buf++ = -PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag < 0\n");}
+ else { *buf++ = 0;
+ if(debug) fprintf(stderr,"real=0 and imag=0\n");}
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ if (real) /* a hack to avoid div by zero */
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* real only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* imag only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* real and imag */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* COMPUTE TRANSFORMATION */
+/*****************************************************************************/
+
+void compute_fft(FFT_NET *fft_net)
+
+
+/* modifies: fft_net
+ effects: Passes the values (already loaded) in the registers through
+ the network, multiplying with appropriate coefficients at each
+ stage. The fft result will be in the registers at the end of
+ the computation. The direction of the transformation is indicated
+ by the network flag 'direction'. The form of the computation is:
+
+ X(pn) = X(p) + C*X(q)
+ X(qn) = X(p) - C*X(q)
+
+ where X(pn,qn) represents the output of the registers at each stage.
+ The calculations are actually done in place. Register pointers are
+ used to speed up the calculations.
+
+ Register and coefficient addresses involved in the calculations
+ are stored sequentially and are accessed as such. fft_net->indexp,
+ indexq contain pointers to the relevant addresses, and fft_net->coeffs,
+ inv_coeffs points to the appropriate coefficients at each stage of the
+ computation.
+*/
+
+{
+ SAMPLE **xpr, **xpi, **xqr, **xqi, *cr, *ci;
+ int i;
+ SAMPLE tpr, tpi, tqr, tqi;
+ int bps = fft_net->bps;
+ int cnt = bps * (fft_net->stages - 1);
+
+ /* predetermined register addresses and coefficients */
+ xpr = fft_net->indexpr;
+ xpi = fft_net->indexpi;
+ xqr = fft_net->indexqr;
+ xqi = fft_net->indexqi;
+
+ if (fft_net->direction==FORWARD) { /* FORWARD FFT coefficients */
+ cr = fft_net->coeffr;
+ ci = fft_net->coeffi;
+ }
+ else { /* INVERSE FFT coefficients */
+ cr = fft_net->inv_coeffr;
+ ci = fft_net->inv_coeffi;
+ }
+
+ /* stage one coefficients are 1 + 0j so C*X(q)=X(q) */
+ /* bps mults can be avoided */
+
+ for (i = 0; i < bps; i++) {
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+
+ }
+
+ for (i = 0; i < cnt; i++) {
+
+ /* mult X(q) by coeff C */
+ tqr = **xqr * *cr - **xqi * *ci;
+ tqi = **xqr * *ci + **xqi * *cr;
+
+ /* exchange register with temp */
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+ }
+}
+
+
+/****************************************************************************/
+/* SUPPORT MODULES */
+/****************************************************************************/
+
+void net_alloc(FFT_NET *fft_net)
+
+
+/* effects: Allocates appropriate two dimensional arrays and assigns
+ correct internal pointers.
+*/
+
+{
+
+ int stages, bps, n;
+
+ n = fft_net->n;
+ stages = fft_net->stages;
+ bps = fft_net->bps;
+
+
+ /* two dimensional arrays with elements stored sequentially */
+
+ fft_net->load_index = (int *)malloc(n * INT_SIZE);
+ fft_net->regr = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->regi = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->indexpr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexpi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+
+ /* one dimensional load window */
+ fft_net->window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->inv_window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+}
+
+void net_dealloc(FFT_NET *fft_net)
+
+
+/* effects: Deallocates given FFT network.
+*/
+
+{
+
+ free((char *)fft_net->load_index);
+ free((char *)fft_net->regr);
+ free((char *)fft_net->regi);
+ free((char *)fft_net->coeffr);
+ free((char *)fft_net->coeffi);
+ free((char *)fft_net->inv_coeffr);
+ free((char *)fft_net->inv_coeffi);
+ free((char *)fft_net->indexpr);
+ free((char *)fft_net->indexpi);
+ free((char *)fft_net->indexqr);
+ free((char *)fft_net->indexqi);
+ free((char *)fft_net->window);
+ free((char *)fft_net->inv_window);
+}
+
+
+BOOL power_of_two(n)
+
+int n;
+
+/* effects: Returns TRUE if n is a power of two, otherwise FALSE.
+*/
+
+{
+ int i;
+
+ for (i = n; i > 1; i >>= 1)
+ if (i & 1) return FALSE; /* more than one bit high */
+ return TRUE;
+}
+
+
+void create_hanning(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a hanning window of the appropriate
+ size scaled by scale.
+*/
+
+{
+ SAMPLE a, pi_div_n = PI/n;
+ int k;
+
+ for (k=1; k <= n; k++) {
+ a = sin(k * pi_div_n);
+ *window++ = scale * a * a;
+ }
+}
+
+
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a rectangular window of the
+ appropriate size of height scale.
+*/
+
+{
+ while (n--)
+ *window++ = scale;
+}
+
+
+void short_to_float(short *short_buf, float *float_buf, int n)
+
+/* effects; Converts short_buf to floats and stores them in float_buf.
+*/
+
+{
+ while (n--) {
+ *float_buf++ = (float)*short_buf++;
+ }
+}
+
+
+/* here's the meat: */
+
+void pd_fft(float *buf, int npoints, int inverse)
+{
+ double renorm;
+ float *fp, *fp2;
+ int i;
+ renorm = (inverse ? npoints : 1.);
+ cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR,
+ buf, RECT, LINEAR, buf, RECT, LINEAR, 0);
+ for (i = npoints << 1, fp = buf; i--; fp++) *fp *= renorm;
+}
diff --git a/apps/plugins/pdbox/PDa/src/d_filter.c b/apps/plugins/pdbox/PDa/src/d_filter.c
new file mode 100644
index 0000000000..05bb7cd58e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_filter.c
@@ -0,0 +1,1094 @@
+/* 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. */
+
+/* "filters", both linear and nonlinear.
+*/
+#include "m_pd.h"
+#include <math.h>
+
+/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
+
+typedef struct hipctl
+{
+ float c_x;
+ float c_coef;
+} t_hipctl;
+
+typedef struct sighip
+{
+ t_object x_obj;
+ float x_sr;
+ float x_hz;
+ t_hipctl x_cspace;
+ t_hipctl *x_ctl;
+ float x_f;
+} t_sighip;
+
+t_class *sighip_class;
+static void sighip_ft1(t_sighip *x, t_floatarg f);
+
+static void *sighip_new(t_floatarg f)
+{
+ t_sighip *x = (t_sighip *)pd_new(sighip_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x = 0;
+ sighip_ft1(x, f);
+ x->x_f = 0;
+ return (x);
+}
+
+static void sighip_ft1(t_sighip *x, t_floatarg f)
+{
+ if (f < 0) f = 0;
+ x->x_hz = f;
+ x->x_ctl->c_coef = 1 - f * (2 * 3.14159) / x->x_sr;
+ if (x->x_ctl->c_coef < 0)
+ x->x_ctl->c_coef = 0;
+ else if (x->x_ctl->c_coef > 1)
+ x->x_ctl->c_coef = 1;
+}
+
+static t_int *sighip_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_hipctl *c = (t_hipctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x;
+ float coef = c->c_coef;
+ if (coef < 1)
+ {
+ for (i = 0; i < n; i++)
+ {
+ float new = *in++ + coef * last;
+ *out++ = new - last;
+ last = new;
+ }
+ if (PD_BIGORSMALL(last))
+ last = 0;
+ c->c_x = last;
+ }
+ else
+ {
+ for (i = 0; i < n; i++)
+ *out++ = *in++;
+ c->c_x = 0;
+ }
+ return (w+5);
+}
+
+static void sighip_dsp(t_sighip *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ sighip_ft1(x, x->x_hz);
+ dsp_add(sighip_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+static void sighip_clear(t_sighip *x, t_floatarg q)
+{
+ x->x_cspace.c_x = 0;
+}
+
+void sighip_setup(void)
+{
+ sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
+ sizeof(t_sighip), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
+ class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
+ class_addmethod(sighip_class, (t_method)sighip_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
+}
+
+/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
+
+typedef struct lopctl
+{
+ float c_x;
+ float c_coef;
+} t_lopctl;
+
+typedef struct siglop
+{
+ t_object x_obj;
+ float x_sr;
+ float x_hz;
+ t_lopctl x_cspace;
+ t_lopctl *x_ctl;
+ float x_f;
+} t_siglop;
+
+t_class *siglop_class;
+
+static void siglop_ft1(t_siglop *x, t_floatarg f);
+
+static void *siglop_new(t_floatarg f)
+{
+ t_siglop *x = (t_siglop *)pd_new(siglop_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x = 0;
+ siglop_ft1(x, f);
+ x->x_f = 0;
+ return (x);
+}
+
+static void siglop_ft1(t_siglop *x, t_floatarg f)
+{
+ if (f < 0) f = 0;
+ x->x_hz = f;
+ x->x_ctl->c_coef = f * (2 * 3.14159) / x->x_sr;
+ if (x->x_ctl->c_coef > 1)
+ x->x_ctl->c_coef = 1;
+ else if (x->x_ctl->c_coef < 0)
+ x->x_ctl->c_coef = 0;
+}
+
+static void siglop_clear(t_siglop *x, t_floatarg q)
+{
+ x->x_cspace.c_x = 0;
+}
+
+static t_int *siglop_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_lopctl *c = (t_lopctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x;
+ float coef = c->c_coef;
+ float feedback = 1 - coef;
+ for (i = 0; i < n; i++)
+ last = *out++ = coef * *in++ + feedback * last;
+ if (PD_BIGORSMALL(last))
+ last = 0;
+ c->c_x = last;
+ return (w+5);
+}
+
+static void siglop_dsp(t_siglop *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ siglop_ft1(x, x->x_hz);
+ dsp_add(siglop_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void siglop_setup(void)
+{
+ siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
+ sizeof(t_siglop), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
+ class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
+ class_addmethod(siglop_class, (t_method)siglop_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
+}
+
+/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
+
+typedef struct bpctl
+{
+ float c_x1;
+ float c_x2;
+ float c_coef1;
+ float c_coef2;
+ float c_gain;
+} t_bpctl;
+
+typedef struct sigbp
+{
+ t_object x_obj;
+ float x_sr;
+ float x_freq;
+ float x_q;
+ t_bpctl x_cspace;
+ t_bpctl *x_ctl;
+ float x_f;
+} t_sigbp;
+
+t_class *sigbp_class;
+
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
+
+static void *sigbp_new(t_floatarg f, t_floatarg q)
+{
+ t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x1 = 0;
+ x->x_cspace.c_x2 = 0;
+ sigbp_docoef(x, f, q);
+ x->x_f = 0;
+ return (x);
+}
+
+static float sigbp_qcos(float f)
+{
+ if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
+ {
+ float g = f*f;
+ return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
+ }
+ else return (0);
+}
+
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
+{
+ float r, oneminusr, omega;
+ if (f < 0.001) f = 10;
+ if (q < 0) q = 0;
+ x->x_freq = f;
+ x->x_q = q;
+ omega = f * (2.0f * 3.14159f) / x->x_sr;
+ if (q < 0.001) oneminusr = 1.0f;
+ else oneminusr = omega/q;
+ if (oneminusr > 1.0f) oneminusr = 1.0f;
+ r = 1.0f - oneminusr;
+ x->x_ctl->c_coef1 = 2.0f * sigbp_qcos(omega) * r;
+ x->x_ctl->c_coef2 = - r * r;
+ x->x_ctl->c_gain = 2 * oneminusr * (oneminusr + r * omega);
+ /* post("r %f, omega %f, coef1 %f, coef2 %f",
+ r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
+}
+
+static void sigbp_ft1(t_sigbp *x, t_floatarg f)
+{
+ sigbp_docoef(x, f, x->x_q);
+}
+
+static void sigbp_ft2(t_sigbp *x, t_floatarg q)
+{
+ sigbp_docoef(x, x->x_freq, q);
+}
+
+static void sigbp_clear(t_sigbp *x, t_floatarg q)
+{
+ x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
+}
+
+static t_int *sigbp_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_bpctl *c = (t_bpctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x1;
+ float prev = c->c_x2;
+ float coef1 = c->c_coef1;
+ float coef2 = c->c_coef2;
+ float gain = c->c_gain;
+ for (i = 0; i < n; i++)
+ {
+ float output = *in++ + coef1 * last + coef2 * prev;
+ *out++ = gain * output;
+ prev = last;
+ last = output;
+ }
+ if (PD_BIGORSMALL(last))
+ last = 0;
+ if (PD_BIGORSMALL(prev))
+ prev = 0;
+ c->c_x1 = last;
+ c->c_x2 = prev;
+ return (w+5);
+}
+
+static void sigbp_dsp(t_sigbp *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ sigbp_docoef(x, x->x_freq, x->x_q);
+ dsp_add(sigbp_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigbp_setup(void)
+{
+ sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
+ sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
+ class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
+}
+
+/* ---------------- biquad~ - raw biquad filter ----------------- */
+
+typedef struct biquadctl
+{
+ float c_x1;
+ float c_x2;
+ float c_fb1;
+ float c_fb2;
+ float c_ff1;
+ float c_ff2;
+ float c_ff3;
+} t_biquadctl;
+
+typedef struct sigbiquad
+{
+ t_object x_obj;
+ float x_f;
+ t_biquadctl x_cspace;
+ t_biquadctl *x_ctl;
+} t_sigbiquad;
+
+t_class *sigbiquad_class;
+
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
+
+static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
+ sigbiquad_list(x, s, argc, argv);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigbiquad_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_biquadctl *c = (t_biquadctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x1;
+ float prev = c->c_x2;
+ float fb1 = c->c_fb1;
+ float fb2 = c->c_fb2;
+ float ff1 = c->c_ff1;
+ float ff2 = c->c_ff2;
+ float ff3 = c->c_ff3;
+ for (i = 0; i < n; i++)
+ {
+ float output = *in++ + fb1 * last + fb2 * prev;
+ if (PD_BIGORSMALL(output))
+ output = 0;
+ *out++ = ff1 * output + ff2 * last + ff3 * prev;
+ prev = last;
+ last = output;
+ }
+ c->c_x1 = last;
+ c->c_x2 = prev;
+ return (w+5);
+}
+
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
+{
+ float fb1 = atom_getfloatarg(0, argc, argv);
+ float fb2 = atom_getfloatarg(1, argc, argv);
+ float ff1 = atom_getfloatarg(2, argc, argv);
+ float ff2 = atom_getfloatarg(3, argc, argv);
+ float ff3 = atom_getfloatarg(4, argc, argv);
+ float discriminant = fb1 * fb1 + 4 * fb2;
+ t_biquadctl *c = x->x_ctl;
+ if (discriminant < 0) /* imaginary roots -- resonant filter */
+ {
+ /* they're conjugates so we just check that the product
+ is less than one */
+ if (fb2 >= -1.0f) goto stable;
+ }
+ else /* real roots */
+ {
+ /* check that the parabola 1 - fb1 x - fb2 x^2 has a
+ vertex between -1 and 1, and that it's nonnegative
+ at both ends, which implies both roots are in [1-,1]. */
+ if (fb1 <= 2.0f && fb1 >= -2.0f &&
+ 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
+ goto stable;
+ }
+ /* if unstable, just bash to zero */
+ fb1 = fb2 = ff1 = ff2 = ff3 = 0;
+stable:
+ c->c_fb1 = fb1;
+ c->c_fb2 = fb2;
+ c->c_ff1 = ff1;
+ c->c_ff2 = ff2;
+ c->c_ff3 = ff3;
+}
+
+static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_biquadctl *c = x->x_ctl;
+ c->c_x1 = atom_getfloatarg(0, argc, argv);
+ c->c_x2 = atom_getfloatarg(1, argc, argv);
+}
+
+static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
+{
+ dsp_add(sigbiquad_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigbiquad_setup(void)
+{
+ sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
+ 0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
+ class_addlist(sigbiquad_class, sigbiquad_list);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
+ A_GIMME, 0);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
+ A_GIMME, 0);
+}
+
+/* ---------------- samphold~ - sample and hold ----------------- */
+
+typedef struct sigsamphold
+{
+ t_object x_obj;
+ float x_f;
+ float x_lastin;
+ float x_lastout;
+} t_sigsamphold;
+
+t_class *sigsamphold_class;
+
+static void *sigsamphold_new(void)
+{
+ t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_lastin = 0;
+ x->x_lastout = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigsamphold_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ float *in2 = (float *)(w[2]);
+ float *out = (float *)(w[3]);
+ t_sigsamphold *x = (t_sigsamphold *)(w[4]);
+ int n = (t_int)(w[5]);
+ int i;
+ float lastin = x->x_lastin;
+ float lastout = x->x_lastout;
+ for (i = 0; i < n; i++, *in1++)
+ {
+ float next = *in2++;
+ if (next < lastin) lastout = *in1;
+ *out++ = lastout;
+ lastin = next;
+ }
+ x->x_lastin = lastin;
+ x->x_lastout = lastout;
+ return (w+6);
+}
+
+static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
+{
+ dsp_add(sigsamphold_perform, 5,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ x, sp[0]->s_n);
+}
+
+static void sigsamphold_reset(t_sigsamphold *x)
+{
+ x->x_lastin = 1e20;
+}
+
+static void sigsamphold_set(t_sigsamphold *x, t_float f)
+{
+ x->x_lastout = f;
+}
+
+void sigsamphold_setup(void)
+{
+ sigsamphold_class = class_new(gensym("samphold~"),
+ (t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
+ CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
+ gensym("set"), A_FLOAT, 0);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
+ gensym("reset"), 0);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ setup routine ------------------------- */
+
+void d_filter_setup(void)
+{
+ sighip_setup();
+ siglop_setup();
+ sigbp_setup();
+ sigbiquad_setup();
+ sigsamphold_setup();
+}
+/* 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. */
+
+/* "filters", both linear and nonlinear.
+*/
+#include "m_pd.h"
+#include <math.h>
+
+/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
+
+typedef struct hipctl
+{
+ float c_x;
+ float c_coef;
+} t_hipctl;
+
+typedef struct sighip
+{
+ t_object x_obj;
+ float x_sr;
+ float x_hz;
+ t_hipctl x_cspace;
+ t_hipctl *x_ctl;
+ float x_f;
+} t_sighip;
+
+t_class *sighip_class;
+static void sighip_ft1(t_sighip *x, t_floatarg f);
+
+static void *sighip_new(t_floatarg f)
+{
+ t_sighip *x = (t_sighip *)pd_new(sighip_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x = 0;
+ sighip_ft1(x, f);
+ x->x_f = 0;
+ return (x);
+}
+
+static void sighip_ft1(t_sighip *x, t_floatarg f)
+{
+ if (f < 0) f = 0;
+ x->x_hz = f;
+ x->x_ctl->c_coef = 1 - f * (2 * 3.14159) / x->x_sr;
+ if (x->x_ctl->c_coef < 0)
+ x->x_ctl->c_coef = 0;
+ else if (x->x_ctl->c_coef > 1)
+ x->x_ctl->c_coef = 1;
+}
+
+static t_int *sighip_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_hipctl *c = (t_hipctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x;
+ float coef = c->c_coef;
+ if (coef < 1)
+ {
+ for (i = 0; i < n; i++)
+ {
+ float new = *in++ + coef * last;
+ *out++ = new - last;
+ last = new;
+ }
+ if (PD_BIGORSMALL(last))
+ last = 0;
+ c->c_x = last;
+ }
+ else
+ {
+ for (i = 0; i < n; i++)
+ *out++ = *in++;
+ c->c_x = 0;
+ }
+ return (w+5);
+}
+
+static void sighip_dsp(t_sighip *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ sighip_ft1(x, x->x_hz);
+ dsp_add(sighip_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+static void sighip_clear(t_sighip *x, t_floatarg q)
+{
+ x->x_cspace.c_x = 0;
+}
+
+void sighip_setup(void)
+{
+ sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
+ sizeof(t_sighip), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
+ class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
+ class_addmethod(sighip_class, (t_method)sighip_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
+}
+
+/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
+
+typedef struct lopctl
+{
+ float c_x;
+ float c_coef;
+} t_lopctl;
+
+typedef struct siglop
+{
+ t_object x_obj;
+ float x_sr;
+ float x_hz;
+ t_lopctl x_cspace;
+ t_lopctl *x_ctl;
+ float x_f;
+} t_siglop;
+
+t_class *siglop_class;
+
+static void siglop_ft1(t_siglop *x, t_floatarg f);
+
+static void *siglop_new(t_floatarg f)
+{
+ t_siglop *x = (t_siglop *)pd_new(siglop_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x = 0;
+ siglop_ft1(x, f);
+ x->x_f = 0;
+ return (x);
+}
+
+static void siglop_ft1(t_siglop *x, t_floatarg f)
+{
+ if (f < 0) f = 0;
+ x->x_hz = f;
+ x->x_ctl->c_coef = f * (2 * 3.14159) / x->x_sr;
+ if (x->x_ctl->c_coef > 1)
+ x->x_ctl->c_coef = 1;
+ else if (x->x_ctl->c_coef < 0)
+ x->x_ctl->c_coef = 0;
+}
+
+static void siglop_clear(t_siglop *x, t_floatarg q)
+{
+ x->x_cspace.c_x = 0;
+}
+
+static t_int *siglop_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_lopctl *c = (t_lopctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x;
+ float coef = c->c_coef;
+ float feedback = 1 - coef;
+ for (i = 0; i < n; i++)
+ last = *out++ = coef * *in++ + feedback * last;
+ if (PD_BIGORSMALL(last))
+ last = 0;
+ c->c_x = last;
+ return (w+5);
+}
+
+static void siglop_dsp(t_siglop *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ siglop_ft1(x, x->x_hz);
+ dsp_add(siglop_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void siglop_setup(void)
+{
+ siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
+ sizeof(t_siglop), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
+ class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
+ class_addmethod(siglop_class, (t_method)siglop_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
+}
+
+/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
+
+typedef struct bpctl
+{
+ float c_x1;
+ float c_x2;
+ float c_coef1;
+ float c_coef2;
+ float c_gain;
+} t_bpctl;
+
+typedef struct sigbp
+{
+ t_object x_obj;
+ float x_sr;
+ float x_freq;
+ float x_q;
+ t_bpctl x_cspace;
+ t_bpctl *x_ctl;
+ float x_f;
+} t_sigbp;
+
+t_class *sigbp_class;
+
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
+
+static void *sigbp_new(t_floatarg f, t_floatarg q)
+{
+ t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x1 = 0;
+ x->x_cspace.c_x2 = 0;
+ sigbp_docoef(x, f, q);
+ x->x_f = 0;
+ return (x);
+}
+
+static float sigbp_qcos(float f)
+{
+ if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
+ {
+ float g = f*f;
+ return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
+ }
+ else return (0);
+}
+
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
+{
+ float r, oneminusr, omega;
+ if (f < 0.001) f = 10;
+ if (q < 0) q = 0;
+ x->x_freq = f;
+ x->x_q = q;
+ omega = f * (2.0f * 3.14159f) / x->x_sr;
+ if (q < 0.001) oneminusr = 1.0f;
+ else oneminusr = omega/q;
+ if (oneminusr > 1.0f) oneminusr = 1.0f;
+ r = 1.0f - oneminusr;
+ x->x_ctl->c_coef1 = 2.0f * sigbp_qcos(omega) * r;
+ x->x_ctl->c_coef2 = - r * r;
+ x->x_ctl->c_gain = 2 * oneminusr * (oneminusr + r * omega);
+ /* post("r %f, omega %f, coef1 %f, coef2 %f",
+ r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
+}
+
+static void sigbp_ft1(t_sigbp *x, t_floatarg f)
+{
+ sigbp_docoef(x, f, x->x_q);
+}
+
+static void sigbp_ft2(t_sigbp *x, t_floatarg q)
+{
+ sigbp_docoef(x, x->x_freq, q);
+}
+
+static void sigbp_clear(t_sigbp *x, t_floatarg q)
+{
+ x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
+}
+
+static t_int *sigbp_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_bpctl *c = (t_bpctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x1;
+ float prev = c->c_x2;
+ float coef1 = c->c_coef1;
+ float coef2 = c->c_coef2;
+ float gain = c->c_gain;
+ for (i = 0; i < n; i++)
+ {
+ float output = *in++ + coef1 * last + coef2 * prev;
+ *out++ = gain * output;
+ prev = last;
+ last = output;
+ }
+ if (PD_BIGORSMALL(last))
+ last = 0;
+ if (PD_BIGORSMALL(prev))
+ prev = 0;
+ c->c_x1 = last;
+ c->c_x2 = prev;
+ return (w+5);
+}
+
+static void sigbp_dsp(t_sigbp *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ sigbp_docoef(x, x->x_freq, x->x_q);
+ dsp_add(sigbp_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigbp_setup(void)
+{
+ sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
+ sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
+ class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
+}
+
+/* ---------------- biquad~ - raw biquad filter ----------------- */
+
+typedef struct biquadctl
+{
+ float c_x1;
+ float c_x2;
+ float c_fb1;
+ float c_fb2;
+ float c_ff1;
+ float c_ff2;
+ float c_ff3;
+} t_biquadctl;
+
+typedef struct sigbiquad
+{
+ t_object x_obj;
+ float x_f;
+ t_biquadctl x_cspace;
+ t_biquadctl *x_ctl;
+} t_sigbiquad;
+
+t_class *sigbiquad_class;
+
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
+
+static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
+ sigbiquad_list(x, s, argc, argv);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigbiquad_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_biquadctl *c = (t_biquadctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x1;
+ float prev = c->c_x2;
+ float fb1 = c->c_fb1;
+ float fb2 = c->c_fb2;
+ float ff1 = c->c_ff1;
+ float ff2 = c->c_ff2;
+ float ff3 = c->c_ff3;
+ for (i = 0; i < n; i++)
+ {
+ float output = *in++ + fb1 * last + fb2 * prev;
+ if (PD_BIGORSMALL(output))
+ output = 0;
+ *out++ = ff1 * output + ff2 * last + ff3 * prev;
+ prev = last;
+ last = output;
+ }
+ c->c_x1 = last;
+ c->c_x2 = prev;
+ return (w+5);
+}
+
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
+{
+ float fb1 = atom_getfloatarg(0, argc, argv);
+ float fb2 = atom_getfloatarg(1, argc, argv);
+ float ff1 = atom_getfloatarg(2, argc, argv);
+ float ff2 = atom_getfloatarg(3, argc, argv);
+ float ff3 = atom_getfloatarg(4, argc, argv);
+ float discriminant = fb1 * fb1 + 4 * fb2;
+ t_biquadctl *c = x->x_ctl;
+ if (discriminant < 0) /* imaginary roots -- resonant filter */
+ {
+ /* they're conjugates so we just check that the product
+ is less than one */
+ if (fb2 >= -1.0f) goto stable;
+ }
+ else /* real roots */
+ {
+ /* check that the parabola 1 - fb1 x - fb2 x^2 has a
+ vertex between -1 and 1, and that it's nonnegative
+ at both ends, which implies both roots are in [1-,1]. */
+ if (fb1 <= 2.0f && fb1 >= -2.0f &&
+ 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
+ goto stable;
+ }
+ /* if unstable, just bash to zero */
+ fb1 = fb2 = ff1 = ff2 = ff3 = 0;
+stable:
+ c->c_fb1 = fb1;
+ c->c_fb2 = fb2;
+ c->c_ff1 = ff1;
+ c->c_ff2 = ff2;
+ c->c_ff3 = ff3;
+}
+
+static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_biquadctl *c = x->x_ctl;
+ c->c_x1 = atom_getfloatarg(0, argc, argv);
+ c->c_x2 = atom_getfloatarg(1, argc, argv);
+}
+
+static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
+{
+ dsp_add(sigbiquad_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigbiquad_setup(void)
+{
+ sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
+ 0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
+ class_addlist(sigbiquad_class, sigbiquad_list);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
+ A_GIMME, 0);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
+ A_GIMME, 0);
+}
+
+/* ---------------- samphold~ - sample and hold ----------------- */
+
+typedef struct sigsamphold
+{
+ t_object x_obj;
+ float x_f;
+ float x_lastin;
+ float x_lastout;
+} t_sigsamphold;
+
+t_class *sigsamphold_class;
+
+static void *sigsamphold_new(void)
+{
+ t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_lastin = 0;
+ x->x_lastout = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigsamphold_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ float *in2 = (float *)(w[2]);
+ float *out = (float *)(w[3]);
+ t_sigsamphold *x = (t_sigsamphold *)(w[4]);
+ int n = (t_int)(w[5]);
+ int i;
+ float lastin = x->x_lastin;
+ float lastout = x->x_lastout;
+ for (i = 0; i < n; i++, *in1++)
+ {
+ float next = *in2++;
+ if (next < lastin) lastout = *in1;
+ *out++ = lastout;
+ lastin = next;
+ }
+ x->x_lastin = lastin;
+ x->x_lastout = lastout;
+ return (w+6);
+}
+
+static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
+{
+ dsp_add(sigsamphold_perform, 5,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ x, sp[0]->s_n);
+}
+
+static void sigsamphold_reset(t_sigsamphold *x)
+{
+ x->x_lastin = 1e20;
+}
+
+static void sigsamphold_set(t_sigsamphold *x, t_float f)
+{
+ x->x_lastout = f;
+}
+
+void sigsamphold_setup(void)
+{
+ sigsamphold_class = class_new(gensym("samphold~"),
+ (t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
+ CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
+ gensym("set"), A_FLOAT, 0);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
+ gensym("reset"), 0);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ setup routine ------------------------- */
+
+void d_filter_setup(void)
+{
+ sighip_setup();
+ siglop_setup();
+ sigbp_setup();
+ sigbiquad_setup();
+ sigsamphold_setup();
+}
diff --git a/apps/plugins/pdbox/PDa/src/d_global.c b/apps/plugins/pdbox/PDa/src/d_global.c
new file mode 100644
index 0000000000..2b129ac5f4
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_global.c
@@ -0,0 +1,616 @@
+/* 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~, receive~, throw~, catch~ */
+
+#include "m_pd.h"
+#include <string.h>
+
+#define DEFSENDVS 64 /* LATER get send to get this from canvas */
+
+/* ----------------------------- send~ ----------------------------- */
+static t_class *sigsend_class;
+
+typedef struct _sigsend
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ int x_n;
+ t_sample *x_vec;
+ float x_f;
+} t_sigsend;
+
+static void *sigsend_new(t_symbol *s)
+{
+ t_sigsend *x = (t_sigsend *)pd_new(sigsend_class);
+ pd_bind(&x->x_obj.ob_pd, s);
+ x->x_sym = s;
+ x->x_n = DEFSENDVS;
+ x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
+ memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigsend_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--)
+ {
+ *out = (PD_BIGORSMALL(*in) ? 0 : *in);
+ out++;
+ in++;
+ }
+ return (w+4);
+}
+
+static void sigsend_dsp(t_sigsend *x, t_signal **sp)
+{
+ if (x->x_n == sp[0]->s_n)
+ dsp_add(sigsend_perform, 3, sp[0]->s_vec, x->x_vec, sp[0]->s_n);
+ else error("sigsend %s: unexpected vector size", x->x_sym->s_name);
+}
+
+static void sigsend_free(t_sigsend *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ freebytes(x->x_vec, x->x_n * sizeof(float));
+}
+
+static void sigsend_setup(void)
+{
+ sigsend_class = class_new(gensym("send~"), (t_newmethod)sigsend_new,
+ (t_method)sigsend_free, sizeof(t_sigsend), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigsend_new, gensym("s~"), A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, x_f);
+ class_addmethod(sigsend_class, (t_method)sigsend_dsp, gensym("dsp"), 0);
+}
+
+/* ----------------------------- receive~ ----------------------------- */
+static t_class *sigreceive_class;
+
+typedef struct _sigreceive
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_sample *x_wherefrom;
+ int x_n;
+} t_sigreceive;
+
+static void *sigreceive_new(t_symbol *s)
+{
+ t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class);
+ x->x_n = DEFSENDVS; /* LATER find our vector size correctly */
+ x->x_sym = s;
+ x->x_wherefrom = 0;
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static t_int *sigreceive_perform(t_int *w)
+{
+ t_sigreceive *x = (t_sigreceive *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ t_sample *in = x->x_wherefrom;
+ if (in)
+ {
+ while (n--)
+ *out++ = *in++;
+ }
+ else
+ {
+ while (n--)
+ *out++ = 0;
+ }
+ return (w+4);
+}
+
+static void sigreceive_set(t_sigreceive *x, t_symbol *s)
+{
+ t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->x_sym = s),
+ sigsend_class);
+ if (sender)
+ {
+ if (sender->x_n == x->x_n)
+ x->x_wherefrom = sender->x_vec;
+ else
+ {
+ pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
+ x->x_wherefrom = 0;
+ }
+ }
+ else
+ {
+ pd_error(x, "receive~ %s: no matching send", x->x_sym->s_name);
+ x->x_wherefrom = 0;
+ }
+}
+
+static void sigreceive_dsp(t_sigreceive *x, t_signal **sp)
+{
+ if (sp[0]->s_n != x->x_n)
+ {
+ pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
+ }
+ else
+ {
+ sigreceive_set(x, x->x_sym);
+ dsp_add(sigreceive_perform, 3,
+ x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigreceive_setup(void)
+{
+ sigreceive_class = class_new(gensym("receive~"),
+ (t_newmethod)sigreceive_new, 0,
+ sizeof(t_sigreceive), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigreceive_new, gensym("r~"), A_DEFSYM, 0);
+ class_addmethod(sigreceive_class, (t_method)sigreceive_set, gensym("set"),
+ A_SYMBOL, 0);
+ class_addmethod(sigreceive_class, (t_method)sigreceive_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(sigreceive_class, gensym("send~"));
+}
+
+/* ----------------------------- catch~ ----------------------------- */
+static t_class *sigcatch_class;
+
+typedef struct _sigcatch
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ int x_n;
+ t_sample *x_vec;
+} t_sigcatch;
+
+static void *sigcatch_new(t_symbol *s)
+{
+ t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class);
+ pd_bind(&x->x_obj.ob_pd, s);
+ x->x_sym = s;
+ x->x_n = DEFSENDVS;
+ x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
+ memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static t_int *sigcatch_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--) *out++ = *in, *in++ = 0;
+ return (w+4);
+}
+
+static void sigcatch_dsp(t_sigcatch *x, t_signal **sp)
+{
+ if (x->x_n == sp[0]->s_n)
+ dsp_add(sigcatch_perform, 3, x->x_vec, sp[0]->s_vec, sp[0]->s_n);
+ else error("sigcatch %s: unexpected vector size", x->x_sym->s_name);
+}
+
+static void sigcatch_free(t_sigcatch *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ freebytes(x->x_vec, x->x_n * sizeof(float));
+}
+
+static void sigcatch_setup(void)
+{
+ sigcatch_class = class_new(gensym("catch~"), (t_newmethod)sigcatch_new,
+ (t_method)sigcatch_free, sizeof(t_sigcatch), CLASS_NOINLET, A_DEFSYM, 0);
+ class_addmethod(sigcatch_class, (t_method)sigcatch_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigcatch_class, gensym("throw~"));
+}
+
+/* ----------------------------- throw~ ----------------------------- */
+static t_class *sigthrow_class;
+
+typedef struct _sigthrow
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_sample *x_whereto;
+ int x_n;
+ t_float x_f;
+} t_sigthrow;
+
+static void *sigthrow_new(t_symbol *s)
+{
+ t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class);
+ x->x_sym = s;
+ x->x_whereto = 0;
+ x->x_n = DEFSENDVS;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigthrow_perform(t_int *w)
+{
+ t_sigthrow *x = (t_sigthrow *)(w[1]);
+ t_sample *in = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ t_sample *out = x->x_whereto;
+ if (out)
+ {
+ while (n--)
+ {
+ *out += (PD_BIGORSMALL(*in) ? 0 : *in);
+ out++;
+ in++;
+ }
+ }
+ return (w+4);
+}
+
+static void sigthrow_set(t_sigthrow *x, t_symbol *s)
+{
+ t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass((x->x_sym = s),
+ sigcatch_class);
+ if (catcher)
+ {
+ if (catcher->x_n == x->x_n)
+ x->x_whereto = catcher->x_vec;
+ else
+ {
+ pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
+ x->x_whereto = 0;
+ }
+ }
+ else
+ {
+ pd_error(x, "throw~ %s: no matching catch", x->x_sym->s_name);
+ x->x_whereto = 0;
+ }
+}
+
+static void sigthrow_dsp(t_sigthrow *x, t_signal **sp)
+{
+ if (sp[0]->s_n != x->x_n)
+ {
+ pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
+ }
+ else
+ {
+ sigthrow_set(x, x->x_sym);
+ dsp_add(sigthrow_perform, 3,
+ x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigthrow_setup(void)
+{
+ sigthrow_class = class_new(gensym("throw~"), (t_newmethod)sigthrow_new, 0,
+ sizeof(t_sigthrow), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigthrow_new, gensym("r~"), A_DEFSYM, 0);
+ class_addmethod(sigthrow_class, (t_method)sigthrow_set, gensym("set"),
+ A_SYMBOL, 0);
+ CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, x_f);
+ class_addmethod(sigthrow_class, (t_method)sigthrow_dsp, gensym("dsp"), 0);
+}
+
+/* ----------------------- global setup routine ---------------- */
+
+void d_global_setup(void)
+{
+ sigsend_setup();
+ sigreceive_setup();
+ sigcatch_setup();
+ sigthrow_setup();
+}
+
+/* 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~, receive~, throw~, catch~ */
+
+#include "m_pd.h"
+#include <string.h>
+
+#define DEFSENDVS 64 /* LATER get send to get this from canvas */
+
+/* ----------------------------- send~ ----------------------------- */
+static t_class *sigsend_class;
+
+typedef struct _sigsend
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ int x_n;
+ t_sample *x_vec;
+ float x_f;
+} t_sigsend;
+
+static void *sigsend_new(t_symbol *s)
+{
+ t_sigsend *x = (t_sigsend *)pd_new(sigsend_class);
+ pd_bind(&x->x_obj.ob_pd, s);
+ x->x_sym = s;
+ x->x_n = DEFSENDVS;
+ x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
+ memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigsend_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--)
+ {
+ *out = (PD_BIGORSMALL(*in) ? 0 : *in);
+ out++;
+ in++;
+ }
+ return (w+4);
+}
+
+static void sigsend_dsp(t_sigsend *x, t_signal **sp)
+{
+ if (x->x_n == sp[0]->s_n)
+ dsp_add(sigsend_perform, 3, sp[0]->s_vec, x->x_vec, sp[0]->s_n);
+ else error("sigsend %s: unexpected vector size", x->x_sym->s_name);
+}
+
+static void sigsend_free(t_sigsend *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ freebytes(x->x_vec, x->x_n * sizeof(float));
+}
+
+static void sigsend_setup(void)
+{
+ sigsend_class = class_new(gensym("send~"), (t_newmethod)sigsend_new,
+ (t_method)sigsend_free, sizeof(t_sigsend), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigsend_new, gensym("s~"), A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, x_f);
+ class_addmethod(sigsend_class, (t_method)sigsend_dsp, gensym("dsp"), 0);
+}
+
+/* ----------------------------- receive~ ----------------------------- */
+static t_class *sigreceive_class;
+
+typedef struct _sigreceive
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_sample *x_wherefrom;
+ int x_n;
+} t_sigreceive;
+
+static void *sigreceive_new(t_symbol *s)
+{
+ t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class);
+ x->x_n = DEFSENDVS; /* LATER find our vector size correctly */
+ x->x_sym = s;
+ x->x_wherefrom = 0;
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static t_int *sigreceive_perform(t_int *w)
+{
+ t_sigreceive *x = (t_sigreceive *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ t_sample *in = x->x_wherefrom;
+ if (in)
+ {
+ while (n--)
+ *out++ = *in++;
+ }
+ else
+ {
+ while (n--)
+ *out++ = 0;
+ }
+ return (w+4);
+}
+
+static void sigreceive_set(t_sigreceive *x, t_symbol *s)
+{
+ t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->x_sym = s),
+ sigsend_class);
+ if (sender)
+ {
+ if (sender->x_n == x->x_n)
+ x->x_wherefrom = sender->x_vec;
+ else
+ {
+ pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
+ x->x_wherefrom = 0;
+ }
+ }
+ else
+ {
+ pd_error(x, "receive~ %s: no matching send", x->x_sym->s_name);
+ x->x_wherefrom = 0;
+ }
+}
+
+static void sigreceive_dsp(t_sigreceive *x, t_signal **sp)
+{
+ if (sp[0]->s_n != x->x_n)
+ {
+ pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
+ }
+ else
+ {
+ sigreceive_set(x, x->x_sym);
+ dsp_add(sigreceive_perform, 3,
+ x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigreceive_setup(void)
+{
+ sigreceive_class = class_new(gensym("receive~"),
+ (t_newmethod)sigreceive_new, 0,
+ sizeof(t_sigreceive), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigreceive_new, gensym("r~"), A_DEFSYM, 0);
+ class_addmethod(sigreceive_class, (t_method)sigreceive_set, gensym("set"),
+ A_SYMBOL, 0);
+ class_addmethod(sigreceive_class, (t_method)sigreceive_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(sigreceive_class, gensym("send~"));
+}
+
+/* ----------------------------- catch~ ----------------------------- */
+static t_class *sigcatch_class;
+
+typedef struct _sigcatch
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ int x_n;
+ t_sample *x_vec;
+} t_sigcatch;
+
+static void *sigcatch_new(t_symbol *s)
+{
+ t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class);
+ pd_bind(&x->x_obj.ob_pd, s);
+ x->x_sym = s;
+ x->x_n = DEFSENDVS;
+ x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample));
+ memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample));
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static t_int *sigcatch_perform(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]);
+ t_sample *out = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--) *out++ = *in, *in++ = 0;
+ return (w+4);
+}
+
+static void sigcatch_dsp(t_sigcatch *x, t_signal **sp)
+{
+ if (x->x_n == sp[0]->s_n)
+ dsp_add(sigcatch_perform, 3, x->x_vec, sp[0]->s_vec, sp[0]->s_n);
+ else error("sigcatch %s: unexpected vector size", x->x_sym->s_name);
+}
+
+static void sigcatch_free(t_sigcatch *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ freebytes(x->x_vec, x->x_n * sizeof(float));
+}
+
+static void sigcatch_setup(void)
+{
+ sigcatch_class = class_new(gensym("catch~"), (t_newmethod)sigcatch_new,
+ (t_method)sigcatch_free, sizeof(t_sigcatch), CLASS_NOINLET, A_DEFSYM, 0);
+ class_addmethod(sigcatch_class, (t_method)sigcatch_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigcatch_class, gensym("throw~"));
+}
+
+/* ----------------------------- throw~ ----------------------------- */
+static t_class *sigthrow_class;
+
+typedef struct _sigthrow
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_sample *x_whereto;
+ int x_n;
+ t_float x_f;
+} t_sigthrow;
+
+static void *sigthrow_new(t_symbol *s)
+{
+ t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class);
+ x->x_sym = s;
+ x->x_whereto = 0;
+ x->x_n = DEFSENDVS;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigthrow_perform(t_int *w)
+{
+ t_sigthrow *x = (t_sigthrow *)(w[1]);
+ t_sample *in = (t_sample *)(w[2]);
+ int n = (int)(w[3]);
+ t_sample *out = x->x_whereto;
+ if (out)
+ {
+ while (n--)
+ {
+ *out += (PD_BIGORSMALL(*in) ? 0 : *in);
+ out++;
+ in++;
+ }
+ }
+ return (w+4);
+}
+
+static void sigthrow_set(t_sigthrow *x, t_symbol *s)
+{
+ t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass((x->x_sym = s),
+ sigcatch_class);
+ if (catcher)
+ {
+ if (catcher->x_n == x->x_n)
+ x->x_whereto = catcher->x_vec;
+ else
+ {
+ pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
+ x->x_whereto = 0;
+ }
+ }
+ else
+ {
+ pd_error(x, "throw~ %s: no matching catch", x->x_sym->s_name);
+ x->x_whereto = 0;
+ }
+}
+
+static void sigthrow_dsp(t_sigthrow *x, t_signal **sp)
+{
+ if (sp[0]->s_n != x->x_n)
+ {
+ pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
+ }
+ else
+ {
+ sigthrow_set(x, x->x_sym);
+ dsp_add(sigthrow_perform, 3,
+ x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigthrow_setup(void)
+{
+ sigthrow_class = class_new(gensym("throw~"), (t_newmethod)sigthrow_new, 0,
+ sizeof(t_sigthrow), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigthrow_new, gensym("r~"), A_DEFSYM, 0);
+ class_addmethod(sigthrow_class, (t_method)sigthrow_set, gensym("set"),
+ A_SYMBOL, 0);
+ CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, x_f);
+ class_addmethod(sigthrow_class, (t_method)sigthrow_dsp, gensym("dsp"), 0);
+}
+
+/* ----------------------- global setup routine ---------------- */
+
+void d_global_setup(void)
+{
+ sigsend_setup();
+ sigreceive_setup();
+ sigcatch_setup();
+ sigthrow_setup();
+}
+
diff --git a/apps/plugins/pdbox/PDa/src/d_imayer_fft.c b/apps/plugins/pdbox/PDa/src/d_imayer_fft.c
new file mode 100644
index 0000000000..d8e9e9f243
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_imayer_fft.c
@@ -0,0 +1,1032 @@
+/*
+** Algorithm: complex multiplication
+**
+** Performance: Bad accuracy, great speed.
+**
+** The simplest, way of generating trig values. Note, this method is
+** not stable, and errors accumulate rapidly.
+**
+** Computation: 2 *, 1 + per value.
+*/
+
+
+#include "m_fixed.h"
+
+
+#define TRIG_FAST
+
+#ifdef TRIG_FAST
+char mtrig_algorithm[] = "Simple";
+#define TRIG_VARS \
+ t_fixed t_c,t_s;
+#define TRIG_INIT(k,c,s) \
+ { \
+ t_c = fcostab[k]; \
+ t_s = fsintab[k]; \
+ c = itofix(1); \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ t_fixed t = c; \
+ c = mult(t,t_c) - mult(s,t_s); \
+ s = mult(t,t_s) + mult(s,t_c); \
+ }
+#define TRIG_23(k,c1,s1,c2,s2,c3,s3) \
+ { \
+ c2 = mult(c1,c1) - mult(s1,s1); \
+ s2 = (mult(c1,s1)<<2); \
+ c3 = mult(c2,c1) - mult(s2,s1); \
+ s3 = mult(c2,s1) + mult(s2,c1); \
+ }
+#endif
+#define TRIG_RESET(k,c,s)
+
+/*
+** Algorithm: O. Buneman's trig generator.
+**
+** Performance: Good accuracy, mediocre speed.
+**
+** Manipulates a log(n) table to stably create n evenly spaced trig
+** values. The newly generated values lay halfway between two
+** known values, and are calculated by appropriatelly scaling the
+** average of the known trig values appropriatelly according to the
+** angle between them. This process is inherently stable; and is
+** about as accurate as most trig library functions. The errors
+** caused by this code segment are primarily due to the less stable
+** method to calculate values for 2t and s 3t. Note: I believe this
+** algorithm is patented(!), see readme file for more details.
+**
+** Computation: 1 +, 1 *, much integer math, per trig value
+**
+*/
+
+#ifdef TRIG_GOOD
+#define TRIG_VARS \
+ int t_lam=0; \
+ double coswrk[TRIG_TABLE_SIZE],sinwrk[TRIG_TABLE_SIZE];
+#define TRIG_INIT(k,c,s) \
+ { \
+ int i; \
+ for (i=0 ; i<=k ; i++) \
+ {coswrk[i]=fcostab[i];sinwrk[i]=fsintab[i];} \
+ t_lam = 0; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ int i,j; \
+ (t_lam)++; \
+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
+ i = k-i; \
+ s = sinwrk[i]; \
+ c = coswrk[i]; \
+ if (i>1) \
+ { \
+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
+ j = k - j; \
+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
+ } \
+ }
+#endif
+
+
+#define TRIG_TAB_SIZE 22
+
+static long long halsec[TRIG_TAB_SIZE]= {1,2,3};
+
+#define FFTmult(x,y) mult(x,y)
+
+
+
+
+#include "d_imayer_tables.h"
+
+#define SQRT2 ftofix(1.414213562373095048801688724209698)
+
+
+void imayer_fht(t_fixed *fz, int n)
+{
+ int k,k1,k2,k3,k4,kx;
+ t_fixed *fi,*fn,*gi;
+ TRIG_VARS;
+
+ for (k1=1,k2=0;k1<n;k1++)
+ {
+ t_fixed aa;
+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
+ if (k1>k2)
+ {
+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
+ }
+ }
+ for ( k=0 ; (1<<k)<n ; k++ );
+ k &= 1;
+ if (k==0)
+ {
+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
+ {
+ t_fixed f0,f1,f2,f3;
+ f1 = fi[0 ]-fi[1 ];
+ f0 = fi[0 ]+fi[1 ];
+ f3 = fi[2 ]-fi[3 ];
+ f2 = fi[2 ]+fi[3 ];
+ fi[2 ] = (f0-f2);
+ fi[0 ] = (f0+f2);
+ fi[3 ] = (f1-f3);
+ fi[1 ] = (f1+f3);
+ }
+ }
+ else
+ {
+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
+ {
+ t_fixed bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
+ bc1 = fi[0 ] - gi[0 ];
+ bs1 = fi[0 ] + gi[0 ];
+ bc2 = fi[2 ] - gi[2 ];
+ bs2 = fi[2 ] + gi[2 ];
+ bc3 = fi[4 ] - gi[4 ];
+ bs3 = fi[4 ] + gi[4 ];
+ bc4 = fi[6 ] - gi[6 ];
+ bs4 = fi[6 ] + gi[6 ];
+ bf1 = (bs1 - bs2);
+ bf0 = (bs1 + bs2);
+ bg1 = (bc1 - bc2);
+ bg0 = (bc1 + bc2);
+ bf3 = (bs3 - bs4);
+ bf2 = (bs3 + bs4);
+ bg3 = FFTmult(SQRT2,bc4);
+ bg2 = FFTmult(SQRT2,bc3);
+ fi[4 ] = bf0 - bf2;
+ fi[0 ] = bf0 + bf2;
+ fi[6 ] = bf1 - bf3;
+ fi[2 ] = bf1 + bf3;
+ gi[4 ] = bg0 - bg2;
+ gi[0 ] = bg0 + bg2;
+ gi[6 ] = bg1 - bg3;
+ gi[2 ] = bg1 + bg3;
+ }
+ }
+ if (n<16) return;
+
+ do
+ {
+ t_fixed s1,c1;
+ int ii;
+ k += 2;
+ k1 = 1 << k;
+ k2 = k1 << 1;
+ k4 = k2 << 1;
+ k3 = k2 + k1;
+ kx = k1 >> 1;
+ fi = fz;
+ gi = fi + kx;
+ fn = fz + n;
+ do
+ {
+ t_fixed g0,f0,f1,g1,f2,g2,f3,g3;
+ f1 = fi[0 ] - fi[k1];
+ f0 = fi[0 ] + fi[k1];
+ f3 = fi[k2] - fi[k3];
+ f2 = fi[k2] + fi[k3];
+ fi[k2] = f0 - f2;
+ fi[0 ] = f0 + f2;
+ fi[k3] = f1 - f3;
+ fi[k1] = f1 + f3;
+ g1 = gi[0 ] - gi[k1];
+ g0 = gi[0 ] + gi[k1];
+ g3 = FFTmult(SQRT2, gi[k3]);
+ g2 = FFTmult(SQRT2, gi[k2]);
+ gi[k2] = g0 - g2;
+ gi[0 ] = g0 + g2;
+ gi[k3] = g1 - g3;
+ gi[k1] = g1 + g3;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ TRIG_INIT(k,c1,s1);
+ for (ii=1;ii<kx;ii++)
+ {
+ t_fixed c2,s2;
+ TRIG_NEXT(k,c1,s1);
+ c2 = FFTmult(c1,c1) - FFTmult(s1,s1);
+ s2 = 2*FFTmult(c1,s1);
+ fn = fz + n;
+ fi = fz +ii;
+ gi = fz +k1-ii;
+ do
+ {
+ t_fixed a,b,g0,f0,f1,g1,f2,g2,f3,g3;
+ b = FFTmult(s2,fi[k1]) - FFTmult(c2,gi[k1]);
+ a = FFTmult(c2,fi[k1]) + FFTmult(s2,gi[k1]);
+ f1 = fi[0 ] - a;
+ f0 = fi[0 ] + a;
+ g1 = gi[0 ] - b;
+ g0 = gi[0 ] + b;
+ b = FFTmult(s2,fi[k3]) - FFTmult(c2,gi[k3]);
+ a = FFTmult(c2,fi[k3]) + FFTmult(s2,gi[k3]);
+ f3 = fi[k2] - a;
+ f2 = fi[k2] + a;
+ g3 = gi[k2] - b;
+ g2 = gi[k2] + b;
+ b = FFTmult(s1,f2) - FFTmult(c1,g3);
+ a = FFTmult(c1,f2) + FFTmult(s1,g3);
+ fi[k2] = f0 - a;
+ fi[0 ] = f0 + a;
+ gi[k3] = g1 - b;
+ gi[k1] = g1 + b;
+ b = FFTmult(c1,g2) - FFTmult(s1,f3);
+ a = FFTmult(s1,g2) + FFTmult(c1,f3);
+ gi[k2] = g0 - a;
+ gi[0 ] = g0 + a;
+ fi[k3] = f1 - b;
+ fi[k1] = f1 + b;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ }
+ TRIG_RESET(k,c1,s1);
+ } while (k4<n);
+}
+
+
+void imayer_fft(int n, t_fixed *real, t_fixed *imag)
+{
+ t_fixed a,b,c,d;
+ t_fixed q,r,s,t;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ real[i] = (q+t)>>1; real[j] = (q-t)>>1;
+ imag[i] = (s-r)>>1; imag[j] = (s+r)>>1;
+ }
+ imayer_fht(real,n);
+ imayer_fht(imag,n);
+}
+
+void imayer_ifft(int n, t_fixed *real, t_fixed *imag)
+{
+ t_fixed a,b,c,d;
+ t_fixed q,r,s,t;
+ int i,j,k;
+ imayer_fht(real,n);
+ imayer_fht(imag,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ imag[i] = (s+r)>>1; imag[j] = (s-r)>>1;
+ real[i] = (q-t)>>1; real[j] = (q+t)>>1;
+ }
+}
+
+void imayer_realfft(int n, t_fixed *real)
+{
+ t_fixed a,b,c,d;
+ int i,j,k;
+ imayer_fht(real,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b)>>1;
+ real[i] = (a+b)>>1;
+ }
+}
+
+void imayer_realifft(int n, t_fixed *real)
+{
+ t_fixed a,b,c,d;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b);
+ real[i] = (a+b);
+ }
+ imayer_fht(real,n);
+}
+
+
+
+#ifdef TEST
+
+static double dfcostab[TRIG_TAB_SIZE]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428,
+ .99999999971275670684941397221864177608908945791828,
+ .99999999992818917670977509588385049026048033310951
+ };
+static double dfsintab[TRIG_TAB_SIZE]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768,
+ .00002396844980841821872918657716502182009476147489,
+ .00001198422490506970642152156159698898480473197753
+ };
+
+static double dhalsec[TRIG_TAB_SIZE]=
+ {
+ 0,
+ 0,
+ .54119610014619698439972320536638942006107206337801,
+ .50979557910415916894193980398784391368261849190893,
+ .50241928618815570551167011928012092247859337193963,
+ .50060299823519630134550410676638239611758632599591,
+ .50015063602065098821477101271097658495974913010340,
+ .50003765191554772296778139077905492847503165398345,
+ .50000941253588775676512870469186533538523133757983,
+ .50000235310628608051401267171204408939326297376426,
+ .50000058827484117879868526730916804925780637276181,
+ .50000014706860214875463798283871198206179118093251,
+ .50000003676714377807315864400643020315103490883972,
+ .50000000919178552207366560348853455333939112569380,
+ .50000000229794635411562887767906868558991922348920,
+ .50000000057448658687873302235147272458812263401372,
+ .50000000014362164661654736863252589967935073278768,
+ .50000000003590541164769084922906986545517021050714
+ };
+
+
+#include <stdio.h>
+
+
+int writetables()
+{
+ int i;
+
+ printf("/* Tables for fixed point lookup with %d bit precision*/\n\n",fix1);
+
+ printf("static int fsintab[TRIG_TAB_SIZE]= {\n");
+
+ for (i=0;i<TRIG_TAB_SIZE-1;i++)
+ printf("%ld, \n",ftofix(dfsintab[i]));
+ printf("%ld }; \n",ftofix(dfsintab[i]));
+
+
+ printf("\n\nstatic int fcostab[TRIG_TAB_SIZE]= {\n");
+
+ for (i=0;i<TRIG_TAB_SIZE-1;i++)
+ printf("%ld, \n",ftofix(dfcostab[i]));
+ printf("%ld }; \n",ftofix(dfcostab[i]));
+
+}
+
+
+#define OUTPUT \
+ fprintf(stderr,"Integer - Float\n");\
+ for (i=0;i<NP;i++)\
+ fprintf(stderr,"%f %f --> %f %f\n",fixtof(r[i]),fixtof(im[i]),\
+ fr[i],fim[i]);\
+ fprintf(stderr,"\n\n");
+
+
+
+int main()
+{
+ int i;
+ t_fixed r[256];
+ t_fixed im[256];
+ float fr[256];
+ float fim[256];
+
+
+#if 1
+ writetables();
+ exit(0);
+#endif
+
+
+#if 0
+ t_fixed c1,s1,c2,s2,c3,s3;
+ int k;
+ int i;
+
+ TRIG_VARS;
+
+ for (k=2;k<10;k+=2) {
+ TRIG_INIT(k,c1,s1);
+ for (i=0;i<8;i++) {
+ TRIG_NEXT(k,c1,s1);
+ TRIG_23(k,c1,s1,c2,s2,c3,s3);
+ printf("TRIG value k=%d,%d val1 = %f %f\n",k,i,fixtof(c1),fixtof(s1));
+ }
+ }
+#endif
+
+
+
+#if 1
+
+ #define NP 16
+
+ for (i=0;i<NP;i++) {
+ fr[i] = 0.;
+ r[i] = 0.;
+ fim[i] = 0.;
+ im[i] = 0;
+ }
+
+#if 0
+ for (i=0;i<NP;i++) {
+ if (i&1) {
+ fr[i] = 0.1*i;
+ r[i] = ftofix(0.1*i);
+ }
+ else {
+ fr[i] = 0.;
+ r[i] = 0.;
+ }
+ }
+#endif
+#if 0
+ for (i=0;i<NP;i++) {
+ fr[i] = 0.1;
+ r[i] = ftofix(0.1);
+ }
+#endif
+
+ r[1] = ftofix(0.1);
+ fr[1] = 0.1;
+
+
+
+ /* TEST RUN */
+
+ OUTPUT
+
+ imayer_fft(NP,r,im);
+ mayer_fft(NP,fr,fim);
+// imayer_fht(r,NP);
+// mayer_fht(fr,NP);
+
+#if 1
+ for (i=0;i<NP;i++) {
+ r[i] = mult(ftofix(0.01),r[i]);
+ fr[i] = 0.01*fr[i];
+ }
+#endif
+
+ OUTPUT
+
+
+ imayer_fft(NP,r,im);
+ mayer_fft(NP,fr,fim);
+
+ OUTPUT
+
+
+#endif
+
+
+}
+
+#endif
+/*
+** Algorithm: complex multiplication
+**
+** Performance: Bad accuracy, great speed.
+**
+** The simplest, way of generating trig values. Note, this method is
+** not stable, and errors accumulate rapidly.
+**
+** Computation: 2 *, 1 + per value.
+*/
+
+
+#include "m_fixed.h"
+
+
+#define TRIG_FAST
+
+#ifdef TRIG_FAST
+char mtrig_algorithm[] = "Simple";
+#define TRIG_VARS \
+ t_fixed t_c,t_s;
+#define TRIG_INIT(k,c,s) \
+ { \
+ t_c = fcostab[k]; \
+ t_s = fsintab[k]; \
+ c = itofix(1); \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ t_fixed t = c; \
+ c = mult(t,t_c) - mult(s,t_s); \
+ s = mult(t,t_s) + mult(s,t_c); \
+ }
+#define TRIG_23(k,c1,s1,c2,s2,c3,s3) \
+ { \
+ c2 = mult(c1,c1) - mult(s1,s1); \
+ s2 = (mult(c1,s1)<<2); \
+ c3 = mult(c2,c1) - mult(s2,s1); \
+ s3 = mult(c2,s1) + mult(s2,c1); \
+ }
+#endif
+#define TRIG_RESET(k,c,s)
+
+/*
+** Algorithm: O. Buneman's trig generator.
+**
+** Performance: Good accuracy, mediocre speed.
+**
+** Manipulates a log(n) table to stably create n evenly spaced trig
+** values. The newly generated values lay halfway between two
+** known values, and are calculated by appropriatelly scaling the
+** average of the known trig values appropriatelly according to the
+** angle between them. This process is inherently stable; and is
+** about as accurate as most trig library functions. The errors
+** caused by this code segment are primarily due to the less stable
+** method to calculate values for 2t and s 3t. Note: I believe this
+** algorithm is patented(!), see readme file for more details.
+**
+** Computation: 1 +, 1 *, much integer math, per trig value
+**
+*/
+
+#ifdef TRIG_GOOD
+#define TRIG_VARS \
+ int t_lam=0; \
+ double coswrk[TRIG_TABLE_SIZE],sinwrk[TRIG_TABLE_SIZE];
+#define TRIG_INIT(k,c,s) \
+ { \
+ int i; \
+ for (i=0 ; i<=k ; i++) \
+ {coswrk[i]=fcostab[i];sinwrk[i]=fsintab[i];} \
+ t_lam = 0; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ int i,j; \
+ (t_lam)++; \
+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
+ i = k-i; \
+ s = sinwrk[i]; \
+ c = coswrk[i]; \
+ if (i>1) \
+ { \
+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
+ j = k - j; \
+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
+ } \
+ }
+#endif
+
+
+#define TRIG_TAB_SIZE 22
+
+static long long halsec[TRIG_TAB_SIZE]= {1,2,3};
+
+#define FFTmult(x,y) mult(x,y)
+
+
+
+
+#include "d_imayer_tables.h"
+
+#define SQRT2 ftofix(1.414213562373095048801688724209698)
+
+
+void imayer_fht(t_fixed *fz, int n)
+{
+ int k,k1,k2,k3,k4,kx;
+ t_fixed *fi,*fn,*gi;
+ TRIG_VARS;
+
+ for (k1=1,k2=0;k1<n;k1++)
+ {
+ t_fixed aa;
+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
+ if (k1>k2)
+ {
+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
+ }
+ }
+ for ( k=0 ; (1<<k)<n ; k++ );
+ k &= 1;
+ if (k==0)
+ {
+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
+ {
+ t_fixed f0,f1,f2,f3;
+ f1 = fi[0 ]-fi[1 ];
+ f0 = fi[0 ]+fi[1 ];
+ f3 = fi[2 ]-fi[3 ];
+ f2 = fi[2 ]+fi[3 ];
+ fi[2 ] = (f0-f2);
+ fi[0 ] = (f0+f2);
+ fi[3 ] = (f1-f3);
+ fi[1 ] = (f1+f3);
+ }
+ }
+ else
+ {
+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
+ {
+ t_fixed bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
+ bc1 = fi[0 ] - gi[0 ];
+ bs1 = fi[0 ] + gi[0 ];
+ bc2 = fi[2 ] - gi[2 ];
+ bs2 = fi[2 ] + gi[2 ];
+ bc3 = fi[4 ] - gi[4 ];
+ bs3 = fi[4 ] + gi[4 ];
+ bc4 = fi[6 ] - gi[6 ];
+ bs4 = fi[6 ] + gi[6 ];
+ bf1 = (bs1 - bs2);
+ bf0 = (bs1 + bs2);
+ bg1 = (bc1 - bc2);
+ bg0 = (bc1 + bc2);
+ bf3 = (bs3 - bs4);
+ bf2 = (bs3 + bs4);
+ bg3 = FFTmult(SQRT2,bc4);
+ bg2 = FFTmult(SQRT2,bc3);
+ fi[4 ] = bf0 - bf2;
+ fi[0 ] = bf0 + bf2;
+ fi[6 ] = bf1 - bf3;
+ fi[2 ] = bf1 + bf3;
+ gi[4 ] = bg0 - bg2;
+ gi[0 ] = bg0 + bg2;
+ gi[6 ] = bg1 - bg3;
+ gi[2 ] = bg1 + bg3;
+ }
+ }
+ if (n<16) return;
+
+ do
+ {
+ t_fixed s1,c1;
+ int ii;
+ k += 2;
+ k1 = 1 << k;
+ k2 = k1 << 1;
+ k4 = k2 << 1;
+ k3 = k2 + k1;
+ kx = k1 >> 1;
+ fi = fz;
+ gi = fi + kx;
+ fn = fz + n;
+ do
+ {
+ t_fixed g0,f0,f1,g1,f2,g2,f3,g3;
+ f1 = fi[0 ] - fi[k1];
+ f0 = fi[0 ] + fi[k1];
+ f3 = fi[k2] - fi[k3];
+ f2 = fi[k2] + fi[k3];
+ fi[k2] = f0 - f2;
+ fi[0 ] = f0 + f2;
+ fi[k3] = f1 - f3;
+ fi[k1] = f1 + f3;
+ g1 = gi[0 ] - gi[k1];
+ g0 = gi[0 ] + gi[k1];
+ g3 = FFTmult(SQRT2, gi[k3]);
+ g2 = FFTmult(SQRT2, gi[k2]);
+ gi[k2] = g0 - g2;
+ gi[0 ] = g0 + g2;
+ gi[k3] = g1 - g3;
+ gi[k1] = g1 + g3;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ TRIG_INIT(k,c1,s1);
+ for (ii=1;ii<kx;ii++)
+ {
+ t_fixed c2,s2;
+ TRIG_NEXT(k,c1,s1);
+ c2 = FFTmult(c1,c1) - FFTmult(s1,s1);
+ s2 = 2*FFTmult(c1,s1);
+ fn = fz + n;
+ fi = fz +ii;
+ gi = fz +k1-ii;
+ do
+ {
+ t_fixed a,b,g0,f0,f1,g1,f2,g2,f3,g3;
+ b = FFTmult(s2,fi[k1]) - FFTmult(c2,gi[k1]);
+ a = FFTmult(c2,fi[k1]) + FFTmult(s2,gi[k1]);
+ f1 = fi[0 ] - a;
+ f0 = fi[0 ] + a;
+ g1 = gi[0 ] - b;
+ g0 = gi[0 ] + b;
+ b = FFTmult(s2,fi[k3]) - FFTmult(c2,gi[k3]);
+ a = FFTmult(c2,fi[k3]) + FFTmult(s2,gi[k3]);
+ f3 = fi[k2] - a;
+ f2 = fi[k2] + a;
+ g3 = gi[k2] - b;
+ g2 = gi[k2] + b;
+ b = FFTmult(s1,f2) - FFTmult(c1,g3);
+ a = FFTmult(c1,f2) + FFTmult(s1,g3);
+ fi[k2] = f0 - a;
+ fi[0 ] = f0 + a;
+ gi[k3] = g1 - b;
+ gi[k1] = g1 + b;
+ b = FFTmult(c1,g2) - FFTmult(s1,f3);
+ a = FFTmult(s1,g2) + FFTmult(c1,f3);
+ gi[k2] = g0 - a;
+ gi[0 ] = g0 + a;
+ fi[k3] = f1 - b;
+ fi[k1] = f1 + b;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ }
+ TRIG_RESET(k,c1,s1);
+ } while (k4<n);
+}
+
+
+void imayer_fft(int n, t_fixed *real, t_fixed *imag)
+{
+ t_fixed a,b,c,d;
+ t_fixed q,r,s,t;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ real[i] = (q+t)>>1; real[j] = (q-t)>>1;
+ imag[i] = (s-r)>>1; imag[j] = (s+r)>>1;
+ }
+ imayer_fht(real,n);
+ imayer_fht(imag,n);
+}
+
+void imayer_ifft(int n, t_fixed *real, t_fixed *imag)
+{
+ t_fixed a,b,c,d;
+ t_fixed q,r,s,t;
+ int i,j,k;
+ imayer_fht(real,n);
+ imayer_fht(imag,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ imag[i] = (s+r)>>1; imag[j] = (s-r)>>1;
+ real[i] = (q-t)>>1; real[j] = (q+t)>>1;
+ }
+}
+
+void imayer_realfft(int n, t_fixed *real)
+{
+ t_fixed a,b,c,d;
+ int i,j,k;
+ imayer_fht(real,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b)>>1;
+ real[i] = (a+b)>>1;
+ }
+}
+
+void imayer_realifft(int n, t_fixed *real)
+{
+ t_fixed a,b,c,d;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b);
+ real[i] = (a+b);
+ }
+ imayer_fht(real,n);
+}
+
+
+
+#ifdef TEST
+
+static double dfcostab[TRIG_TAB_SIZE]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428,
+ .99999999971275670684941397221864177608908945791828,
+ .99999999992818917670977509588385049026048033310951
+ };
+static double dfsintab[TRIG_TAB_SIZE]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768,
+ .00002396844980841821872918657716502182009476147489,
+ .00001198422490506970642152156159698898480473197753
+ };
+
+static double dhalsec[TRIG_TAB_SIZE]=
+ {
+ 0,
+ 0,
+ .54119610014619698439972320536638942006107206337801,
+ .50979557910415916894193980398784391368261849190893,
+ .50241928618815570551167011928012092247859337193963,
+ .50060299823519630134550410676638239611758632599591,
+ .50015063602065098821477101271097658495974913010340,
+ .50003765191554772296778139077905492847503165398345,
+ .50000941253588775676512870469186533538523133757983,
+ .50000235310628608051401267171204408939326297376426,
+ .50000058827484117879868526730916804925780637276181,
+ .50000014706860214875463798283871198206179118093251,
+ .50000003676714377807315864400643020315103490883972,
+ .50000000919178552207366560348853455333939112569380,
+ .50000000229794635411562887767906868558991922348920,
+ .50000000057448658687873302235147272458812263401372,
+ .50000000014362164661654736863252589967935073278768,
+ .50000000003590541164769084922906986545517021050714
+ };
+
+
+#include <stdio.h>
+
+
+int writetables()
+{
+ int i;
+
+ printf("/* Tables for fixed point lookup with %d bit precision*/\n\n",fix1);
+
+ printf("static int fsintab[TRIG_TAB_SIZE]= {\n");
+
+ for (i=0;i<TRIG_TAB_SIZE-1;i++)
+ printf("%ld, \n",ftofix(dfsintab[i]));
+ printf("%ld }; \n",ftofix(dfsintab[i]));
+
+
+ printf("\n\nstatic int fcostab[TRIG_TAB_SIZE]= {\n");
+
+ for (i=0;i<TRIG_TAB_SIZE-1;i++)
+ printf("%ld, \n",ftofix(dfcostab[i]));
+ printf("%ld }; \n",ftofix(dfcostab[i]));
+
+}
+
+
+#define OUTPUT \
+ fprintf(stderr,"Integer - Float\n");\
+ for (i=0;i<NP;i++)\
+ fprintf(stderr,"%f %f --> %f %f\n",fixtof(r[i]),fixtof(im[i]),\
+ fr[i],fim[i]);\
+ fprintf(stderr,"\n\n");
+
+
+
+int main()
+{
+ int i;
+ t_fixed r[256];
+ t_fixed im[256];
+ float fr[256];
+ float fim[256];
+
+
+#if 1
+ writetables();
+ exit(0);
+#endif
+
+
+#if 0
+ t_fixed c1,s1,c2,s2,c3,s3;
+ int k;
+ int i;
+
+ TRIG_VARS;
+
+ for (k=2;k<10;k+=2) {
+ TRIG_INIT(k,c1,s1);
+ for (i=0;i<8;i++) {
+ TRIG_NEXT(k,c1,s1);
+ TRIG_23(k,c1,s1,c2,s2,c3,s3);
+ printf("TRIG value k=%d,%d val1 = %f %f\n",k,i,fixtof(c1),fixtof(s1));
+ }
+ }
+#endif
+
+
+
+#if 1
+
+ #define NP 16
+
+ for (i=0;i<NP;i++) {
+ fr[i] = 0.;
+ r[i] = 0.;
+ fim[i] = 0.;
+ im[i] = 0;
+ }
+
+#if 0
+ for (i=0;i<NP;i++) {
+ if (i&1) {
+ fr[i] = 0.1*i;
+ r[i] = ftofix(0.1*i);
+ }
+ else {
+ fr[i] = 0.;
+ r[i] = 0.;
+ }
+ }
+#endif
+#if 0
+ for (i=0;i<NP;i++) {
+ fr[i] = 0.1;
+ r[i] = ftofix(0.1);
+ }
+#endif
+
+ r[1] = ftofix(0.1);
+ fr[1] = 0.1;
+
+
+
+ /* TEST RUN */
+
+ OUTPUT
+
+ imayer_fft(NP,r,im);
+ mayer_fft(NP,fr,fim);
+// imayer_fht(r,NP);
+// mayer_fht(fr,NP);
+
+#if 1
+ for (i=0;i<NP;i++) {
+ r[i] = mult(ftofix(0.01),r[i]);
+ fr[i] = 0.01*fr[i];
+ }
+#endif
+
+ OUTPUT
+
+
+ imayer_fft(NP,r,im);
+ mayer_fft(NP,fr,fim);
+
+ OUTPUT
+
+
+#endif
+
+
+}
+
+#endif
diff --git a/apps/plugins/pdbox/PDa/src/d_imayer_tables.h b/apps/plugins/pdbox/PDa/src/d_imayer_tables.h
new file mode 100644
index 0000000000..e02d62490b
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_imayer_tables.h
@@ -0,0 +1,100 @@
+/* Tables for fixed point lookup with 18 bit precision*/
+
+static int fsintab[TRIG_TAB_SIZE]= {
+262144,
+185363,
+100318,
+51141,
+25694,
+12862,
+6433,
+3216,
+1608,
+804,
+402,
+201,
+100,
+50,
+25,
+12,
+6,
+3,
+0,
+0,
+0,
+0 };
+
+
+static int fcostab[TRIG_TAB_SIZE]= {
+0,
+185363,
+242189,
+257106,
+260881,
+261828,
+262065,
+262124,
+262139,
+262142,
+262143,
+262143,
+262143,
+262143,
+262143,
+262143,
+262143,
+262143,
+0,
+0,
+0,
+0 };
+/* Tables for fixed point lookup with 18 bit precision*/
+
+static int fsintab[TRIG_TAB_SIZE]= {
+262144,
+185363,
+100318,
+51141,
+25694,
+12862,
+6433,
+3216,
+1608,
+804,
+402,
+201,
+100,
+50,
+25,
+12,
+6,
+3,
+0,
+0,
+0,
+0 };
+
+
+static int fcostab[TRIG_TAB_SIZE]= {
+0,
+185363,
+242189,
+257106,
+260881,
+261828,
+262065,
+262124,
+262139,
+262142,
+262143,
+262143,
+262143,
+262143,
+262143,
+262143,
+262143,
+262143,
+0,
+0,
+0,
+0 };
diff --git a/apps/plugins/pdbox/PDa/src/d_math.c b/apps/plugins/pdbox/PDa/src/d_math.c
new file mode 100644
index 0000000000..ee8a96692c
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_math.c
@@ -0,0 +1,1146 @@
+/* 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. */
+
+/* mathematical functions and other transfer functions, including tilde
+ versions of stuff from x_acoustics.c.
+*/
+
+#include "m_pd.h"
+#include <math.h>
+#define LOGTEN 2.302585092994
+
+/* ------------------------- clip~ -------------------------- */
+static t_class *clip_class;
+
+typedef struct _clip
+{
+ t_object x_obj;
+ float x_f;
+ t_sample x_lo;
+ t_sample x_hi;
+} t_clip;
+
+static void *clip_new(t_floatarg lo, t_floatarg hi)
+{
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ x->x_lo = lo;
+ x->x_hi = hi;
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_lo);
+ floatinlet_new(&x->x_obj, &x->x_hi);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *clip_perform(t_int *w)
+{
+ t_clip *x = (t_clip *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ float f = *in++;
+ if (f < x->x_lo) f = x->x_lo;
+ if (f > x->x_hi) f = x->x_hi;
+ *out++ = f;
+ }
+ return (w+5);
+}
+
+static void clip_dsp(t_clip *x, t_signal **sp)
+{
+ dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void clip_setup(void)
+{
+ clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
+ sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
+ class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
+}
+
+/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
+
+#define DUMTAB1SIZE 256
+#define DUMTAB2SIZE 1024
+
+static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
+
+static void init_rsqrt(void)
+{
+ int i;
+ for (i = 0; i < DUMTAB1SIZE; i++)
+ {
+ float f;
+ long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
+ *(long *)(&f) = l;
+ rsqrt_exptab[i] = 1./sqrt(f);
+ }
+ for (i = 0; i < DUMTAB2SIZE; i++)
+ {
+ float f = 1 + (1./DUMTAB2SIZE) * i;
+ rsqrt_mantissatab[i] = 1./sqrt(f);
+ }
+}
+
+ /* these are used in externs like "bonk" */
+
+float q8_rsqrt(float f)
+{
+ long l = *(long *)(&f);
+ if (f < 0) return (0);
+ else return (rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff]);
+}
+
+float q8_sqrt(float f)
+{
+ long l = *(long *)(&f);
+ if (f < 0) return (0);
+ else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff]);
+}
+
+ /* 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)); }
+#endif
+
+
+
+typedef struct sigrsqrt
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrsqrt;
+
+static t_class *sigrsqrt_class;
+
+static void *sigrsqrt_new(void)
+{
+ t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrsqrt_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else
+ {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = 1.5 * g - 0.5 * g * g * g * f;
+ }
+ }
+ return (w + 4);
+}
+
+static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
+{
+ dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigrsqrt_setup(void)
+{
+ init_rsqrt();
+ sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
+ sizeof(t_sigrsqrt), 0, 0);
+ /* an old name for it: */
+ class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
+ CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
+ class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
+}
+
+
+/* sigsqrt - square root good to 8 mantissa bits */
+
+typedef struct sigsqrt
+{
+ t_object x_obj;
+ float x_f;
+} t_sigsqrt;
+
+static t_class *sigsqrt_class;
+
+static void *sigsqrt_new(void)
+{
+ t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else
+ {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
+ }
+ }
+ return (w + 4);
+}
+
+static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
+{
+ dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigsqrt_setup(void)
+{
+ sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
+ sizeof(t_sigsqrt), 0, 0);
+ class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
+ CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
+ class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ wrap~ -------------------------- */
+
+typedef struct wrap
+{
+ t_object x_obj;
+ float x_f;
+} t_sigwrap;
+
+t_class *sigwrap_class;
+
+static void *sigwrap_new(void)
+{
+ t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigwrap_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in++;
+ int k = f;
+ if (f > 0) *out++ = f-k;
+ else *out++ = f - (k-1);
+ }
+ return (w + 4);
+}
+
+static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
+{
+ dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigwrap_setup(void)
+{
+ sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
+ sizeof(t_sigwrap), 0, 0);
+ CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
+ class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ mtof_tilde~ -------------------------- */
+
+typedef struct mtof_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_mtof_tilde;
+
+t_class *mtof_tilde_class;
+
+static void *mtof_tilde_new(void)
+{
+ t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *mtof_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= -1500) *out = 0;
+ else
+ {
+ if (f > 1499) f = 1499;
+ *out = 8.17579891564 * exp(.0577622650 * f);
+ }
+ }
+ return (w + 4);
+}
+
+static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
+{
+ dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void mtof_tilde_setup(void)
+{
+ mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
+ sizeof(t_mtof_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
+ class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ ftom_tilde~ -------------------------- */
+
+typedef struct ftom_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_ftom_tilde;
+
+t_class *ftom_tilde_class;
+
+static void *ftom_tilde_new(void)
+{
+ t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *ftom_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; *in++, out++)
+ {
+ float f = *in;
+ *out = (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
+ }
+ return (w + 4);
+}
+
+static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
+{
+ dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void ftom_tilde_setup(void)
+{
+ ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
+ sizeof(t_ftom_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
+ class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ dbtorms~ -------------------------- */
+
+typedef struct dbtorms_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_dbtorms_tilde;
+
+t_class *dbtorms_tilde_class;
+
+static void *dbtorms_tilde_new(void)
+{
+ t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *dbtorms_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ if (f > 485)
+ f = 485;
+ *out = exp((LOGTEN * 0.05) * (f-100.));
+ }
+ }
+ return (w + 4);
+}
+
+static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
+{
+ dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void dbtorms_tilde_setup(void)
+{
+ dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
+ sizeof(t_dbtorms_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
+ class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ rmstodb~ -------------------------- */
+
+typedef struct rmstodb_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_rmstodb_tilde;
+
+t_class *rmstodb_tilde_class;
+
+static void *rmstodb_tilde_new(void)
+{
+ t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *rmstodb_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ float g = 100 + 20./LOGTEN * log(f);
+ *out = (g < 0 ? 0 : g);
+ }
+ }
+ return (w + 4);
+}
+
+static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
+{
+ dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void rmstodb_tilde_setup(void)
+{
+ rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
+ sizeof(t_rmstodb_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
+ class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ dbtopow~ -------------------------- */
+
+typedef struct dbtopow_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_dbtopow_tilde;
+
+t_class *dbtopow_tilde_class;
+
+static void *dbtopow_tilde_new(void)
+{
+ t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *dbtopow_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ if (f > 870)
+ f = 870;
+ *out = exp((LOGTEN * 0.1) * (f-100.));
+ }
+ }
+ return (w + 4);
+}
+
+static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
+{
+ dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void dbtopow_tilde_setup(void)
+{
+ dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
+ sizeof(t_dbtopow_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
+ class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ powtodb~ -------------------------- */
+
+typedef struct powtodb_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_powtodb_tilde;
+
+t_class *powtodb_tilde_class;
+
+static void *powtodb_tilde_new(void)
+{
+ t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *powtodb_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ float g = 100 + 10./LOGTEN * log(f);
+ *out = (g < 0 ? 0 : g);
+ }
+ }
+ return (w + 4);
+}
+
+static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
+{
+ dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void powtodb_tilde_setup(void)
+{
+ powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
+ sizeof(t_powtodb_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
+ class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
+}
+
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_math_setup(void)
+{
+ t_symbol *s = gensym("acoustics~.pd");
+ clip_setup();
+ sigrsqrt_setup();
+ sigsqrt_setup();
+ sigwrap_setup();
+ mtof_tilde_setup();
+ ftom_tilde_setup();
+ dbtorms_tilde_setup();
+ rmstodb_tilde_setup();
+ dbtopow_tilde_setup();
+ powtodb_tilde_setup();
+
+ class_sethelpsymbol(mtof_tilde_class, s);
+ class_sethelpsymbol(ftom_tilde_class, s);
+ class_sethelpsymbol(dbtorms_tilde_class, s);
+ class_sethelpsymbol(rmstodb_tilde_class, s);
+ class_sethelpsymbol(dbtopow_tilde_class, s);
+ class_sethelpsymbol(powtodb_tilde_class, s);
+}
+
+/* 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. */
+
+/* mathematical functions and other transfer functions, including tilde
+ versions of stuff from x_acoustics.c.
+*/
+
+#include "m_pd.h"
+#include <math.h>
+#define LOGTEN 2.302585092994
+
+/* ------------------------- clip~ -------------------------- */
+static t_class *clip_class;
+
+typedef struct _clip
+{
+ t_object x_obj;
+ float x_f;
+ t_sample x_lo;
+ t_sample x_hi;
+} t_clip;
+
+static void *clip_new(t_floatarg lo, t_floatarg hi)
+{
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ x->x_lo = lo;
+ x->x_hi = hi;
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_lo);
+ floatinlet_new(&x->x_obj, &x->x_hi);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *clip_perform(t_int *w)
+{
+ t_clip *x = (t_clip *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ float f = *in++;
+ if (f < x->x_lo) f = x->x_lo;
+ if (f > x->x_hi) f = x->x_hi;
+ *out++ = f;
+ }
+ return (w+5);
+}
+
+static void clip_dsp(t_clip *x, t_signal **sp)
+{
+ dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void clip_setup(void)
+{
+ clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
+ sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
+ class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
+}
+
+/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
+
+#define DUMTAB1SIZE 256
+#define DUMTAB2SIZE 1024
+
+static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
+
+static void init_rsqrt(void)
+{
+ int i;
+ for (i = 0; i < DUMTAB1SIZE; i++)
+ {
+ float f;
+ long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
+ *(long *)(&f) = l;
+ rsqrt_exptab[i] = 1./sqrt(f);
+ }
+ for (i = 0; i < DUMTAB2SIZE; i++)
+ {
+ float f = 1 + (1./DUMTAB2SIZE) * i;
+ rsqrt_mantissatab[i] = 1./sqrt(f);
+ }
+}
+
+ /* these are used in externs like "bonk" */
+
+float q8_rsqrt(float f)
+{
+ long l = *(long *)(&f);
+ if (f < 0) return (0);
+ else return (rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff]);
+}
+
+float q8_sqrt(float f)
+{
+ long l = *(long *)(&f);
+ if (f < 0) return (0);
+ else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff]);
+}
+
+ /* 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)); }
+#endif
+
+
+
+typedef struct sigrsqrt
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrsqrt;
+
+static t_class *sigrsqrt_class;
+
+static void *sigrsqrt_new(void)
+{
+ t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrsqrt_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else
+ {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = 1.5 * g - 0.5 * g * g * g * f;
+ }
+ }
+ return (w + 4);
+}
+
+static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
+{
+ dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigrsqrt_setup(void)
+{
+ init_rsqrt();
+ sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
+ sizeof(t_sigrsqrt), 0, 0);
+ /* an old name for it: */
+ class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
+ CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
+ class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
+}
+
+
+/* sigsqrt - square root good to 8 mantissa bits */
+
+typedef struct sigsqrt
+{
+ t_object x_obj;
+ float x_f;
+} t_sigsqrt;
+
+static t_class *sigsqrt_class;
+
+static void *sigsqrt_new(void)
+{
+ t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else
+ {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
+ }
+ }
+ return (w + 4);
+}
+
+static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
+{
+ dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigsqrt_setup(void)
+{
+ sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
+ sizeof(t_sigsqrt), 0, 0);
+ class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
+ CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
+ class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ wrap~ -------------------------- */
+
+typedef struct wrap
+{
+ t_object x_obj;
+ float x_f;
+} t_sigwrap;
+
+t_class *sigwrap_class;
+
+static void *sigwrap_new(void)
+{
+ t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigwrap_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in++;
+ int k = f;
+ if (f > 0) *out++ = f-k;
+ else *out++ = f - (k-1);
+ }
+ return (w + 4);
+}
+
+static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
+{
+ dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigwrap_setup(void)
+{
+ sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
+ sizeof(t_sigwrap), 0, 0);
+ CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
+ class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ mtof_tilde~ -------------------------- */
+
+typedef struct mtof_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_mtof_tilde;
+
+t_class *mtof_tilde_class;
+
+static void *mtof_tilde_new(void)
+{
+ t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *mtof_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= -1500) *out = 0;
+ else
+ {
+ if (f > 1499) f = 1499;
+ *out = 8.17579891564 * exp(.0577622650 * f);
+ }
+ }
+ return (w + 4);
+}
+
+static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
+{
+ dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void mtof_tilde_setup(void)
+{
+ mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
+ sizeof(t_mtof_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
+ class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ ftom_tilde~ -------------------------- */
+
+typedef struct ftom_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_ftom_tilde;
+
+t_class *ftom_tilde_class;
+
+static void *ftom_tilde_new(void)
+{
+ t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *ftom_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; *in++, out++)
+ {
+ float f = *in;
+ *out = (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
+ }
+ return (w + 4);
+}
+
+static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
+{
+ dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void ftom_tilde_setup(void)
+{
+ ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
+ sizeof(t_ftom_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
+ class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ dbtorms~ -------------------------- */
+
+typedef struct dbtorms_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_dbtorms_tilde;
+
+t_class *dbtorms_tilde_class;
+
+static void *dbtorms_tilde_new(void)
+{
+ t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *dbtorms_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ if (f > 485)
+ f = 485;
+ *out = exp((LOGTEN * 0.05) * (f-100.));
+ }
+ }
+ return (w + 4);
+}
+
+static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
+{
+ dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void dbtorms_tilde_setup(void)
+{
+ dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
+ sizeof(t_dbtorms_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
+ class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ rmstodb~ -------------------------- */
+
+typedef struct rmstodb_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_rmstodb_tilde;
+
+t_class *rmstodb_tilde_class;
+
+static void *rmstodb_tilde_new(void)
+{
+ t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *rmstodb_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ float g = 100 + 20./LOGTEN * log(f);
+ *out = (g < 0 ? 0 : g);
+ }
+ }
+ return (w + 4);
+}
+
+static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
+{
+ dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void rmstodb_tilde_setup(void)
+{
+ rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
+ sizeof(t_rmstodb_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
+ class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ dbtopow~ -------------------------- */
+
+typedef struct dbtopow_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_dbtopow_tilde;
+
+t_class *dbtopow_tilde_class;
+
+static void *dbtopow_tilde_new(void)
+{
+ t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *dbtopow_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ if (f > 870)
+ f = 870;
+ *out = exp((LOGTEN * 0.1) * (f-100.));
+ }
+ }
+ return (w + 4);
+}
+
+static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
+{
+ dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void dbtopow_tilde_setup(void)
+{
+ dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
+ sizeof(t_dbtopow_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
+ class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ powtodb~ -------------------------- */
+
+typedef struct powtodb_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_powtodb_tilde;
+
+t_class *powtodb_tilde_class;
+
+static void *powtodb_tilde_new(void)
+{
+ t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *powtodb_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ float g = 100 + 10./LOGTEN * log(f);
+ *out = (g < 0 ? 0 : g);
+ }
+ }
+ return (w + 4);
+}
+
+static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
+{
+ dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void powtodb_tilde_setup(void)
+{
+ powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
+ sizeof(t_powtodb_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
+ class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
+}
+
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_math_setup(void)
+{
+ t_symbol *s = gensym("acoustics~.pd");
+ clip_setup();
+ sigrsqrt_setup();
+ sigsqrt_setup();
+ sigwrap_setup();
+ mtof_tilde_setup();
+ ftom_tilde_setup();
+ dbtorms_tilde_setup();
+ rmstodb_tilde_setup();
+ dbtopow_tilde_setup();
+ powtodb_tilde_setup();
+
+ class_sethelpsymbol(mtof_tilde_class, s);
+ class_sethelpsymbol(ftom_tilde_class, s);
+ class_sethelpsymbol(dbtorms_tilde_class, s);
+ class_sethelpsymbol(rmstodb_tilde_class, s);
+ class_sethelpsymbol(dbtopow_tilde_class, s);
+ class_sethelpsymbol(powtodb_tilde_class, s);
+}
+
diff --git a/apps/plugins/pdbox/PDa/src/d_mayer_fft.c b/apps/plugins/pdbox/PDa/src/d_mayer_fft.c
new file mode 100644
index 0000000000..7c29c6e7c8
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_mayer_fft.c
@@ -0,0 +1,838 @@
+/*
+** FFT and FHT routines
+** Copyright 1988, 1993; Ron Mayer
+**
+** mayer_fht(fz,n);
+** Does a hartley transform of "n" points in the array "fz".
+** mayer_fft(n,real,imag)
+** Does a fourier transform of "n" points of the "real" and
+** "imag" arrays.
+** mayer_ifft(n,real,imag)
+** Does an inverse fourier transform of "n" points of the "real"
+** and "imag" arrays.
+** mayer_realfft(n,real)
+** Does a real-valued fourier transform of "n" points of the
+** "real" array. The real part of the transform ends
+** up in the first half of the array and the imaginary part of the
+** transform ends up in the second half of the array.
+** mayer_realifft(n,real)
+** The inverse of the realfft() routine above.
+**
+**
+** NOTE: This routine uses at least 2 patented algorithms, and may be
+** under the restrictions of a bunch of different organizations.
+** Although I wrote it completely myself, it is kind of a derivative
+** of a routine I once authored and released under the GPL, so it
+** may fall under the free software foundation's restrictions;
+** it was worked on as a Stanford Univ project, so they claim
+** some rights to it; it was further optimized at work here, so
+** I think this company claims parts of it. The patents are
+** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
+** trig generator), both at Stanford Univ.
+** If it were up to me, I'd say go do whatever you want with it;
+** but it would be polite to give credit to the following people
+** if you use this anywhere:
+** Euler - probable inventor of the fourier transform.
+** Gauss - probable inventor of the FFT.
+** Hartley - probable inventor of the hartley transform.
+** Buneman - for a really cool trig generator
+** Mayer(me) - for authoring this particular version and
+** including all the optimizations in one package.
+** Thanks,
+** Ron Mayer; mayer@acuson.com
+**
+*/
+
+/* This is a slightly modified version of Mayer's contribution; write
+* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
+* of work. -msp
+*/
+
+#ifdef MSW
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast double to float */
+#pragma warning( disable : 4101 ) /* unused local variables */
+#endif
+
+#define REAL float
+#define GOOD_TRIG
+
+#ifdef GOOD_TRIG
+#else
+#define FAST_TRIG
+#endif
+
+#if defined(GOOD_TRIG)
+#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
+#define TRIG_VARS \
+ int t_lam=0;
+#define TRIG_INIT(k,c,s) \
+ { \
+ int i; \
+ for (i=2 ; i<=k ; i++) \
+ {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
+ t_lam = 0; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ int i,j; \
+ (t_lam)++; \
+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
+ i = k-i; \
+ s = sinwrk[i]; \
+ c = coswrk[i]; \
+ if (i>1) \
+ { \
+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
+ j = k - j; \
+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
+ } \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+#if defined(FAST_TRIG)
+#define TRIG_VARS \
+ REAL t_c,t_s;
+#define TRIG_INIT(k,c,s) \
+ { \
+ t_c = costab[k]; \
+ t_s = sintab[k]; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ REAL t = c; \
+ c = t*t_c - s*t_s; \
+ s = t*t_s + s*t_c; \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+static REAL halsec[20]=
+ {
+ 0,
+ 0,
+ .54119610014619698439972320536638942006107206337801,
+ .50979557910415916894193980398784391368261849190893,
+ .50241928618815570551167011928012092247859337193963,
+ .50060299823519630134550410676638239611758632599591,
+ .50015063602065098821477101271097658495974913010340,
+ .50003765191554772296778139077905492847503165398345,
+ .50000941253588775676512870469186533538523133757983,
+ .50000235310628608051401267171204408939326297376426,
+ .50000058827484117879868526730916804925780637276181,
+ .50000014706860214875463798283871198206179118093251,
+ .50000003676714377807315864400643020315103490883972,
+ .50000000919178552207366560348853455333939112569380,
+ .50000000229794635411562887767906868558991922348920,
+ .50000000057448658687873302235147272458812263401372
+ };
+static REAL costab[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sintab[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+static REAL coswrk[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sinwrk[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+
+
+#define SQRT2_2 0.70710678118654752440084436210484
+#define SQRT2 2*0.70710678118654752440084436210484
+
+void mayer_fht(REAL *fz, int n)
+{
+/* REAL a,b;
+REAL c1,s1,s2,c2,s3,c3,s4,c4;
+ REAL f0,g0,f1,g1,f2,g2,f3,g3; */
+ int k,k1,k2,k3,k4,kx;
+ REAL *fi,*fn,*gi;
+ TRIG_VARS;
+
+ for (k1=1,k2=0;k1<n;k1++)
+ {
+ REAL aa;
+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
+ if (k1>k2)
+ {
+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
+ }
+ }
+ for ( k=0 ; (1<<k)<n ; k++ );
+ k &= 1;
+ if (k==0)
+ {
+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
+ {
+ REAL f0,f1,f2,f3;
+ f1 = fi[0 ]-fi[1 ];
+ f0 = fi[0 ]+fi[1 ];
+ f3 = fi[2 ]-fi[3 ];
+ f2 = fi[2 ]+fi[3 ];
+ fi[2 ] = (f0-f2);
+ fi[0 ] = (f0+f2);
+ fi[3 ] = (f1-f3);
+ fi[1 ] = (f1+f3);
+ }
+ }
+ else
+ {
+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
+ {
+ REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
+ bc1 = fi[0 ] - gi[0 ];
+ bs1 = fi[0 ] + gi[0 ];
+ bc2 = fi[2 ] - gi[2 ];
+ bs2 = fi[2 ] + gi[2 ];
+ bc3 = fi[4 ] - gi[4 ];
+ bs3 = fi[4 ] + gi[4 ];
+ bc4 = fi[6 ] - gi[6 ];
+ bs4 = fi[6 ] + gi[6 ];
+ bf1 = (bs1 - bs2);
+ bf0 = (bs1 + bs2);
+ bg1 = (bc1 - bc2);
+ bg0 = (bc1 + bc2);
+ bf3 = (bs3 - bs4);
+ bf2 = (bs3 + bs4);
+ bg3 = SQRT2*bc4;
+ bg2 = SQRT2*bc3;
+ fi[4 ] = bf0 - bf2;
+ fi[0 ] = bf0 + bf2;
+ fi[6 ] = bf1 - bf3;
+ fi[2 ] = bf1 + bf3;
+ gi[4 ] = bg0 - bg2;
+ gi[0 ] = bg0 + bg2;
+ gi[6 ] = bg1 - bg3;
+ gi[2 ] = bg1 + bg3;
+ }
+ }
+ if (n<16) return;
+
+ do
+ {
+ REAL s1,c1;
+ int ii;
+ k += 2;
+ k1 = 1 << k;
+ k2 = k1 << 1;
+ k4 = k2 << 1;
+ k3 = k2 + k1;
+ kx = k1 >> 1;
+ fi = fz;
+ gi = fi + kx;
+ fn = fz + n;
+ do
+ {
+ REAL g0,f0,f1,g1,f2,g2,f3,g3;
+ f1 = fi[0 ] - fi[k1];
+ f0 = fi[0 ] + fi[k1];
+ f3 = fi[k2] - fi[k3];
+ f2 = fi[k2] + fi[k3];
+ fi[k2] = f0 - f2;
+ fi[0 ] = f0 + f2;
+ fi[k3] = f1 - f3;
+ fi[k1] = f1 + f3;
+ g1 = gi[0 ] - gi[k1];
+ g0 = gi[0 ] + gi[k1];
+ g3 = SQRT2 * gi[k3];
+ g2 = SQRT2 * gi[k2];
+ gi[k2] = g0 - g2;
+ gi[0 ] = g0 + g2;
+ gi[k3] = g1 - g3;
+ gi[k1] = g1 + g3;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ TRIG_INIT(k,c1,s1);
+ for (ii=1;ii<kx;ii++)
+ {
+ REAL c2,s2;
+ TRIG_NEXT(k,c1,s1);
+ c2 = c1*c1 - s1*s1;
+ s2 = 2*(c1*s1);
+ fn = fz + n;
+ fi = fz +ii;
+ gi = fz +k1-ii;
+ do
+ {
+ REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
+ b = s2*fi[k1] - c2*gi[k1];
+ a = c2*fi[k1] + s2*gi[k1];
+ f1 = fi[0 ] - a;
+ f0 = fi[0 ] + a;
+ g1 = gi[0 ] - b;
+ g0 = gi[0 ] + b;
+ b = s2*fi[k3] - c2*gi[k3];
+ a = c2*fi[k3] + s2*gi[k3];
+ f3 = fi[k2] - a;
+ f2 = fi[k2] + a;
+ g3 = gi[k2] - b;
+ g2 = gi[k2] + b;
+ b = s1*f2 - c1*g3;
+ a = c1*f2 + s1*g3;
+ fi[k2] = f0 - a;
+ fi[0 ] = f0 + a;
+ gi[k3] = g1 - b;
+ gi[k1] = g1 + b;
+ b = c1*g2 - s1*f3;
+ a = s1*g2 + c1*f3;
+ gi[k2] = g0 - a;
+ gi[0 ] = g0 + a;
+ fi[k3] = f1 - b;
+ fi[k1] = f1 + b;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ }
+ TRIG_RESET(k,c1,s1);
+ } while (k4<n);
+}
+
+void mayer_fft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ real[i] = (q+t)*.5; real[j] = (q-t)*.5;
+ imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
+ }
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+}
+
+void mayer_ifft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
+ real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
+ }
+}
+
+void mayer_realfft(int n, REAL *real)
+{
+ REAL a,b,c,d;
+ int i,j,k;
+ mayer_fht(real,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b)*0.5;
+ real[i] = (a+b)*0.5;
+ }
+}
+
+void mayer_realifft(int n, REAL *real)
+{
+ REAL a,b,c,d;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b);
+ real[i] = (a+b);
+ }
+ mayer_fht(real,n);
+}
+/*
+** FFT and FHT routines
+** Copyright 1988, 1993; Ron Mayer
+**
+** mayer_fht(fz,n);
+** Does a hartley transform of "n" points in the array "fz".
+** mayer_fft(n,real,imag)
+** Does a fourier transform of "n" points of the "real" and
+** "imag" arrays.
+** mayer_ifft(n,real,imag)
+** Does an inverse fourier transform of "n" points of the "real"
+** and "imag" arrays.
+** mayer_realfft(n,real)
+** Does a real-valued fourier transform of "n" points of the
+** "real" array. The real part of the transform ends
+** up in the first half of the array and the imaginary part of the
+** transform ends up in the second half of the array.
+** mayer_realifft(n,real)
+** The inverse of the realfft() routine above.
+**
+**
+** NOTE: This routine uses at least 2 patented algorithms, and may be
+** under the restrictions of a bunch of different organizations.
+** Although I wrote it completely myself, it is kind of a derivative
+** of a routine I once authored and released under the GPL, so it
+** may fall under the free software foundation's restrictions;
+** it was worked on as a Stanford Univ project, so they claim
+** some rights to it; it was further optimized at work here, so
+** I think this company claims parts of it. The patents are
+** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
+** trig generator), both at Stanford Univ.
+** If it were up to me, I'd say go do whatever you want with it;
+** but it would be polite to give credit to the following people
+** if you use this anywhere:
+** Euler - probable inventor of the fourier transform.
+** Gauss - probable inventor of the FFT.
+** Hartley - probable inventor of the hartley transform.
+** Buneman - for a really cool trig generator
+** Mayer(me) - for authoring this particular version and
+** including all the optimizations in one package.
+** Thanks,
+** Ron Mayer; mayer@acuson.com
+**
+*/
+
+/* This is a slightly modified version of Mayer's contribution; write
+* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
+* of work. -msp
+*/
+
+#ifdef MSW
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast double to float */
+#pragma warning( disable : 4101 ) /* unused local variables */
+#endif
+
+#define REAL float
+#define GOOD_TRIG
+
+#ifdef GOOD_TRIG
+#else
+#define FAST_TRIG
+#endif
+
+#if defined(GOOD_TRIG)
+#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
+#define TRIG_VARS \
+ int t_lam=0;
+#define TRIG_INIT(k,c,s) \
+ { \
+ int i; \
+ for (i=2 ; i<=k ; i++) \
+ {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
+ t_lam = 0; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ int i,j; \
+ (t_lam)++; \
+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
+ i = k-i; \
+ s = sinwrk[i]; \
+ c = coswrk[i]; \
+ if (i>1) \
+ { \
+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
+ j = k - j; \
+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
+ } \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+#if defined(FAST_TRIG)
+#define TRIG_VARS \
+ REAL t_c,t_s;
+#define TRIG_INIT(k,c,s) \
+ { \
+ t_c = costab[k]; \
+ t_s = sintab[k]; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ REAL t = c; \
+ c = t*t_c - s*t_s; \
+ s = t*t_s + s*t_c; \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+static REAL halsec[20]=
+ {
+ 0,
+ 0,
+ .54119610014619698439972320536638942006107206337801,
+ .50979557910415916894193980398784391368261849190893,
+ .50241928618815570551167011928012092247859337193963,
+ .50060299823519630134550410676638239611758632599591,
+ .50015063602065098821477101271097658495974913010340,
+ .50003765191554772296778139077905492847503165398345,
+ .50000941253588775676512870469186533538523133757983,
+ .50000235310628608051401267171204408939326297376426,
+ .50000058827484117879868526730916804925780637276181,
+ .50000014706860214875463798283871198206179118093251,
+ .50000003676714377807315864400643020315103490883972,
+ .50000000919178552207366560348853455333939112569380,
+ .50000000229794635411562887767906868558991922348920,
+ .50000000057448658687873302235147272458812263401372
+ };
+static REAL costab[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sintab[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+static REAL coswrk[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sinwrk[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+
+
+#define SQRT2_2 0.70710678118654752440084436210484
+#define SQRT2 2*0.70710678118654752440084436210484
+
+void mayer_fht(REAL *fz, int n)
+{
+/* REAL a,b;
+REAL c1,s1,s2,c2,s3,c3,s4,c4;
+ REAL f0,g0,f1,g1,f2,g2,f3,g3; */
+ int k,k1,k2,k3,k4,kx;
+ REAL *fi,*fn,*gi;
+ TRIG_VARS;
+
+ for (k1=1,k2=0;k1<n;k1++)
+ {
+ REAL aa;
+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
+ if (k1>k2)
+ {
+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
+ }
+ }
+ for ( k=0 ; (1<<k)<n ; k++ );
+ k &= 1;
+ if (k==0)
+ {
+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
+ {
+ REAL f0,f1,f2,f3;
+ f1 = fi[0 ]-fi[1 ];
+ f0 = fi[0 ]+fi[1 ];
+ f3 = fi[2 ]-fi[3 ];
+ f2 = fi[2 ]+fi[3 ];
+ fi[2 ] = (f0-f2);
+ fi[0 ] = (f0+f2);
+ fi[3 ] = (f1-f3);
+ fi[1 ] = (f1+f3);
+ }
+ }
+ else
+ {
+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
+ {
+ REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
+ bc1 = fi[0 ] - gi[0 ];
+ bs1 = fi[0 ] + gi[0 ];
+ bc2 = fi[2 ] - gi[2 ];
+ bs2 = fi[2 ] + gi[2 ];
+ bc3 = fi[4 ] - gi[4 ];
+ bs3 = fi[4 ] + gi[4 ];
+ bc4 = fi[6 ] - gi[6 ];
+ bs4 = fi[6 ] + gi[6 ];
+ bf1 = (bs1 - bs2);
+ bf0 = (bs1 + bs2);
+ bg1 = (bc1 - bc2);
+ bg0 = (bc1 + bc2);
+ bf3 = (bs3 - bs4);
+ bf2 = (bs3 + bs4);
+ bg3 = SQRT2*bc4;
+ bg2 = SQRT2*bc3;
+ fi[4 ] = bf0 - bf2;
+ fi[0 ] = bf0 + bf2;
+ fi[6 ] = bf1 - bf3;
+ fi[2 ] = bf1 + bf3;
+ gi[4 ] = bg0 - bg2;
+ gi[0 ] = bg0 + bg2;
+ gi[6 ] = bg1 - bg3;
+ gi[2 ] = bg1 + bg3;
+ }
+ }
+ if (n<16) return;
+
+ do
+ {
+ REAL s1,c1;
+ int ii;
+ k += 2;
+ k1 = 1 << k;
+ k2 = k1 << 1;
+ k4 = k2 << 1;
+ k3 = k2 + k1;
+ kx = k1 >> 1;
+ fi = fz;
+ gi = fi + kx;
+ fn = fz + n;
+ do
+ {
+ REAL g0,f0,f1,g1,f2,g2,f3,g3;
+ f1 = fi[0 ] - fi[k1];
+ f0 = fi[0 ] + fi[k1];
+ f3 = fi[k2] - fi[k3];
+ f2 = fi[k2] + fi[k3];
+ fi[k2] = f0 - f2;
+ fi[0 ] = f0 + f2;
+ fi[k3] = f1 - f3;
+ fi[k1] = f1 + f3;
+ g1 = gi[0 ] - gi[k1];
+ g0 = gi[0 ] + gi[k1];
+ g3 = SQRT2 * gi[k3];
+ g2 = SQRT2 * gi[k2];
+ gi[k2] = g0 - g2;
+ gi[0 ] = g0 + g2;
+ gi[k3] = g1 - g3;
+ gi[k1] = g1 + g3;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ TRIG_INIT(k,c1,s1);
+ for (ii=1;ii<kx;ii++)
+ {
+ REAL c2,s2;
+ TRIG_NEXT(k,c1,s1);
+ c2 = c1*c1 - s1*s1;
+ s2 = 2*(c1*s1);
+ fn = fz + n;
+ fi = fz +ii;
+ gi = fz +k1-ii;
+ do
+ {
+ REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
+ b = s2*fi[k1] - c2*gi[k1];
+ a = c2*fi[k1] + s2*gi[k1];
+ f1 = fi[0 ] - a;
+ f0 = fi[0 ] + a;
+ g1 = gi[0 ] - b;
+ g0 = gi[0 ] + b;
+ b = s2*fi[k3] - c2*gi[k3];
+ a = c2*fi[k3] + s2*gi[k3];
+ f3 = fi[k2] - a;
+ f2 = fi[k2] + a;
+ g3 = gi[k2] - b;
+ g2 = gi[k2] + b;
+ b = s1*f2 - c1*g3;
+ a = c1*f2 + s1*g3;
+ fi[k2] = f0 - a;
+ fi[0 ] = f0 + a;
+ gi[k3] = g1 - b;
+ gi[k1] = g1 + b;
+ b = c1*g2 - s1*f3;
+ a = s1*g2 + c1*f3;
+ gi[k2] = g0 - a;
+ gi[0 ] = g0 + a;
+ fi[k3] = f1 - b;
+ fi[k1] = f1 + b;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ }
+ TRIG_RESET(k,c1,s1);
+ } while (k4<n);
+}
+
+void mayer_fft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ real[i] = (q+t)*.5; real[j] = (q-t)*.5;
+ imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
+ }
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+}
+
+void mayer_ifft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
+ real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
+ }
+}
+
+void mayer_realfft(int n, REAL *real)
+{
+ REAL a,b,c,d;
+ int i,j,k;
+ mayer_fht(real,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b)*0.5;
+ real[i] = (a+b)*0.5;
+ }
+}
+
+void mayer_realifft(int n, REAL *real)
+{
+ REAL a,b,c,d;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b);
+ real[i] = (a+b);
+ }
+ mayer_fht(real,n);
+}
diff --git a/apps/plugins/pdbox/PDa/src/d_misc.c b/apps/plugins/pdbox/PDa/src/d_misc.c
new file mode 100644
index 0000000000..f601d66d90
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_misc.c
@@ -0,0 +1,524 @@
+/* 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. */
+
+/* miscellaneous: print~; more to come.
+*/
+
+#include "m_pd.h"
+#include <stdio.h>
+#include <string.h>
+
+/* ------------------------- print~ -------------------------- */
+static t_class *print_class;
+
+typedef struct _print
+{
+ t_object x_obj;
+ float x_f;
+ t_symbol *x_sym;
+ int x_count;
+} t_print;
+
+static t_int *print_perform(t_int *w)
+{
+ t_print *x = (t_print *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ if (x->x_count)
+ {
+ post("%s:", x->x_sym->s_name);
+ if (n == 1) post("%8g", in[0]);
+ else if (n == 2) post("%8g %8g", in[0], in[1]);
+ else if (n == 4) post("%8g %8g %8g %8g",
+ in[0], in[1], in[2], in[3]);
+ else while (n > 0)
+ {
+ post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
+ in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+ n -= 8;
+ in += 8;
+ }
+ x->x_count--;
+ }
+ return (w+4);
+}
+
+static void print_dsp(t_print *x, t_signal **sp)
+{
+ dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void print_float(t_print *x, t_float f)
+{
+ if (f < 0) f = 0;
+ x->x_count = f;
+}
+
+static void print_bang(t_print *x)
+{
+ x->x_count = 1;
+}
+
+static void *print_new(t_symbol *s)
+{
+ t_print *x = (t_print *)pd_new(print_class);
+ x->x_sym = (s->s_name[0]? s : gensym("print~"));
+ x->x_count = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static void print_setup(void)
+{
+ print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0,
+ sizeof(t_print), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(print_class, t_print, x_f);
+ class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), 0);
+ class_addbang(print_class, print_bang);
+ class_addfloat(print_class, print_float);
+}
+
+/* ------------------------- scope~ -------------------------- */
+/* this has been replaced by arrays; to be deleted later */
+
+#include "g_canvas.h"
+
+static t_class *scope_class;
+
+#define SCOPESIZE 256
+
+typedef struct _scope
+{
+ t_object x_obj;
+ t_sample x_samps[SCOPESIZE];
+ int x_phase;
+ int x_drawn;
+ void *x_canvas;
+} t_scope;
+
+static t_int *scope_perform(t_int *w)
+{
+ t_scope *x = (t_scope *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]), phase = x->x_phase;
+ while (n--)
+ {
+ x->x_samps[phase] = *in++;
+ phase = (phase + 1) & (SCOPESIZE-1);
+ }
+ x->x_phase = phase;
+ return (w+4);
+}
+
+static void scope_dsp(t_scope *x, t_signal **sp)
+{
+ dsp_add(scope_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void scope_erase(t_scope *x)
+{
+ if (x->x_drawn) sys_vgui(".x%x.c delete gumbo\n", x->x_canvas);
+}
+
+#define X1 10.
+#define X2 20.
+#define YC 5.
+static void scope_bang(t_scope *x)
+{
+ int n, phase;
+ char hugebuf[10000], *s = hugebuf;
+ scope_erase(x);
+ sys_vgui(".x%x.c create line 10c 5c 20c 5c -tags gumbo\n", x->x_canvas);
+ sprintf(s, ".x%x.c create line ", (t_int)x->x_canvas);
+ s += strlen(s);
+ for (n = 0, phase = x->x_phase;
+ n < SCOPESIZE; phase = ((phase+1) & (SCOPESIZE-1)), n++)
+ {
+ sprintf(s, "%fc %fc ", X1 + (X2 - X1) * (float)n * (1./SCOPESIZE),
+ YC - 5 * x->x_samps[phase]);
+ s += strlen(s);
+ /* post("phase %d", phase); */
+ }
+ sprintf(s, "-tags gumbo\n");
+ sys_gui(hugebuf);
+ x->x_drawn = 1;
+}
+
+static void scope_free(t_scope *x)
+{
+ scope_erase(x);
+}
+
+static void *scope_new(t_symbol *s)
+{
+ t_scope *x = (t_scope *)pd_new(scope_class);
+ error("scope: this is now obsolete; use arrays and tabwrite~ instead");
+ x->x_phase = 0;
+ x->x_drawn = 0;
+ x->x_canvas = canvas_getcurrent();
+ return (x);
+}
+
+static void scope_setup(void)
+{
+ scope_class = class_new(gensym("scope~"), (t_newmethod)scope_new,
+ (t_method)scope_free, sizeof(t_scope), 0, A_DEFSYM, 0);
+ class_addmethod(scope_class, nullfn, gensym("signal"), 0);
+ class_addmethod(scope_class, (t_method)scope_dsp, gensym("dsp"), 0);
+ class_addbang(scope_class, scope_bang);
+}
+
+/* ------------------------ bang~ -------------------------- */
+
+static t_class *bang_tilde_class;
+
+typedef struct _bang
+{
+ t_object x_obj;
+ t_clock *x_clock;
+} t_bang;
+
+static t_int *bang_tilde_perform(t_int *w)
+{
+ t_bang *x = (t_bang *)(w[1]);
+ clock_delay(x->x_clock, 0);
+ return (w+2);
+}
+
+static void bang_tilde_dsp(t_bang *x, t_signal **sp)
+{
+ dsp_add(bang_tilde_perform, 1, x);
+}
+
+static void bang_tilde_tick(t_bang *x)
+{
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void bang_tilde_free(t_bang *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *bang_tilde_new(t_symbol *s)
+{
+ t_bang *x = (t_bang *)pd_new(bang_tilde_class);
+ x->x_clock = clock_new(x, (t_method)bang_tilde_tick);
+ outlet_new(&x->x_obj, &s_bang);
+ return (x);
+}
+
+static void bang_tilde_setup(void)
+{
+ bang_tilde_class = class_new(gensym("bang~"), (t_newmethod)bang_tilde_new,
+ (t_method)bang_tilde_free, sizeof(t_bang), 0, 0);
+ class_addmethod(bang_tilde_class, (t_method)bang_tilde_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ samplerate~~ -------------------------- */
+
+static t_class *samplerate_tilde_class;
+
+typedef struct _samplerate
+{
+ t_object x_obj;
+} t_samplerate;
+
+static void samplerate_tilde_bang(t_samplerate *x)
+{
+ outlet_float(x->x_obj.ob_outlet, sys_getsr());
+}
+
+static void *samplerate_tilde_new(t_symbol *s)
+{
+ t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class);
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void samplerate_tilde_setup(void)
+{
+ samplerate_tilde_class = class_new(gensym("samplerate~"),
+ (t_newmethod)samplerate_tilde_new, 0, sizeof(t_samplerate), 0, 0);
+ class_addbang(samplerate_tilde_class, samplerate_tilde_bang);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_misc_setup(void)
+{
+#ifndef FIXEDPOINT
+ print_setup();
+#endif
+ scope_setup();
+ bang_tilde_setup();
+ samplerate_tilde_setup();
+}
+
+
+
+
+/* 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. */
+
+/* miscellaneous: print~; more to come.
+*/
+
+#include "m_pd.h"
+#include <stdio.h>
+#include <string.h>
+
+/* ------------------------- print~ -------------------------- */
+static t_class *print_class;
+
+typedef struct _print
+{
+ t_object x_obj;
+ float x_f;
+ t_symbol *x_sym;
+ int x_count;
+} t_print;
+
+static t_int *print_perform(t_int *w)
+{
+ t_print *x = (t_print *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ if (x->x_count)
+ {
+ post("%s:", x->x_sym->s_name);
+ if (n == 1) post("%8g", in[0]);
+ else if (n == 2) post("%8g %8g", in[0], in[1]);
+ else if (n == 4) post("%8g %8g %8g %8g",
+ in[0], in[1], in[2], in[3]);
+ else while (n > 0)
+ {
+ post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
+ in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+ n -= 8;
+ in += 8;
+ }
+ x->x_count--;
+ }
+ return (w+4);
+}
+
+static void print_dsp(t_print *x, t_signal **sp)
+{
+ dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void print_float(t_print *x, t_float f)
+{
+ if (f < 0) f = 0;
+ x->x_count = f;
+}
+
+static void print_bang(t_print *x)
+{
+ x->x_count = 1;
+}
+
+static void *print_new(t_symbol *s)
+{
+ t_print *x = (t_print *)pd_new(print_class);
+ x->x_sym = (s->s_name[0]? s : gensym("print~"));
+ x->x_count = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static void print_setup(void)
+{
+ print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0,
+ sizeof(t_print), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(print_class, t_print, x_f);
+ class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), 0);
+ class_addbang(print_class, print_bang);
+ class_addfloat(print_class, print_float);
+}
+
+/* ------------------------- scope~ -------------------------- */
+/* this has been replaced by arrays; to be deleted later */
+
+#include "g_canvas.h"
+
+static t_class *scope_class;
+
+#define SCOPESIZE 256
+
+typedef struct _scope
+{
+ t_object x_obj;
+ t_sample x_samps[SCOPESIZE];
+ int x_phase;
+ int x_drawn;
+ void *x_canvas;
+} t_scope;
+
+static t_int *scope_perform(t_int *w)
+{
+ t_scope *x = (t_scope *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]), phase = x->x_phase;
+ while (n--)
+ {
+ x->x_samps[phase] = *in++;
+ phase = (phase + 1) & (SCOPESIZE-1);
+ }
+ x->x_phase = phase;
+ return (w+4);
+}
+
+static void scope_dsp(t_scope *x, t_signal **sp)
+{
+ dsp_add(scope_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void scope_erase(t_scope *x)
+{
+ if (x->x_drawn) sys_vgui(".x%x.c delete gumbo\n", x->x_canvas);
+}
+
+#define X1 10.
+#define X2 20.
+#define YC 5.
+static void scope_bang(t_scope *x)
+{
+ int n, phase;
+ char hugebuf[10000], *s = hugebuf;
+ scope_erase(x);
+ sys_vgui(".x%x.c create line 10c 5c 20c 5c -tags gumbo\n", x->x_canvas);
+ sprintf(s, ".x%x.c create line ", (t_int)x->x_canvas);
+ s += strlen(s);
+ for (n = 0, phase = x->x_phase;
+ n < SCOPESIZE; phase = ((phase+1) & (SCOPESIZE-1)), n++)
+ {
+ sprintf(s, "%fc %fc ", X1 + (X2 - X1) * (float)n * (1./SCOPESIZE),
+ YC - 5 * x->x_samps[phase]);
+ s += strlen(s);
+ /* post("phase %d", phase); */
+ }
+ sprintf(s, "-tags gumbo\n");
+ sys_gui(hugebuf);
+ x->x_drawn = 1;
+}
+
+static void scope_free(t_scope *x)
+{
+ scope_erase(x);
+}
+
+static void *scope_new(t_symbol *s)
+{
+ t_scope *x = (t_scope *)pd_new(scope_class);
+ error("scope: this is now obsolete; use arrays and tabwrite~ instead");
+ x->x_phase = 0;
+ x->x_drawn = 0;
+ x->x_canvas = canvas_getcurrent();
+ return (x);
+}
+
+static void scope_setup(void)
+{
+ scope_class = class_new(gensym("scope~"), (t_newmethod)scope_new,
+ (t_method)scope_free, sizeof(t_scope), 0, A_DEFSYM, 0);
+ class_addmethod(scope_class, nullfn, gensym("signal"), 0);
+ class_addmethod(scope_class, (t_method)scope_dsp, gensym("dsp"), 0);
+ class_addbang(scope_class, scope_bang);
+}
+
+/* ------------------------ bang~ -------------------------- */
+
+static t_class *bang_tilde_class;
+
+typedef struct _bang
+{
+ t_object x_obj;
+ t_clock *x_clock;
+} t_bang;
+
+static t_int *bang_tilde_perform(t_int *w)
+{
+ t_bang *x = (t_bang *)(w[1]);
+ clock_delay(x->x_clock, 0);
+ return (w+2);
+}
+
+static void bang_tilde_dsp(t_bang *x, t_signal **sp)
+{
+ dsp_add(bang_tilde_perform, 1, x);
+}
+
+static void bang_tilde_tick(t_bang *x)
+{
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void bang_tilde_free(t_bang *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *bang_tilde_new(t_symbol *s)
+{
+ t_bang *x = (t_bang *)pd_new(bang_tilde_class);
+ x->x_clock = clock_new(x, (t_method)bang_tilde_tick);
+ outlet_new(&x->x_obj, &s_bang);
+ return (x);
+}
+
+static void bang_tilde_setup(void)
+{
+ bang_tilde_class = class_new(gensym("bang~"), (t_newmethod)bang_tilde_new,
+ (t_method)bang_tilde_free, sizeof(t_bang), 0, 0);
+ class_addmethod(bang_tilde_class, (t_method)bang_tilde_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ samplerate~~ -------------------------- */
+
+static t_class *samplerate_tilde_class;
+
+typedef struct _samplerate
+{
+ t_object x_obj;
+} t_samplerate;
+
+static void samplerate_tilde_bang(t_samplerate *x)
+{
+ outlet_float(x->x_obj.ob_outlet, sys_getsr());
+}
+
+static void *samplerate_tilde_new(t_symbol *s)
+{
+ t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class);
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void samplerate_tilde_setup(void)
+{
+ samplerate_tilde_class = class_new(gensym("samplerate~"),
+ (t_newmethod)samplerate_tilde_new, 0, sizeof(t_samplerate), 0, 0);
+ class_addbang(samplerate_tilde_class, samplerate_tilde_bang);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_misc_setup(void)
+{
+#ifndef FIXEDPOINT
+ print_setup();
+#endif
+ scope_setup();
+ bang_tilde_setup();
+ samplerate_tilde_setup();
+}
+
+
+
+
diff --git a/apps/plugins/pdbox/PDa/src/d_osc.c b/apps/plugins/pdbox/PDa/src/d_osc.c
new file mode 100644
index 0000000000..8a3486d981
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_osc.c
@@ -0,0 +1,1070 @@
+/* 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. */
+
+/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c.
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+ /* machine-dependent definitions. These ifdefs really
+ should have been by CPU type and not by operating system! */
+#ifdef IRIX
+ /* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef MSW
+ /* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+#ifdef __linux__
+
+#include <endian.h>
+
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef MACOSX
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* MACOSX */
+#endif /* __linux__ */
+#endif /* MSW */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+
+/* -------------------------- phasor~ ------------------------------ */
+static t_class *phasor_class, *scalarphasor_class;
+
+#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */
+
+typedef struct _phasor
+{
+ t_object x_obj;
+ double x_phase;
+ float x_conv;
+ float x_f; /* scalar frequency */
+} t_phasor;
+
+static void *phasor_new(t_floatarg f)
+{
+ t_phasor *x = (t_phasor *)pd_new(phasor_class);
+ x->x_f = f;
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_phase = 0;
+ x->x_conv = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *phasor_perform(t_int *w)
+{
+ t_phasor *x = (t_phasor *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ double dphase = x->x_phase + UNITBIT32;
+ union tabfudge tf;
+ int normhipart;
+ float conv = x->x_conv;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase;
+
+ while (n--)
+ {
+ tf.tf_i[HIOFFSET] = normhipart;
+ dphase += *in++ * conv;
+ *out++ = tf.tf_d - UNITBIT32;
+ tf.tf_d = dphase;
+ }
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = tf.tf_d - UNITBIT32;
+ return (w+5);
+}
+
+static void phasor_dsp(t_phasor *x, t_signal **sp)
+{
+ x->x_conv = 1./sp[0]->s_sr;
+ dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void phasor_ft1(t_phasor *x, t_float f)
+{
+ x->x_phase = f;
+}
+
+static void phasor_setup(void)
+{
+ phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
+ sizeof(t_phasor), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
+ class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
+ class_addmethod(phasor_class, (t_method)phasor_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+#endif /* Hoeldrich version */
+
+/* ------------------------ cos~ ----------------------------- */
+
+float *cos_table;
+
+static t_class *cos_class;
+
+typedef struct _cos
+{
+ t_object x_obj;
+ float x_f;
+} t_cos;
+
+static void *cos_new(void)
+{
+ t_cos *x = (t_cos *)pd_new(cos_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *cos_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart;
+ union tabfudge tf;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+#if 0 /* this is the readable version of the code. */
+ while (n--)
+ {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.tf_d = dphase;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#endif
+#if 1 /* this is the same, unwrapped by hand. */
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.tf_d = dphase;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ while (--n)
+ {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ frac = tf.tf_d - UNITBIT32;
+ tf.tf_d = dphase;
+ f1 = addr[0];
+ f2 = addr[1];
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ *out++ = f1 + frac * (f2 - f1);
+ tf.tf_i[HIOFFSET] = normhipart;
+ }
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+ return (w+4);
+}
+
+static void cos_dsp(t_cos *x, t_signal **sp)
+{
+ dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void cos_maketable(void)
+{
+ int i;
+ float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE;
+ union tabfudge tf;
+
+ if (cos_table) return;
+ cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
+ for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--;
+ fp++, phase += phsinc)
+ *fp = cos(phase);
+
+ /* here we check at startup whether the byte alignment
+ is as we declared it. If not, the code has to be
+ recompiled the other way. */
+ tf.tf_d = UNITBIT32 + 0.5;
+ if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000)
+ bug("cos~: unexpected machine alignment");
+}
+
+static void cos_setup(void)
+{
+ cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
+ sizeof(t_cos), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
+ class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
+ cos_maketable();
+}
+
+/* ------------------------ osc~ ----------------------------- */
+
+static t_class *osc_class, *scalarosc_class;
+
+typedef struct _osc
+{
+ t_object x_obj;
+ double x_phase;
+ float x_conv;
+ float x_f; /* frequency if scalar */
+} t_osc;
+
+static void *osc_new(t_floatarg f)
+{
+ t_osc *x = (t_osc *)pd_new(osc_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_phase = 0;
+ x->x_conv = 0;
+ return (x);
+}
+
+static t_int *osc_perform(t_int *w)
+{
+ t_osc *x = (t_osc *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase = x->x_phase + UNITBIT32;
+ int normhipart;
+ union tabfudge tf;
+ float conv = x->x_conv;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+#if 0
+ while (n--)
+ {
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#endif
+#if 1
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ while (--n)
+ {
+ tf.tf_d = dphase;
+ f1 = addr[0];
+ dphase += *in++ * conv;
+ f2 = addr[1];
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ *out++ = f1 + frac * (f2 - f1);
+ frac = tf.tf_d - UNITBIT32;
+ }
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+
+ tf.tf_d = UNITBIT32 * COSTABSIZE;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE;
+ return (w+5);
+}
+
+static void osc_dsp(t_osc *x, t_signal **sp)
+{
+ x->x_conv = COSTABSIZE/sp[0]->s_sr;
+ dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void osc_ft1(t_osc *x, t_float f)
+{
+ x->x_phase = COSTABSIZE * f;
+}
+
+static void osc_setup(void)
+{
+ osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
+ sizeof(t_osc), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
+ class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
+ class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
+
+ cos_maketable();
+}
+
+/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
+
+typedef struct vcfctl
+{
+ float c_re;
+ float c_im;
+ float c_q;
+ float c_isr;
+} t_vcfctl;
+
+typedef struct sigvcf
+{
+ t_object x_obj;
+ t_vcfctl x_cspace;
+ t_vcfctl *x_ctl;
+ float x_f;
+} t_sigvcf;
+
+t_class *sigvcf_class;
+
+static void *sigvcf_new(t_floatarg q)
+{
+ t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_re = 0;
+ x->x_cspace.c_im = 0;
+ x->x_cspace.c_q = q;
+ x->x_cspace.c_isr = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
+{
+ x->x_ctl->c_q = (f > 0 ? f : 0.f);
+}
+
+static t_int *sigvcf_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ float *in2 = (float *)(w[2]);
+ float *out1 = (float *)(w[3]);
+ float *out2 = (float *)(w[4]);
+ t_vcfctl *c = (t_vcfctl *)(w[5]);
+ int n = (t_int)(w[6]);
+ int i;
+ float re = c->c_re, re2;
+ float im = c->c_im;
+ float q = c->c_q;
+ float qinv = (q > 0? 1.0f/q : 0);
+ float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
+ float isr = c->c_isr;
+ float coefr, coefi;
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart, tabindex;
+ union tabfudge tf;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+ for (i = 0; i < n; i++)
+ {
+ float cf, cfindx, r, oneminusr;
+ cf = *in2++ * isr;
+ if (cf < 0) cf = 0;
+ cfindx = cf * (float)(COSTABSIZE/6.28318f);
+ r = (qinv > 0 ? 1 - cf * qinv : 0);
+ if (r < 0) r = 0;
+ oneminusr = 1.0f - r;
+ dphase = ((double)(cfindx)) + UNITBIT32;
+ tf.tf_d = dphase;
+ tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1);
+ addr = tab + tabindex;
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ coefr = r * (f1 + frac * (f2 - f1));
+
+ addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
+ f1 = addr[0];
+ f2 = addr[1];
+ coefi = r * (f1 + frac * (f2 - f1));
+
+ f1 = *in1++;
+ re2 = re;
+ *out1++ = re = ampcorrect * oneminusr * f1
+ + coefr * re2 - coefi * im;
+ *out2++ = im = coefi * re2 + coefr * im;
+ }
+ if (PD_BIGORSMALL(re))
+ re = 0;
+ if (PD_BIGORSMALL(im))
+ im = 0;
+ c->c_re = re;
+ c->c_im = im;
+ return (w+7);
+}
+
+static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
+{
+ x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr;
+ dsp_add(sigvcf_perform, 6,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigvcf_setup(void)
+{
+ sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
+ sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
+ class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
+ class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+/* -------------------------- noise~ ------------------------------ */
+static t_class *noise_class;
+
+typedef struct _noise
+{
+ t_object x_obj;
+ int x_val;
+} t_noise;
+
+static void *noise_new(void)
+{
+ t_noise *x = (t_noise *)pd_new(noise_class);
+ static int init = 307;
+ x->x_val = (init *= 1319);
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *noise_perform(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]);
+ int *vp = (int *)(w[2]);
+ int n = (int)(w[3]);
+ int val = *vp;
+ while (n--)
+ {
+ *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) *
+ (float)(1.0 / 0x40000000);
+ val = val * 435898247 + 382842987;
+ }
+ *vp = val;
+ return (w+4);
+}
+
+static void noise_dsp(t_noise *x, t_signal **sp)
+{
+ dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
+}
+
+static void noise_setup(void)
+{
+ noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
+ sizeof(t_noise), 0, 0);
+ class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
+}
+
+
+/* ----------------------- global setup routine ---------------- */
+void d_osc_setup(void)
+{
+ phasor_setup();
+ cos_setup();
+ osc_setup();
+ sigvcf_setup();
+ noise_setup();
+}
+
+/* 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. */
+
+/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c.
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+ /* machine-dependent definitions. These ifdefs really
+ should have been by CPU type and not by operating system! */
+#ifdef IRIX
+ /* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef MSW
+ /* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+#ifdef __linux__
+
+#include <endian.h>
+
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef MACOSX
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* MACOSX */
+#endif /* __linux__ */
+#endif /* MSW */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+
+/* -------------------------- phasor~ ------------------------------ */
+static t_class *phasor_class, *scalarphasor_class;
+
+#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */
+
+typedef struct _phasor
+{
+ t_object x_obj;
+ double x_phase;
+ float x_conv;
+ float x_f; /* scalar frequency */
+} t_phasor;
+
+static void *phasor_new(t_floatarg f)
+{
+ t_phasor *x = (t_phasor *)pd_new(phasor_class);
+ x->x_f = f;
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_phase = 0;
+ x->x_conv = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *phasor_perform(t_int *w)
+{
+ t_phasor *x = (t_phasor *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ double dphase = x->x_phase + UNITBIT32;
+ union tabfudge tf;
+ int normhipart;
+ float conv = x->x_conv;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase;
+
+ while (n--)
+ {
+ tf.tf_i[HIOFFSET] = normhipart;
+ dphase += *in++ * conv;
+ *out++ = tf.tf_d - UNITBIT32;
+ tf.tf_d = dphase;
+ }
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = tf.tf_d - UNITBIT32;
+ return (w+5);
+}
+
+static void phasor_dsp(t_phasor *x, t_signal **sp)
+{
+ x->x_conv = 1./sp[0]->s_sr;
+ dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void phasor_ft1(t_phasor *x, t_float f)
+{
+ x->x_phase = f;
+}
+
+static void phasor_setup(void)
+{
+ phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
+ sizeof(t_phasor), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
+ class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
+ class_addmethod(phasor_class, (t_method)phasor_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+#endif /* Hoeldrich version */
+
+/* ------------------------ cos~ ----------------------------- */
+
+float *cos_table;
+
+static t_class *cos_class;
+
+typedef struct _cos
+{
+ t_object x_obj;
+ float x_f;
+} t_cos;
+
+static void *cos_new(void)
+{
+ t_cos *x = (t_cos *)pd_new(cos_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *cos_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart;
+ union tabfudge tf;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+#if 0 /* this is the readable version of the code. */
+ while (n--)
+ {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.tf_d = dphase;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#endif
+#if 1 /* this is the same, unwrapped by hand. */
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.tf_d = dphase;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ while (--n)
+ {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ frac = tf.tf_d - UNITBIT32;
+ tf.tf_d = dphase;
+ f1 = addr[0];
+ f2 = addr[1];
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ *out++ = f1 + frac * (f2 - f1);
+ tf.tf_i[HIOFFSET] = normhipart;
+ }
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+ return (w+4);
+}
+
+static void cos_dsp(t_cos *x, t_signal **sp)
+{
+ dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void cos_maketable(void)
+{
+ int i;
+ float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE;
+ union tabfudge tf;
+
+ if (cos_table) return;
+ cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
+ for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--;
+ fp++, phase += phsinc)
+ *fp = cos(phase);
+
+ /* here we check at startup whether the byte alignment
+ is as we declared it. If not, the code has to be
+ recompiled the other way. */
+ tf.tf_d = UNITBIT32 + 0.5;
+ if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000)
+ bug("cos~: unexpected machine alignment");
+}
+
+static void cos_setup(void)
+{
+ cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
+ sizeof(t_cos), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
+ class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
+ cos_maketable();
+}
+
+/* ------------------------ osc~ ----------------------------- */
+
+static t_class *osc_class, *scalarosc_class;
+
+typedef struct _osc
+{
+ t_object x_obj;
+ double x_phase;
+ float x_conv;
+ float x_f; /* frequency if scalar */
+} t_osc;
+
+static void *osc_new(t_floatarg f)
+{
+ t_osc *x = (t_osc *)pd_new(osc_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_phase = 0;
+ x->x_conv = 0;
+ return (x);
+}
+
+static t_int *osc_perform(t_int *w)
+{
+ t_osc *x = (t_osc *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase = x->x_phase + UNITBIT32;
+ int normhipart;
+ union tabfudge tf;
+ float conv = x->x_conv;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+#if 0
+ while (n--)
+ {
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#endif
+#if 1
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ while (--n)
+ {
+ tf.tf_d = dphase;
+ f1 = addr[0];
+ dphase += *in++ * conv;
+ f2 = addr[1];
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ *out++ = f1 + frac * (f2 - f1);
+ frac = tf.tf_d - UNITBIT32;
+ }
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+
+ tf.tf_d = UNITBIT32 * COSTABSIZE;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE;
+ return (w+5);
+}
+
+static void osc_dsp(t_osc *x, t_signal **sp)
+{
+ x->x_conv = COSTABSIZE/sp[0]->s_sr;
+ dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void osc_ft1(t_osc *x, t_float f)
+{
+ x->x_phase = COSTABSIZE * f;
+}
+
+static void osc_setup(void)
+{
+ osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
+ sizeof(t_osc), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
+ class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
+ class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
+
+ cos_maketable();
+}
+
+/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
+
+typedef struct vcfctl
+{
+ float c_re;
+ float c_im;
+ float c_q;
+ float c_isr;
+} t_vcfctl;
+
+typedef struct sigvcf
+{
+ t_object x_obj;
+ t_vcfctl x_cspace;
+ t_vcfctl *x_ctl;
+ float x_f;
+} t_sigvcf;
+
+t_class *sigvcf_class;
+
+static void *sigvcf_new(t_floatarg q)
+{
+ t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_re = 0;
+ x->x_cspace.c_im = 0;
+ x->x_cspace.c_q = q;
+ x->x_cspace.c_isr = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
+{
+ x->x_ctl->c_q = (f > 0 ? f : 0.f);
+}
+
+static t_int *sigvcf_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ float *in2 = (float *)(w[2]);
+ float *out1 = (float *)(w[3]);
+ float *out2 = (float *)(w[4]);
+ t_vcfctl *c = (t_vcfctl *)(w[5]);
+ int n = (t_int)(w[6]);
+ int i;
+ float re = c->c_re, re2;
+ float im = c->c_im;
+ float q = c->c_q;
+ float qinv = (q > 0? 1.0f/q : 0);
+ float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
+ float isr = c->c_isr;
+ float coefr, coefi;
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart, tabindex;
+ union tabfudge tf;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+ for (i = 0; i < n; i++)
+ {
+ float cf, cfindx, r, oneminusr;
+ cf = *in2++ * isr;
+ if (cf < 0) cf = 0;
+ cfindx = cf * (float)(COSTABSIZE/6.28318f);
+ r = (qinv > 0 ? 1 - cf * qinv : 0);
+ if (r < 0) r = 0;
+ oneminusr = 1.0f - r;
+ dphase = ((double)(cfindx)) + UNITBIT32;
+ tf.tf_d = dphase;
+ tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1);
+ addr = tab + tabindex;
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ coefr = r * (f1 + frac * (f2 - f1));
+
+ addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
+ f1 = addr[0];
+ f2 = addr[1];
+ coefi = r * (f1 + frac * (f2 - f1));
+
+ f1 = *in1++;
+ re2 = re;
+ *out1++ = re = ampcorrect * oneminusr * f1
+ + coefr * re2 - coefi * im;
+ *out2++ = im = coefi * re2 + coefr * im;
+ }
+ if (PD_BIGORSMALL(re))
+ re = 0;
+ if (PD_BIGORSMALL(im))
+ im = 0;
+ c->c_re = re;
+ c->c_im = im;
+ return (w+7);
+}
+
+static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
+{
+ x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr;
+ dsp_add(sigvcf_perform, 6,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigvcf_setup(void)
+{
+ sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
+ sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
+ class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
+ class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+/* -------------------------- noise~ ------------------------------ */
+static t_class *noise_class;
+
+typedef struct _noise
+{
+ t_object x_obj;
+ int x_val;
+} t_noise;
+
+static void *noise_new(void)
+{
+ t_noise *x = (t_noise *)pd_new(noise_class);
+ static int init = 307;
+ x->x_val = (init *= 1319);
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *noise_perform(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]);
+ int *vp = (int *)(w[2]);
+ int n = (int)(w[3]);
+ int val = *vp;
+ while (n--)
+ {
+ *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) *
+ (float)(1.0 / 0x40000000);
+ val = val * 435898247 + 382842987;
+ }
+ *vp = val;
+ return (w+4);
+}
+
+static void noise_dsp(t_noise *x, t_signal **sp)
+{
+ dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
+}
+
+static void noise_setup(void)
+{
+ noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
+ sizeof(t_noise), 0, 0);
+ class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
+}
+
+
+/* ----------------------- global setup routine ---------------- */
+void d_osc_setup(void)
+{
+ phasor_setup();
+ cos_setup();
+ osc_setup();
+ sigvcf_setup();
+ noise_setup();
+}
+
diff --git a/apps/plugins/pdbox/PDa/src/d_resample.c b/apps/plugins/pdbox/PDa/src/d_resample.c
new file mode 100644
index 0000000000..4e617ec4df
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_resample.c
@@ -0,0 +1,450 @@
+/* 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. */
+
+/* upsampling/downsampling methods for inlet~/outlet~
+ *
+ * mfg.gfd.uil
+ * IOhannes
+ *
+ * 2509:forum::für::umläute:2001
+ */
+
+
+
+#include "m_pd.h"
+
+/* --------------------- up/down-sampling --------------------- */
+t_int *downsampling_perform_0(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]); /* original signal */
+ t_sample *out = (t_sample *)(w[2]); /* downsampled signal */
+ int down = (int)(w[3]); /* downsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+
+ int n=parent/down;
+
+ while(n--){
+ *out++=*in;
+ in+=down;
+ }
+
+ return (w+5);
+}
+
+t_int *upsampling_perform_0(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]); /* original signal */
+ t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
+ int up = (int)(w[3]); /* upsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+
+ int n=parent*up;
+ t_sample *dummy = out;
+
+ while(n--)*out++=0;
+
+ n = parent;
+ out = dummy;
+ while(n--){
+ *out=*in++;
+ out+=up;
+ }
+
+ return (w+5);
+}
+
+t_int *upsampling_perform_hold(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]); /* original signal */
+ t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
+ int up = (int)(w[3]); /* upsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+ int i=up;
+
+ int n=parent;
+ t_sample *dum_out = out;
+ t_sample *dum_in = in;
+
+ while (i--) {
+ n = parent;
+ out = dum_out+i;
+ in = dum_in;
+ while(n--){
+ *out=*in++;
+ out+=up;
+ }
+ }
+ return (w+5);
+}
+
+t_int *upsampling_perform_linear(t_int *w)
+{
+ t_resample *x= (t_resample *)(w[1]);
+ t_sample *in = (t_sample *)(w[2]); /* original signal */
+ t_sample *out = (t_sample *)(w[3]); /* upsampled signal */
+ int up = (int)(w[4]); /* upsampling factor */
+ int parent = (int)(w[5]); /* original vectorsize */
+ int length = parent*up;
+ int n;
+ t_sample *fp;
+ t_sample a=*x->buffer, b=*in;
+
+
+ for (n=0; n<length; n++) {
+ t_float findex = (t_float)(n+1)/up;
+ int index = findex;
+ t_sample frac=findex - index;
+ if (frac==0.)frac=1.;
+ *out++ = frac * b + (1.-frac) * a;
+ fp = in+index;
+ b=*fp;
+ a=(index)?*(fp-1):a;
+ }
+
+ *x->buffer = a;
+ return (w+6);
+}
+
+/* ----------------------- public -------------------------------- */
+
+/* utils */
+
+void resample_init(t_resample *x)
+{
+ x->method=0;
+
+ x->downsample=x->upsample=1;
+
+ x->s_n = x->coefsize = x->bufsize = 0;
+ x->s_vec = x->coeffs = x->buffer = 0;
+}
+
+void resample_free(t_resample *x)
+{
+ if (x->s_n) t_freebytes(x->s_vec, x->s_n*sizeof(*x->s_vec));
+ if (x->coefsize) t_freebytes(x->coeffs, x->coefsize*sizeof(*x->coeffs));
+ if (x->bufsize) t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
+
+ x->s_n = x->coefsize = x->bufsize = 0;
+ x->s_vec = x->coeffs = x->buffer = 0;
+}
+
+
+/* dsp-adding */
+
+void resample_dsp(t_resample *x,
+ t_sample* in, int insize,
+ t_sample* out, int outsize,
+ int method)
+{
+ if (insize == outsize){
+ bug("nothing to be done");
+ return;
+ }
+
+ if (insize > outsize) { /* downsampling */
+ if (insize % outsize) {
+ error("bad downsampling factor");
+ return;
+ }
+ switch (method) {
+ default:
+ dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize);
+ }
+
+
+ } else { /* upsampling */
+ if (outsize % insize) {
+ error("bad upsampling factor");
+ return;
+ }
+ switch (method) {
+ case 1:
+ dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize);
+ break;
+ case 2:
+ if (x->bufsize != 1) {
+ t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
+ x->bufsize = 1;
+ x->buffer = t_getbytes(x->bufsize*sizeof(*x->buffer));
+ }
+ dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize);
+ break;
+ default:
+ dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize);
+ }
+ }
+}
+
+void resamplefrom_dsp(t_resample *x,
+ t_sample *in,
+ int insize, int outsize, int method)
+{
+ if (insize==outsize) {
+ t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
+ x->s_n = 0;
+ x->s_vec = in;
+ return;
+ }
+
+ if (x->s_n != outsize) {
+ t_sample *buf=x->s_vec;
+ t_freebytes(buf, x->s_n * sizeof(*buf));
+ buf = (t_sample *)t_getbytes(outsize * sizeof(*buf));
+ x->s_vec = buf;
+ x->s_n = outsize;
+ }
+
+ resample_dsp(x, in, insize, x->s_vec, x->s_n, method);
+ return;
+}
+
+void resampleto_dsp(t_resample *x,
+ t_sample *out,
+ int insize, int outsize, int method)
+{
+ if (insize==outsize) {
+ if (x->s_n)t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
+ x->s_n = 0;
+ x->s_vec = out;
+ return;
+ }
+
+ if (x->s_n != insize) {
+ t_sample *buf=x->s_vec;
+ t_freebytes(buf, x->s_n * sizeof(*buf));
+ buf = (t_sample *)t_getbytes(insize * sizeof(*buf));
+ x->s_vec = buf;
+ x->s_n = insize;
+ }
+
+ resample_dsp(x, x->s_vec, x->s_n, out, outsize, method);
+
+ return;
+}
+/* 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. */
+
+/* upsampling/downsampling methods for inlet~/outlet~
+ *
+ * mfg.gfd.uil
+ * IOhannes
+ *
+ * 2509:forum::für::umläute:2001
+ */
+
+
+
+#include "m_pd.h"
+
+/* --------------------- up/down-sampling --------------------- */
+t_int *downsampling_perform_0(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]); /* original signal */
+ t_sample *out = (t_sample *)(w[2]); /* downsampled signal */
+ int down = (int)(w[3]); /* downsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+
+ int n=parent/down;
+
+ while(n--){
+ *out++=*in;
+ in+=down;
+ }
+
+ return (w+5);
+}
+
+t_int *upsampling_perform_0(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]); /* original signal */
+ t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
+ int up = (int)(w[3]); /* upsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+
+ int n=parent*up;
+ t_sample *dummy = out;
+
+ while(n--)*out++=0;
+
+ n = parent;
+ out = dummy;
+ while(n--){
+ *out=*in++;
+ out+=up;
+ }
+
+ return (w+5);
+}
+
+t_int *upsampling_perform_hold(t_int *w)
+{
+ t_sample *in = (t_sample *)(w[1]); /* original signal */
+ t_sample *out = (t_sample *)(w[2]); /* upsampled signal */
+ int up = (int)(w[3]); /* upsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+ int i=up;
+
+ int n=parent;
+ t_sample *dum_out = out;
+ t_sample *dum_in = in;
+
+ while (i--) {
+ n = parent;
+ out = dum_out+i;
+ in = dum_in;
+ while(n--){
+ *out=*in++;
+ out+=up;
+ }
+ }
+ return (w+5);
+}
+
+t_int *upsampling_perform_linear(t_int *w)
+{
+ t_resample *x= (t_resample *)(w[1]);
+ t_sample *in = (t_sample *)(w[2]); /* original signal */
+ t_sample *out = (t_sample *)(w[3]); /* upsampled signal */
+ int up = (int)(w[4]); /* upsampling factor */
+ int parent = (int)(w[5]); /* original vectorsize */
+ int length = parent*up;
+ int n;
+ t_sample *fp;
+ t_sample a=*x->buffer, b=*in;
+
+
+ for (n=0; n<length; n++) {
+ t_float findex = (t_float)(n+1)/up;
+ int index = findex;
+ t_sample frac=findex - index;
+ if (frac==0.)frac=1.;
+ *out++ = frac * b + (1.-frac) * a;
+ fp = in+index;
+ b=*fp;
+ a=(index)?*(fp-1):a;
+ }
+
+ *x->buffer = a;
+ return (w+6);
+}
+
+/* ----------------------- public -------------------------------- */
+
+/* utils */
+
+void resample_init(t_resample *x)
+{
+ x->method=0;
+
+ x->downsample=x->upsample=1;
+
+ x->s_n = x->coefsize = x->bufsize = 0;
+ x->s_vec = x->coeffs = x->buffer = 0;
+}
+
+void resample_free(t_resample *x)
+{
+ if (x->s_n) t_freebytes(x->s_vec, x->s_n*sizeof(*x->s_vec));
+ if (x->coefsize) t_freebytes(x->coeffs, x->coefsize*sizeof(*x->coeffs));
+ if (x->bufsize) t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
+
+ x->s_n = x->coefsize = x->bufsize = 0;
+ x->s_vec = x->coeffs = x->buffer = 0;
+}
+
+
+/* dsp-adding */
+
+void resample_dsp(t_resample *x,
+ t_sample* in, int insize,
+ t_sample* out, int outsize,
+ int method)
+{
+ if (insize == outsize){
+ bug("nothing to be done");
+ return;
+ }
+
+ if (insize > outsize) { /* downsampling */
+ if (insize % outsize) {
+ error("bad downsampling factor");
+ return;
+ }
+ switch (method) {
+ default:
+ dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize);
+ }
+
+
+ } else { /* upsampling */
+ if (outsize % insize) {
+ error("bad upsampling factor");
+ return;
+ }
+ switch (method) {
+ case 1:
+ dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize);
+ break;
+ case 2:
+ if (x->bufsize != 1) {
+ t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
+ x->bufsize = 1;
+ x->buffer = t_getbytes(x->bufsize*sizeof(*x->buffer));
+ }
+ dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize);
+ break;
+ default:
+ dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize);
+ }
+ }
+}
+
+void resamplefrom_dsp(t_resample *x,
+ t_sample *in,
+ int insize, int outsize, int method)
+{
+ if (insize==outsize) {
+ t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
+ x->s_n = 0;
+ x->s_vec = in;
+ return;
+ }
+
+ if (x->s_n != outsize) {
+ t_sample *buf=x->s_vec;
+ t_freebytes(buf, x->s_n * sizeof(*buf));
+ buf = (t_sample *)t_getbytes(outsize * sizeof(*buf));
+ x->s_vec = buf;
+ x->s_n = outsize;
+ }
+
+ resample_dsp(x, in, insize, x->s_vec, x->s_n, method);
+ return;
+}
+
+void resampleto_dsp(t_resample *x,
+ t_sample *out,
+ int insize, int outsize, int method)
+{
+ if (insize==outsize) {
+ if (x->s_n)t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
+ x->s_n = 0;
+ x->s_vec = out;
+ return;
+ }
+
+ if (x->s_n != insize) {
+ t_sample *buf=x->s_vec;
+ t_freebytes(buf, x->s_n * sizeof(*buf));
+ buf = (t_sample *)t_getbytes(insize * sizeof(*buf));
+ x->s_vec = buf;
+ x->s_n = insize;
+ }
+
+ resample_dsp(x, x->s_vec, x->s_n, out, outsize, method);
+
+ return;
+}
diff --git a/apps/plugins/pdbox/PDa/src/d_soundfile.c b/apps/plugins/pdbox/PDa/src/d_soundfile.c
new file mode 100644
index 0000000000..872a44a923
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_soundfile.c
@@ -0,0 +1,4734 @@
+/* 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. */
+
+/* this file contains, first, a collection of soundfile access routines, a
+sort of soundfile library. Second, the "soundfiler" object is defined which
+uses the routines to read or write soundfiles, synchronously, from garrays.
+These operations are not to be done in "real time" as they may have to wait
+for disk accesses (even the write routine.) Finally, the realtime objects
+readsf~ and writesf~ are defined which confine disk operations to a separate
+thread so that they can be used in real time. The readsf~ and writesf~
+objects use Posix-like threads. */
+
+#ifdef UNIX
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#include <pthread.h>
+#ifdef MSW
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "m_pd.h"
+
+#define MAXSFCHANS 64
+
+/***************** soundfile header structures ************************/
+
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+
+/* the NeXTStep sound header structure; can be big or little endian */
+
+typedef struct _nextstep
+{
+ char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
+ uint32 ns_onset; /* byte offset of first sample */
+ uint32 ns_length; /* length of sound in bytes */
+ uint32 ns_format; /* format; see below */
+ uint32 ns_sr; /* sample rate */
+ uint32 ns_nchans; /* number of channels */
+ char ns_info[4]; /* comment */
+} t_nextstep;
+
+#define NS_FORMAT_LINEAR_16 3
+#define NS_FORMAT_LINEAR_24 4
+#define NS_FORMAT_FLOAT 6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+/* the WAVE header. All Wave files are little endian. We assume
+ the "fmt" chunk comes first which is usually the case but perhaps not
+ always; same for AIFF and the "COMM" chunk. */
+
+typedef unsigned word;
+typedef unsigned long dword;
+
+typedef struct _wave
+{
+ char w_fileid[4]; /* chunk id 'RIFF' */
+ uint32 w_chunksize; /* chunk size */
+ char w_waveid[4]; /* wave chunk id 'WAVE' */
+ char w_fmtid[4]; /* format chunk id 'fmt ' */
+ uint32 w_fmtchunksize; /* format chunk size */
+ uint16 w_fmttag; /* format tag (WAV_INT etc) */
+ uint16 w_nchannels; /* number of channels */
+ uint32 w_samplespersec; /* sample rate in hz */
+ uint32 w_navgbytespersec; /* average bytes per second */
+ uint16 w_nblockalign; /* number of bytes per frame */
+ uint16 w_nbitspersample; /* number of bits in a sample */
+ char w_datachunkid[4]; /* data chunk id 'data' */
+ uint32 w_datachunksize; /* length of data chunk */
+} t_wave;
+
+typedef struct _fmt /* format chunk */
+{
+ uint16 f_fmttag; /* format tag, 1 for PCM */
+ uint16 f_nchannels; /* number of channels */
+ uint32 f_samplespersec; /* sample rate in hz */
+ uint32 f_navgbytespersec; /* average bytes per second */
+ uint16 f_nblockalign; /* number of bytes per frame */
+ uint16 f_nbitspersample; /* number of bits in a sample */
+} t_fmt;
+
+typedef struct _wavechunk /* ... and the last two items */
+{
+ char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
+ uint32 wc_size; /* length of data chunk */
+} t_wavechunk;
+
+#define WAV_INT 1
+#define WAV_FLOAT 3
+
+/* the AIFF header. I'm assuming AIFC is compatible but don't really know
+ that. */
+
+typedef struct _datachunk
+{
+ char dc_id[4]; /* data chunk id 'SSND' */
+ uint32 dc_size; /* length of data chunk */
+} t_datachunk;
+
+typedef struct _comm
+{
+ uint16 c_nchannels; /* number of channels */
+ uint16 c_nframeshi; /* # of sample frames (hi) */
+ uint16 c_nframeslo; /* # of sample frames (lo) */
+ uint16 c_bitspersamp; /* bits per sample */
+ unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
+} t_comm;
+
+ /* this version is more convenient for writing them out: */
+typedef struct _aiff
+{
+ char a_fileid[4]; /* chunk id 'FORM' */
+ uint32 a_chunksize; /* chunk size */
+ char a_aiffid[4]; /* aiff chunk id 'AIFF' */
+ char a_fmtid[4]; /* format chunk id 'COMM' */
+ uint32 a_fmtchunksize; /* format chunk size, 18 */
+ uint16 a_nchannels; /* number of channels */
+ uint16 a_nframeshi; /* # of sample frames (hi) */
+ uint16 a_nframeslo; /* # of sample frames (lo) */
+ uint16 a_bitspersamp; /* bits per sample */
+ unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
+} t_aiff;
+
+#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
+
+
+#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
+
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+
+#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
+
+#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
+
+#ifdef MSW
+#include <fcntl.h>
+#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
+#else
+#define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
+#endif
+
+/* this routine returns 1 if the high order byte comes at the lower
+address on our architecture (big-endianness.). It's 1 for Motorola,
+0 for Intel: */
+
+extern int garray_ambigendian(void);
+
+/* byte swappers */
+
+static uint32 swap4(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+ else return (n);
+}
+
+static uint16 swap2(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+ else return (n);
+}
+
+static void swapstring(char *foo, int doit)
+{
+ if (doit)
+ {
+ char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
+ foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
+ }
+}
+
+/******************** soundfile access routines **********************/
+
+/* This routine opens a file, looks for either a nextstep or "wave" header,
+* seeks to end of it, and fills in bytes per sample and number of channels.
+* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
+* are supported. If "headersize" is nonzero, the
+* caller should supply the number of channels, endinanness, and bytes per
+* sample; the header is ignored. Otherwise, the routine tries to read the
+* header and fill in the properties.
+*/
+
+int open_soundfile(const char *dirname, const char *filename, int headersize,
+ int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
+ long skipframes)
+{
+ char buf[OBUFSIZE], *bufptr;
+ int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn;
+ long bytelimit = 0x7fffffff;
+ errno = 0;
+ fd = open_via_path(dirname, filename,
+ "", buf, &bufptr, MAXPDSTRING, 1);
+ if (fd < 0)
+ return (-1);
+ if (headersize >= 0) /* header detection overridden */
+ {
+ bigendian = *p_bigendian;
+ nchannels = *p_nchannels;
+ bytespersamp = *p_bytespersamp;
+ bytelimit = *p_bytelimit;
+ }
+ else
+ {
+ int bytesread = read(fd, buf, READHDRSIZE);
+ int format;
+ if (bytesread < 4)
+ goto badheader;
+ if (!strncmp(buf, ".snd", 4))
+ format = FORMAT_NEXT, bigendian = 1;
+ else if (!strncmp(buf, "dns.", 4))
+ format = FORMAT_NEXT, bigendian = 0;
+ else if (!strncmp(buf, "RIFF", 4))
+ {
+ if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4))
+ goto badheader;
+ format = FORMAT_WAVE, bigendian = 0;
+ }
+ else if (!strncmp(buf, "FORM", 4))
+ {
+ if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4))
+ goto badheader;
+ format = FORMAT_AIFF, bigendian = 1;
+ }
+ else
+ goto badheader;
+ swap = (bigendian != garray_ambigendian());
+ if (format == FORMAT_NEXT) /* nextstep header */
+ {
+ uint32 param;
+ if (bytesread < (int)sizeof(t_nextstep))
+ goto badheader;
+ nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap);
+ format = swap4(((t_nextstep *)buf)->ns_format, swap);
+ headersize = swap4(((t_nextstep *)buf)->ns_onset, swap);
+ if (format == NS_FORMAT_LINEAR_16)
+ bytespersamp = 2;
+ else if (format == NS_FORMAT_LINEAR_24)
+ bytespersamp = 3;
+ else if (format == NS_FORMAT_FLOAT)
+ bytespersamp = 4;
+ else goto badheader;
+ bytelimit = 0x7fffffff;
+ }
+ else if (format == FORMAT_WAVE) /* wave header */
+ {
+ /* This is awful. You have to skip over chunks,
+ except that if one happens to be a "fmt" chunk, you want to
+ find out the format from that one. The case where the
+ "fmt" chunk comes after the audio isn't handled. */
+ headersize = 12;
+ if (bytesread < 20)
+ goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no "fmt" chunk to follow. */
+ nchannels = 1;
+ bytespersamp = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_wavechunk));
+ /* post("chunk %c %c %c %c",
+ ((t_wavechunk *)buf)->wc_id[0],
+ ((t_wavechunk *)buf)->wc_id[1],
+ ((t_wavechunk *)buf)->wc_id[2],
+ ((t_wavechunk *)buf)->wc_id[3]); */
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_wavechunk *)buf)->wc_id, "data", 4))
+ {
+ long chunksize = swap4(((t_wavechunk *)buf)->wc_size,
+ swap), seekto = headersize + chunksize + 8, seekout;
+
+ if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4))
+ {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt))
+ goto badheader;
+ nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap);
+ format = swap2(((t_fmt *)buf)->f_nbitspersample, swap);
+ if (format == 16)
+ bytespersamp = 2;
+ else if (format == 24)
+ bytespersamp = 3;
+ else if (format == 32)
+ bytespersamp = 4;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_wavechunk)) <
+ (int) sizeof(t_wavechunk))
+ goto badheader;
+ /* post("new chunk %c %c %c %c at %d",
+ ((t_wavechunk *)buf)->wc_id[0],
+ ((t_wavechunk *)buf)->wc_id[1],
+ ((t_wavechunk *)buf)->wc_id[2],
+ ((t_wavechunk *)buf)->wc_id[3], seekto); */
+ headersize = seekto;
+ }
+ bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
+ headersize += 8;
+ }
+ else
+ {
+ /* AIFF. same as WAVE; actually predates it. Disgusting. */
+ headersize = 12;
+ if (bytesread < 20)
+ goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no COMM block to follow. */
+ nchannels = 1;
+ bytespersamp = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_datachunk));
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_datachunk *)buf)->dc_id, "SSND", 4))
+ {
+ long chunksize = swap4(((t_datachunk *)buf)->dc_size,
+ swap), seekto = headersize + chunksize + 8, seekout;
+ /* post("chunk %c %c %c %c seek %d",
+ ((t_datachunk *)buf)->dc_id[0],
+ ((t_datachunk *)buf)->dc_id[1],
+ ((t_datachunk *)buf)->dc_id[2],
+ ((t_datachunk *)buf)->dc_id[3], seekto); */
+ if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4))
+ {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_comm)) <
+ (int) sizeof(t_comm))
+ goto badheader;
+ nchannels = swap2(((t_comm *)buf)->c_nchannels, swap);
+ format = swap2(((t_comm *)buf)->c_bitspersamp, swap);
+ if (format == 16)
+ bytespersamp = 2;
+ else if (format == 24)
+ bytespersamp = 3;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_datachunk)) <
+ (int) sizeof(t_datachunk))
+ goto badheader;
+ headersize = seekto;
+ }
+ bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
+ headersize += 8;
+ }
+ }
+ /* seek past header and any sample frames to skip */
+ sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0);
+ if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
+ return (-1);
+ bytelimit -= nchannels * bytespersamp * skipframes;
+ if (bytelimit < 0)
+ bytelimit = 0;
+ /* copy sample format back to caller */
+ *p_bigendian = bigendian;
+ *p_nchannels = nchannels;
+ *p_bytespersamp = bytespersamp;
+ *p_bytelimit = bytelimit;
+ return (fd);
+badheader:
+ /* the header wasn't recognized. We're threadable here so let's not
+ print out the error... */
+ errno = EIO;
+ return (-1);
+}
+
+static void soundfile_xferin(int sfchannels, int nvecs, t_sample **vecs,
+ long itemsread, unsigned char *buf, int nitems, int bytespersamp,
+ int bigendian)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ t_sample *fp;
+ int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
+ int bytesperframe = bytespersamp * sfchannels;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = ((short*)sp2)[0]<<(fix1-16);
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
+ | (sp2[0] << 8));
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8) | sp2[3]);
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
+ | (sp2[1] << 8) | sp2[0]);
+ }
+ }
+ }
+ /* zero out other outputs */
+ for (i = sfchannels; i < nvecs; i++)
+ for (j = nitems, fp = vecs[i]; j--; )
+ *fp++ = 0;
+
+}
+
+ /* soundfiler_write ...
+
+ usage: write [flags] filename table ...
+ flags:
+ -nframes <frames>
+ -skip <frames>
+ -bytes <bytes per sample>
+ -normalize
+ -nextstep
+ -wave
+ -big
+ -little
+ */
+
+ /* the routine which actually does the work should LATER also be called
+ from garray_write16. */
+
+
+ /* Parse arguments for writing. The "obj" argument is only for flagging
+ errors. For streaming to a file the "normalize", "onset" and "nframes"
+ arguments shouldn't be set but the calling routine flags this. */
+
+static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
+ t_symbol **p_filesym,
+ int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
+ int *p_normalize, long *p_onset, long *p_nframes, float *p_rate)
+{
+ int argc = *p_argc;
+ t_atom *argv = *p_argv;
+ int bytespersamp = 2, bigendian = 0,
+ endianness = -1, swap, filetype = -1, normalize = 0;
+ long onset = 0, nframes = 0x7fffffff;
+ t_symbol *filesym;
+ float rate = -1;
+
+ while (argc > 0 && argv->a_type == A_SYMBOL &&
+ *argv->a_w.w_symbol->s_name == '-')
+ {
+ char *flag = argv->a_w.w_symbol->s_name + 1;
+ if (!strcmp(flag, "skip"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((onset = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "nframes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((nframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "bytes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((bytespersamp = argv[1].a_w.w_float) < 2) ||
+ bytespersamp > 4)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "normalize"))
+ {
+ normalize = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "wave"))
+ {
+ filetype = FORMAT_WAVE;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "nextstep"))
+ {
+ filetype = FORMAT_NEXT;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "aiff"))
+ {
+ filetype = FORMAT_AIFF;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "big"))
+ {
+ endianness = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "little"))
+ {
+ endianness = 0;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "r") || !strcmp(flag, "rate"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((rate = argv[1].a_w.w_float) <= 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else goto usage;
+ }
+ if (!argc || argv->a_type != A_SYMBOL)
+ goto usage;
+ filesym = argv->a_w.w_symbol;
+
+ /* check if format not specified and fill in */
+ if (filetype < 0)
+ {
+ if (strlen(filesym->s_name) >= 5 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
+ filetype = FORMAT_AIFF;
+ if (strlen(filesym->s_name) >= 6 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
+ filetype = FORMAT_AIFF;
+ if (strlen(filesym->s_name) >= 5 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
+ filetype = FORMAT_NEXT;
+ if (strlen(filesym->s_name) >= 4 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
+ filetype = FORMAT_NEXT;
+ if (filetype < 0)
+ filetype = FORMAT_WAVE;
+ }
+ /* don't handle AIFF floating point samples */
+ if (bytespersamp == 4)
+ {
+ if (filetype == FORMAT_AIFF)
+ {
+ pd_error(obj, "AIFF floating-point file format unavailable");
+ goto usage;
+ }
+ }
+ /* for WAVE force little endian; for nextstep use machine native */
+ if (filetype == FORMAT_WAVE)
+ {
+ bigendian = 0;
+ if (endianness == 1)
+ pd_error(obj, "WAVE file forced to little endian");
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ bigendian = 1;
+ if (endianness == 0)
+ pd_error(obj, "AIFF file forced to big endian");
+ }
+ else if (endianness == -1)
+ {
+ bigendian = garray_ambigendian();
+ }
+ else bigendian = endianness;
+ swap = (bigendian != garray_ambigendian());
+
+ argc--; argv++;
+
+ *p_argc = argc;
+ *p_argv = argv;
+ *p_filesym = filesym;
+ *p_filetype = filetype;
+ *p_bytespersamp = bytespersamp;
+ *p_swap = swap;
+ *p_normalize = normalize;
+ *p_onset = onset;
+ *p_nframes = nframes;
+ *p_bigendian = bigendian;
+ *p_rate = rate;
+ return (0);
+usage:
+ return (-1);
+}
+
+static int create_soundfile(t_canvas *canvas, const char *filename,
+ int filetype, int nframes, int bytespersamp,
+ int bigendian, int nchannels, int swap, float samplerate)
+{
+ char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
+ char headerbuf[WRITEHDRSIZE];
+ t_wave *wavehdr = (t_wave *)headerbuf;
+ t_nextstep *nexthdr = (t_nextstep *)headerbuf;
+ t_aiff *aiffhdr = (t_aiff *)headerbuf;
+ int fd, headersize = 0;
+
+ strncpy(filenamebuf, filename, MAXPDSTRING-10);
+ filenamebuf[MAXPDSTRING-10] = 0;
+
+ if (filetype == FORMAT_NEXT)
+ {
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
+ strcat(filenamebuf, ".snd");
+ if (bigendian)
+ strncpy(nexthdr->ns_fileid, ".snd", 4);
+ else strncpy(nexthdr->ns_fileid, "dns.", 4);
+ nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
+ nexthdr->ns_length = 0;
+ nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
+ (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);
+ nexthdr->ns_sr = swap4(samplerate, swap);
+ nexthdr->ns_nchans = swap4(nchannels, swap);
+ strcpy(nexthdr->ns_info, "Pd ");
+ swapstring(nexthdr->ns_info, swap);
+ headersize = sizeof(t_nextstep);
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ long longtmp;
+ static unsigned char dogdoo[] =
+ {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
+ strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
+ strcat(filenamebuf, ".aif");
+ strncpy(aiffhdr->a_fileid, "FORM", 4);
+ aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
+ strncpy(aiffhdr->a_aiffid, "AIFF", 4);
+ strncpy(aiffhdr->a_fmtid, "COMM", 4);
+ aiffhdr->a_fmtchunksize = swap4(18, swap);
+ aiffhdr->a_nchannels = swap2(nchannels, swap);
+ longtmp = swap4(nframes, swap);
+ memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
+ aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
+ memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
+ longtmp = swap4(datasize, swap);
+ memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
+ headersize = AIFFPLUS;
+ }
+ else /* WAVE format */
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
+ strcat(filenamebuf, ".wav");
+ strncpy(wavehdr->w_fileid, "RIFF", 4);
+ wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
+ strncpy(wavehdr->w_waveid, "WAVE", 4);
+ strncpy(wavehdr->w_fmtid, "fmt ", 4);
+ wavehdr->w_fmtchunksize = swap4(16, swap);
+ wavehdr->w_fmttag =
+ swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
+ wavehdr->w_nchannels = swap2(nchannels, swap);
+ wavehdr->w_samplespersec = swap4(samplerate, swap);
+ wavehdr->w_navgbytespersec =
+ swap4((int)(samplerate * nchannels * bytespersamp), swap);
+ wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap);
+ wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
+ strncpy(wavehdr->w_datachunkid, "data", 4);
+ wavehdr->w_datachunksize = swap4(datasize, swap);
+ headersize = sizeof(t_wave);
+ }
+
+ canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
+ sys_bashfilename(buf2, buf2);
+ if ((fd = open(buf2, BINCREATE, 0666)) < 0)
+ return (-1);
+
+ if (write(fd, headerbuf, headersize) < headersize)
+ {
+ close (fd);
+ return (-1);
+ }
+ return (fd);
+}
+
+static void soundfile_finishwrite(void *obj, char *filename, int fd,
+ int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
+{
+ if (itemswritten < nframes)
+ {
+ if (nframes < 0x7fffffff)
+ pd_error(obj, "soundfiler_write: %d out of %d bytes written",
+ itemswritten, nframes);
+ /* try to fix size fields in header */
+ if (filetype == FORMAT_WAVE)
+ {
+ long datasize = itemswritten * bytesperframe, mofo;
+
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ if (filetype == FORMAT_AIFF)
+ {
+ long mofo;
+ if (lseek(fd,
+ ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(nframes, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ if (filetype == FORMAT_NEXT)
+ {
+ /* do it the lazy way: just set the size field to 'unknown size'*/
+ uint32 nextsize = 0xffffffff;
+ if (lseek(fd, 8, SEEK_SET) == 0)
+ {
+ goto baddonewrite;
+ }
+ if (write(fd, &nextsize, 4) < 4)
+ {
+ goto baddonewrite;
+ }
+ }
+ }
+ return;
+baddonewrite:
+ post("%s: %s", filename, strerror(errno));
+}
+
+static void soundfile_xferout(int nchannels, t_sample **vecs,
+ unsigned char *buf, int nitems, long onset, int bytespersamp,
+ int bigendian, float normalfactor)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ t_sample *fp;
+ int bytesperframe = bytespersamp * nchannels;
+ long xx;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ float ff = normalfactor * 32768.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp = vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[0] = (xx >> 8);
+ sp2[1] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ float ff = normalfactor * 8388608.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[0] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[2] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[2] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[0] = (xx >> 24); sp2[1] = (xx >> 16);
+ sp2[2] = (xx >> 8); sp2[3] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[3] = (xx >> 24); sp2[2] = (xx >> 16);
+ sp2[1] = (xx >> 8); sp2[0] = xx;
+ }
+ }
+ }
+ }
+}
+
+
+/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
+#define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */
+#define SAMPBUFSIZE 1024
+
+
+static t_class *soundfiler_class;
+
+typedef struct _soundfiler
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+} t_soundfiler;
+
+static t_soundfiler *soundfiler_new(void)
+{
+ t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
+ x->x_canvas = canvas_getcurrent();
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+ /* soundfiler_read ...
+
+ usage: read [flags] filename table ...
+ flags:
+ -skip <frames> ... frames to skip in file
+ -nframes <frames>
+ -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian>
+ -resize
+ -maxsize <max-size>
+ */
+
+static void soundfiler_read(t_soundfiler *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
+ resize = 0, i, j;
+ long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
+ maxsize = DEFMAXSIZE, itemsread = 0, bytelimit = 0x7fffffff;
+ int fd = -1;
+ char endianness, *filename;
+ t_garray *garrays[MAXSFCHANS];
+ t_sample *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ FILE *fp;
+ while (argc > 0 && argv->a_type == A_SYMBOL &&
+ *argv->a_w.w_symbol->s_name == '-')
+ {
+ char *flag = argv->a_w.w_symbol->s_name + 1;
+ if (!strcmp(flag, "skip"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((skipframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "nframes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((nframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "raw"))
+ {
+ if (argc < 5 ||
+ argv[1].a_type != A_FLOAT ||
+ ((headersize = argv[1].a_w.w_float) < 0) ||
+ argv[2].a_type != A_FLOAT ||
+ ((channels = argv[2].a_w.w_float) < 1) ||
+ (channels > MAXSFCHANS) ||
+ argv[3].a_type != A_FLOAT ||
+ ((bytespersamp = argv[3].a_w.w_float) < 2) ||
+ (bytespersamp > 4) ||
+ argv[4].a_type != A_SYMBOL ||
+ ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
+ && endianness != 'l' && endianness != 'n'))
+ goto usage;
+ if (endianness == 'b')
+ bigendian = 1;
+ else if (endianness == 'l')
+ bigendian = 0;
+ else
+ bigendian = garray_ambigendian();
+ argc -= 5; argv += 5;
+ }
+ else if (!strcmp(flag, "resize"))
+ {
+ resize = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "maxsize"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((maxsize = argv[1].a_w.w_float) < 0))
+ goto usage;
+ resize = 1; /* maxsize implies resize. */
+ argc -= 2; argv += 2;
+ }
+ else goto usage;
+ }
+ if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
+ goto usage;
+ filename = argv[0].a_w.w_symbol->s_name;
+ argc--; argv++;
+
+ for (i = 0; i < argc; i++)
+ {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL)
+ goto usage;
+ if (!(garrays[i] =
+ (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+ {
+ pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+ goto done;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite",
+ argv[i].a_w.w_symbol->s_name);
+ if (finalsize && finalsize != vecsize && !resize)
+ {
+ post("soundfiler_read: arrays have different lengths; resizing...");
+ resize = 1;
+ }
+ finalsize = vecsize;
+ }
+ fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
+ headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
+ skipframes);
+
+ if (fd < 0)
+ {
+ pd_error(x, "soundfiler_read: %s: %s", filename, (errno == EIO ?
+ "unknown or bad header format" : strerror(errno)));
+ goto done;
+ }
+
+ if (resize)
+ {
+ /* figure out what to resize to */
+ long poswas, eofis, framesinfile;
+
+ poswas = lseek(fd, 0, SEEK_CUR);
+ eofis = lseek(fd, 0, SEEK_END);
+ if (poswas < 0 || eofis < 0)
+ {
+ pd_error(x, "lseek failed");
+ goto done;
+ }
+ lseek(fd, poswas, SEEK_SET);
+ framesinfile = (eofis - poswas) / (channels * bytespersamp);
+ if (framesinfile > maxsize)
+ {
+ pd_error(x, "soundfiler_read: truncated to %d elements", maxsize);
+ framesinfile = maxsize;
+ }
+ if (framesinfile > bytelimit / (channels * bytespersamp))
+ framesinfile = bytelimit / (channels * bytespersamp);
+ finalsize = framesinfile;
+ for (i = 0; i < argc; i++)
+ {
+ int vecsize;
+
+ garray_resize(garrays[i], finalsize);
+ /* for sanity's sake let's clear the save-in-patch flag here */
+ garray_setsaveit(garrays[i], 0);
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ /* if the resize failed, garray_resize reported the error */
+ if (vecsize != framesinfile)
+ {
+ pd_error(x, "resize failed");
+ goto done;
+ }
+ }
+ }
+ if (!finalsize) finalsize = 0x7fffffff;
+ if (finalsize > bytelimit / (channels * bytespersamp))
+ finalsize = bytelimit / (channels * bytespersamp);
+ fp = fdopen(fd, "rb");
+ bufframes = SAMPBUFSIZE / (channels * bytespersamp);
+
+ for (itemsread = 0; itemsread < finalsize; )
+ {
+ int thisread = finalsize - itemsread;
+ thisread = (thisread > bufframes ? bufframes : thisread);
+ nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
+ if (nitems <= 0) break;
+ soundfile_xferin(channels, argc, vecs, itemsread,
+ (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
+ itemsread += nitems;
+ }
+ /* zero out remaining elements of vectors */
+
+ for (i = 0; i < argc; i++)
+ {
+ int nzero, vecsize;
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ for (j = itemsread; j < vecsize; j++)
+ vecs[i][j] = 0;
+ }
+ /* zero out vectors in excess of number of channels */
+ for (i = channels; i < argc; i++)
+ {
+ int vecsize;
+ t_sample *foo;
+ garray_getfloatarray(garrays[i], &vecsize, &foo);
+ for (j = 0; j < vecsize; j++)
+ foo[j] = 0;
+ }
+ /* do all graphics updates */
+ for (i = 0; i < argc; i++)
+ garray_redraw(garrays[i]);
+ fclose(fp);
+ fd = -1;
+ goto done;
+usage:
+ pd_error(x, "usage: read [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+ post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
+done:
+ if (fd >= 0)
+ close (fd);
+ outlet_float(x->x_obj.ob_outlet, (float)itemsread);
+}
+
+ /* this is broken out from soundfiler_write below so garray_write can
+ call it too... not done yet though. */
+
+long soundfiler_dowrite(void *obj, t_canvas *canvas,
+ int argc, t_atom *argv)
+{
+ int headersize, bytespersamp, bigendian,
+ endianness, swap, filetype, normalize, i, j, nchannels;
+ long onset, nframes, itemsleft,
+ maxsize = DEFMAXSIZE, itemswritten = 0;
+ t_garray *garrays[MAXSFCHANS];
+ t_sample *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ int fd = -1;
+ float normfactor, biggest = 0, samplerate;
+ t_symbol *filesym;
+
+ if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+ &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,
+ &samplerate))
+ goto usage;
+ nchannels = argc;
+ if (nchannels < 1 || nchannels > MAXSFCHANS)
+ goto usage;
+ if (samplerate < 0)
+ samplerate = sys_getsr();
+ for (i = 0; i < nchannels; i++)
+ {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL)
+ goto usage;
+ if (!(garrays[i] =
+ (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+ {
+ pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+ goto fail;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite",
+ argv[i].a_w.w_symbol->s_name);
+ if (nframes > vecsize - onset)
+ nframes = vecsize - onset;
+
+ for (j = 0; j < vecsize; j++)
+ {
+ if (vecs[i][j] > biggest)
+ biggest = vecs[i][j];
+ else if (-vecs[i][j] > biggest)
+ biggest = -vecs[i][j];
+ }
+ }
+ if (nframes <= 0)
+ {
+ pd_error(obj, "soundfiler_write: no samples at onset %ld", onset);
+ goto fail;
+ }
+
+ if ((fd = create_soundfile(canvas, filesym->s_name, filetype,
+ nframes, bytespersamp, bigendian, nchannels,
+ swap, samplerate)) < 0)
+ {
+ post("%s: %s\n", filesym->s_name, strerror(errno));
+ goto fail;
+ }
+ if (!normalize)
+ {
+ if ((bytespersamp != 4) && (biggest > 1))
+ {
+ post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
+ normalize = 1;
+ }
+ else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
+ }
+ if (normalize)
+ normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
+ else normfactor = 1;
+
+ bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
+
+ for (itemswritten = 0; itemswritten < nframes; )
+ {
+ int thiswrite = nframes - itemswritten, nitems, nbytes;
+ thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+ soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
+ onset, bytespersamp, bigendian, normfactor);
+ nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
+ if (nbytes < nchannels * bytespersamp * thiswrite)
+ {
+ post("%s: %s", filesym->s_name, strerror(errno));
+ if (nbytes > 0)
+ itemswritten += nbytes / (nchannels * bytespersamp);
+ break;
+ }
+ itemswritten += thiswrite;
+ onset += thiswrite;
+ }
+ if (fd >= 0)
+ {
+ soundfile_finishwrite(obj, filesym->s_name, fd,
+ filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
+ close (fd);
+ }
+ return ((float)itemswritten);
+usage:
+ pd_error(obj, "usage: write [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+ post("-big -little -normalize");
+ post("(defaults to a 16-bit wave file).");
+fail:
+ if (fd >= 0)
+ close (fd);
+ return (0);
+}
+
+static void soundfiler_write(t_soundfiler *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ long bozo = soundfiler_dowrite(x, x->x_canvas,
+ argc, argv);
+ outlet_float(x->x_obj.ob_outlet, (float)bozo);
+}
+
+static void soundfiler_setup(void)
+{
+ soundfiler_class = class_new(gensym("soundfiler"), (t_newmethod)soundfiler_new,
+ 0, sizeof(t_soundfiler), 0, 0);
+ class_addmethod(soundfiler_class, (t_method)soundfiler_read, gensym("read"),
+ A_GIMME, 0);
+ class_addmethod(soundfiler_class, (t_method)soundfiler_write,
+ gensym("write"), A_GIMME, 0);
+}
+
+
+#ifndef FIXEDPOINT
+/************************* readsf object ******************************/
+
+/* READSF uses the Posix threads package; for the moment we're Linux
+only although this should be portable to the other platforms.
+
+Each instance of readsf~ owns a "child" thread for doing the UNIX (MSW?) file
+reading. The parent thread signals the child each time:
+ (1) a file wants opening or closing;
+ (2) we've eaten another 1/16 of the shared buffer (so that the
+ child thread should check if it's time to read some more.)
+The child signals the parent whenever a read has completed. Signalling
+is done by setting "conditions" and putting data in mutex-controlled common
+areas.
+*/
+
+#define MAXBYTESPERSAMPLE 4
+#define MAXVECSIZE 128
+
+#define READSIZE 65536
+#define WRITESIZE 65536
+#define DEFBUFPERCHAN 262144
+#define MINBUFSIZE (4 * READSIZE)
+#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
+
+#define REQUEST_NOTHING 0
+#define REQUEST_OPEN 1
+#define REQUEST_CLOSE 2
+#define REQUEST_QUIT 3
+#define REQUEST_BUSY 4
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1
+#define STATE_STREAM 2
+
+static t_class *readsf_class;
+
+typedef struct _readsf
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ t_clock *x_clock;
+ char *x_buf; /* soundfile buffer */
+ int x_bufsize; /* buffer size in bytes */
+ int x_noutlets; /* number of audio outlets */
+ t_sample *(x_outvec[MAXSFCHANS]); /* audio vectors */
+ int x_vecsize; /* vector size for transfers */
+ t_outlet *x_bangout; /* bang-on-done outlet */
+ int x_state; /* opened, running, or idle */
+ float x_insamplerate; /* sample rate of input signal if known */
+ /* parameters to communicate with subthread */
+ int x_requestcode; /* pending request from parent to I/O thread */
+ char *x_filename; /* file to open (string is permanently allocated) */
+ int x_fileerror; /* slot for "errno" return */
+ int x_skipheaderbytes; /* size of header we'll skip */
+ int x_bytespersample; /* bytes per sample (2 or 3) */
+ int x_bigendian; /* true if file is big-endian */
+ int x_sfchannels; /* number of channels in soundfile */
+ float x_samplerate; /* sample rate of soundfile */
+ long x_onsetframes; /* number of sample frames to skip */
+ long x_bytelimit; /* max number of data bytes to read */
+ int x_fd; /* filedesc */
+ int x_fifosize; /* buffer size appropriately rounded down */
+ int x_fifohead; /* index of next byte to get from file */
+ int x_fifotail; /* index of next byte the ugen will read */
+ int x_eof; /* true if fifohead has stopped changing */
+ int x_sigcountdown; /* counter for signalling child for more data */
+ int x_sigperiod; /* number of ticks per signal */
+ int x_filetype; /* writesf~ only; type of file to create */
+ int x_itemswritten; /* writesf~ only; items writen */
+ int x_swap; /* writesf~ only; true if byte swapping */
+ float x_f; /* writesf~ only; scalar for signal inlet */
+ pthread_mutex_t x_mutex;
+ pthread_cond_t x_requestcondition;
+ pthread_cond_t x_answercondition;
+ pthread_t x_childthread;
+} t_readsf;
+
+
+/************** the child thread which performs file I/O ***********/
+
+#if 0
+static void pute(char *s) /* debug routine */
+{
+ write(2, s, strlen(s));
+}
+#define DEBUG_SOUNDFILE
+#endif
+
+#if 1
+#define sfread_cond_wait pthread_cond_wait
+#define sfread_cond_signal pthread_cond_signal
+#else
+#include <sys/time.h> /* debugging version... */
+#include <sys/types.h>
+static void readsf_fakewait(pthread_mutex_t *b)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 1000000;
+ pthread_mutex_unlock(b);
+ select(0, 0, 0, 0, &timout);
+ pthread_mutex_lock(b);
+}
+
+#define sfread_cond_wait(a,b) readsf_fakewait(b)
+#define sfread_cond_signal(a)
+#endif
+
+static void *readsf_child_main(void *zz)
+{
+ t_readsf *x = zz;
+#ifdef DEBUG_SOUNDFILE
+ pute("1\n");
+#endif
+ pthread_mutex_lock(&x->x_mutex);
+ while (1)
+ {
+ int fd, fifohead;
+ char *buf;
+#ifdef DEBUG_SOUNDFILE
+ pute("0\n");
+#endif
+ if (x->x_requestcode == REQUEST_NOTHING)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("wait 2\n");
+#endif
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("3\n");
+#endif
+ }
+ else if (x->x_requestcode == REQUEST_OPEN)
+ {
+ char boo[80];
+ int sysrtn, wantbytes;
+
+ /* copy file stuff out of the data structure so we can
+ relinquish the mutex while we're in open_soundfile(). */
+ long onsetframes = x->x_onsetframes;
+ long bytelimit = 0x7fffffff;
+ int skipheaderbytes = x->x_skipheaderbytes;
+ int bytespersample = x->x_bytespersample;
+ int sfchannels = x->x_sfchannels;
+ int bigendian = x->x_bigendian;
+ char *filename = x->x_filename;
+ char *dirname = canvas_getdir(x->x_canvas)->s_name;
+ /* alter the request code so that an ensuing "open" will get
+ noticed. */
+#ifdef DEBUG_SOUNDFILE
+ pute("4\n");
+#endif
+ x->x_requestcode = REQUEST_BUSY;
+ x->x_fileerror = 0;
+
+ /* if there's already a file open, close it */
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ if (x->x_requestcode != REQUEST_BUSY)
+ goto lost;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->x_mutex);
+ fd = open_soundfile(dirname, filename,
+ skipheaderbytes, &bytespersample, &bigendian,
+ &sfchannels, &bytelimit, onsetframes);
+ pthread_mutex_lock(&x->x_mutex);
+
+#ifdef DEBUG_SOUNDFILE
+ pute("5\n");
+#endif
+ /* copy back into the instance structure. */
+ x->x_bytespersample = bytespersample;
+ x->x_sfchannels = sfchannels;
+ x->x_bigendian = bigendian;
+ x->x_fd = fd;
+ x->x_bytelimit = bytelimit;
+ if (fd < 0)
+ {
+ x->x_fileerror = errno;
+ x->x_eof = 1;
+#ifdef DEBUG_SOUNDFILE
+ pute("open failed\n");
+ pute(filename);
+ pute(dirname);
+#endif
+ goto lost;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->x_requestcode != REQUEST_BUSY)
+ goto lost;
+#ifdef DEBUG_SOUNDFILE
+ pute("6\n");
+#endif
+ x->x_fifohead = 0;
+ /* set fifosize from bufsize. fifosize must be a
+ multiple of the number of bytes eaten for each DSP
+ tick. We pessimistically assume MAXVECSIZE samples
+ per tick since that could change. There could be a
+ problem here if the vector size increases while a
+ soundfile is being played... */
+ x->x_fifosize = x->x_bufsize - (x->x_bufsize %
+ (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
+ /* arrange for the "request" condition to be signalled 16
+ times per buffer */
+#ifdef DEBUG_SOUNDFILE
+ sprintf(boo, "fifosize %d\n",
+ x->x_fifosize);
+ pute(boo);
+#endif
+ x->x_sigcountdown = x->x_sigperiod =
+ (x->x_fifosize /
+ (16 * x->x_bytespersample * x->x_sfchannels *
+ x->x_vecsize));
+ /* in a loop, wait for the fifo to get hungry and feed it */
+
+ while (x->x_requestcode == REQUEST_BUSY)
+ {
+ int fifosize = x->x_fifosize;
+#ifdef DEBUG_SOUNDFILE
+ pute("77\n");
+#endif
+ if (x->x_eof)
+ break;
+ if (x->x_fifohead >= x->x_fifotail)
+ {
+ /* if the head is >= the tail, we can immediately read
+ to the end of the fifo. Unless, that is, we would
+ read all the way to the end of the buffer and the
+ "tail" is zero; this would fill the buffer completely
+ which isn't allowed because you can't tell a completely
+ full buffer from an empty one. */
+ if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
+ {
+ wantbytes = fifosize - x->x_fifohead;
+ if (wantbytes > READSIZE)
+ wantbytes = READSIZE;
+ if (wantbytes > x->x_bytelimit)
+ wantbytes = x->x_bytelimit;
+#ifdef DEBUG_SOUNDFILE
+ sprintf(boo, "head %d, tail %d, size %d\n",
+ x->x_fifohead, x->x_fifotail, wantbytes);
+ pute(boo);
+#endif
+ }
+ else
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("wait 7a ...\n");
+#endif
+ sfread_cond_signal(&x->x_answercondition);
+#ifdef DEBUG_SOUNDFILE
+ pute("signalled\n");
+#endif
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("7a done\n");
+#endif
+ continue;
+ }
+ }
+ else
+ {
+ /* otherwise check if there are at least READSIZE
+ bytes to read. If not, wait and loop back. */
+ wantbytes = x->x_fifotail - x->x_fifohead - 1;
+ if (wantbytes < READSIZE)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("wait 7...\n");
+#endif
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("7 done\n");
+#endif
+ continue;
+ }
+ else wantbytes = READSIZE;
+ if (wantbytes > x->x_bytelimit)
+ wantbytes = x->x_bytelimit;
+ }
+#ifdef DEBUG_SOUNDFILE
+ pute("8\n");
+#endif
+ fd = x->x_fd;
+ buf = x->x_buf;
+ fifohead = x->x_fifohead;
+ pthread_mutex_unlock(&x->x_mutex);
+ sysrtn = read(fd, buf + fifohead, wantbytes);
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_requestcode != REQUEST_BUSY)
+ break;
+ if (sysrtn < 0)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("fileerror\n");
+#endif
+ x->x_fileerror = errno;
+ break;
+ }
+ else if (sysrtn == 0)
+ {
+ x->x_eof = 1;
+ break;
+ }
+ else
+ {
+ x->x_fifohead += sysrtn;
+ x->x_bytelimit -= sysrtn;
+ if (x->x_bytelimit <= 0)
+ {
+ x->x_eof = 1;
+ break;
+ }
+ if (x->x_fifohead == fifosize)
+ x->x_fifohead = 0;
+ }
+#ifdef DEBUG_SOUNDFILE
+ sprintf(boo, "after: head %d, tail %d\n",
+ x->x_fifohead, x->x_fifotail);
+ pute(boo);
+#endif
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ lost:
+
+ if (x->x_requestcode == REQUEST_BUSY)
+ x->x_requestcode = REQUEST_NOTHING;
+ /* fell out of read loop: close file if necessary,
+ set EOF and signal once more */
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ sfread_cond_signal(&x->x_answercondition);
+
+ }
+ else if (x->x_requestcode == REQUEST_CLOSE)
+ {
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ if (x->x_requestcode == REQUEST_CLOSE)
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ else if (x->x_requestcode == REQUEST_QUIT)
+ {
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ break;
+ }
+ else
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("13\n");
+#endif
+ }
+ }
+#ifdef DEBUG_SOUNDFILE
+ pute("thread exit\n");
+#endif
+ pthread_mutex_unlock(&x->x_mutex);
+ return (0);
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void readsf_tick(t_readsf *x);
+
+static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
+{
+ t_readsf *x;
+ int nchannels = fnchannels, bufsize = fbufsize, i;
+ char *buf;
+
+ if (nchannels < 1)
+ nchannels = 1;
+ else if (nchannels > MAXSFCHANS)
+ nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE)
+ bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE)
+ bufsize = MAXBUFSIZE;
+ buf = getbytes(bufsize);
+ if (!buf) return (0);
+
+ x = (t_readsf *)pd_new(readsf_class);
+
+ for (i = 0; i < nchannels; i++)
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_noutlets = nchannels;
+ x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+ pthread_mutex_init(&x->x_mutex, 0);
+ pthread_cond_init(&x->x_requestcondition, 0);
+ pthread_cond_init(&x->x_answercondition, 0);
+ x->x_vecsize = MAXVECSIZE;
+ x->x_state = STATE_IDLE;
+ x->x_clock = clock_new(x, (t_method)readsf_tick);
+ x->x_canvas = canvas_getcurrent();
+ x->x_bytespersample = 2;
+ x->x_sfchannels = 1;
+ x->x_fd = -1;
+ x->x_buf = buf;
+ x->x_bufsize = bufsize;
+ x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
+ pthread_create(&x->x_childthread, 0, readsf_child_main, x);
+ return (x);
+}
+
+static void readsf_tick(t_readsf *x)
+{
+ outlet_bang(x->x_bangout);
+}
+
+static t_int *readsf_perform(t_int *w)
+{
+ t_readsf *x = (t_readsf *)(w[1]);
+ int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
+ bytespersample = x->x_bytespersample,
+ bigendian = x->x_bigendian;
+ float *fp;
+ if (x->x_state == STATE_STREAM)
+ {
+ int wantbytes, nchannels, sfchannels = x->x_sfchannels;
+ pthread_mutex_lock(&x->x_mutex);
+ wantbytes = sfchannels * vecsize * bytespersample;
+ while (
+ !x->x_eof && x->x_fifohead >= x->x_fifotail &&
+ x->x_fifohead < x->x_fifotail + wantbytes-1)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("wait...\n");
+#endif
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("done\n");
+#endif
+ }
+ if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
+ x->x_fifohead < x->x_fifotail + wantbytes-1)
+ {
+ int xfersize;
+ if (x->x_fileerror)
+ {
+ pd_error(x, "dsp: %s: %s", x->x_filename,
+ (x->x_fileerror == EIO ?
+ "unknown or bad header format" :
+ strerror(x->x_fileerror)));
+ }
+ clock_delay(x->x_clock, 0);
+ x->x_state = STATE_IDLE;
+
+ /* if there's a partial buffer left, copy it out. */
+ xfersize = (x->x_fifohead - x->x_fifotail + 1) /
+ (sfchannels * bytespersample);
+ if (xfersize)
+ {
+ soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
+ (unsigned char *)(x->x_buf + x->x_fifotail), xfersize,
+ bytespersample, bigendian);
+ vecsize -= xfersize;
+ }
+ /* then zero out the (rest of the) output */
+ for (i = 0; i < noutlets; i++)
+ for (j = vecsize, fp = x->x_outvec[i] + xfersize; j--; )
+ *fp++ = 0;
+
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+ return (w+2);
+ }
+
+ soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
+ (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
+ bytespersample, bigendian);
+
+ x->x_fifotail += wantbytes;
+ if (x->x_fifotail >= x->x_fifosize)
+ x->x_fifotail = 0;
+ if ((--x->x_sigcountdown) <= 0)
+ {
+ sfread_cond_signal(&x->x_requestcondition);
+ x->x_sigcountdown = x->x_sigperiod;
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ }
+ else
+ {
+ idle:
+ for (i = 0; i < noutlets; i++)
+ for (j = vecsize, fp = x->x_outvec[i]; j--; )
+ *fp++ = 0;
+ }
+ return (w+2);
+}
+
+static void readsf_start(t_readsf *x)
+{
+ /* start making output. If we're in the "startup" state change
+ to the "running" state. */
+ if (x->x_state == STATE_STARTUP)
+ x->x_state = STATE_STREAM;
+ else pd_error(x, "readsf: start requested with no prior 'open'");
+}
+
+static void readsf_stop(t_readsf *x)
+{
+ /* LATER rethink whether you need the mutex just to set a variable? */
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_CLOSE;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_float(t_readsf *x, t_floatarg f)
+{
+ if (f != 0)
+ readsf_start(x);
+ else readsf_stop(x);
+}
+
+ /* open method. Called as:
+ open filename [skipframes headersize channels bytespersamp endianness]
+ (if headersize is zero, header is taken to be automatically
+ detected; thus, use the special "-1" to mean a truly headerless file.)
+ */
+
+static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
+ t_float onsetframes = atom_getfloatarg(1, argc, argv);
+ t_float headerbytes = atom_getfloatarg(2, argc, argv);
+ t_float channels = atom_getfloatarg(3, argc, argv);
+ t_float bytespersamp = atom_getfloatarg(4, argc, argv);
+ t_symbol *endian = atom_getsymbolarg(5, argc, argv);
+ if (!*filesym->s_name)
+ return;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_OPEN;
+ x->x_filename = filesym->s_name;
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+ if (*endian->s_name == 'b')
+ x->x_bigendian = 1;
+ else if (*endian->s_name == 'l')
+ x->x_bigendian = 0;
+ else if (*endian->s_name)
+ pd_error(x, "endianness neither 'b' nor 'l'");
+ else x->x_bigendian = garray_ambigendian();
+ x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
+ x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes :
+ (headerbytes == 0 ? -1 : 0));
+ x->x_sfchannels = (channels >= 1 ? channels : 1);
+ x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
+ x->x_eof = 0;
+ x->x_fileerror = 0;
+ x->x_state = STATE_STARTUP;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_dsp(t_readsf *x, t_signal **sp)
+{
+ int i, noutlets = x->x_noutlets;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vecsize = sp[0]->s_n;
+
+ x->x_sigperiod = (x->x_fifosize /
+ (x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
+ for (i = 0; i < noutlets; i++)
+ x->x_outvec[i] = sp[i]->s_vec;
+ pthread_mutex_unlock(&x->x_mutex);
+ dsp_add(readsf_perform, 1, x);
+}
+
+static void readsf_print(t_readsf *x)
+{
+ post("state %d", x->x_state);
+ post("fifo head %d", x->x_fifohead);
+ post("fifo tail %d", x->x_fifotail);
+ post("fifo size %d", x->x_fifosize);
+ post("fd %d", x->x_fd);
+ post("eof %d", x->x_eof);
+}
+
+static void readsf_free(t_readsf *x)
+{
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_QUIT;
+ sfread_cond_signal(&x->x_requestcondition);
+ while (x->x_requestcode != REQUEST_NOTHING)
+ {
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ if (pthread_join(x->x_childthread, &threadrtn))
+ error("readsf_free: join failed");
+
+ pthread_cond_destroy(&x->x_requestcondition);
+ pthread_cond_destroy(&x->x_answercondition);
+ pthread_mutex_destroy(&x->x_mutex);
+ freebytes(x->x_buf, x->x_bufsize);
+ clock_free(x->x_clock);
+}
+
+static void readsf_setup(void)
+{
+ readsf_class = class_new(gensym("readsf~"), (t_newmethod)readsf_new,
+ (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(readsf_class, (t_method)readsf_float);
+ class_addmethod(readsf_class, (t_method)readsf_start, gensym("start"), 0);
+ class_addmethod(readsf_class, (t_method)readsf_stop, gensym("stop"), 0);
+ class_addmethod(readsf_class, (t_method)readsf_dsp, gensym("dsp"), 0);
+ class_addmethod(readsf_class, (t_method)readsf_open, gensym("open"),
+ A_GIMME, 0);
+ class_addmethod(readsf_class, (t_method)readsf_print, gensym("print"), 0);
+}
+
+/******************************* writesf *******************/
+
+static t_class *writesf_class;
+
+#define t_writesf t_readsf /* just re-use the structure */
+
+/************** the child thread which performs file I/O ***********/
+
+static void *writesf_child_main(void *zz)
+{
+ t_writesf *x = zz;
+#ifdef DEBUG_SOUNDFILE
+ pute("1\n");
+#endif
+ pthread_mutex_lock(&x->x_mutex);
+ while (1)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("0\n");
+#endif
+ if (x->x_requestcode == REQUEST_NOTHING)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("wait 2\n");
+#endif
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("3\n");
+#endif
+ }
+ else if (x->x_requestcode == REQUEST_OPEN)
+ {
+ char boo[80];
+ int fd, sysrtn, writebytes;
+
+ /* copy file stuff out of the data structure so we can
+ relinquish the mutex while we're in open_soundfile(). */
+ long onsetframes = x->x_onsetframes;
+ long bytelimit = 0x7fffffff;
+ int skipheaderbytes = x->x_skipheaderbytes;
+ int bytespersample = x->x_bytespersample;
+ int sfchannels = x->x_sfchannels;
+ int bigendian = x->x_bigendian;
+ int filetype = x->x_filetype;
+ char *filename = x->x_filename;
+ t_canvas *canvas = x->x_canvas;
+ float samplerate = x->x_samplerate;
+
+ /* alter the request code so that an ensuing "open" will get
+ noticed. */
+#ifdef DEBUG_SOUNDFILE
+ pute("4\n");
+#endif
+ x->x_requestcode = REQUEST_BUSY;
+ x->x_fileerror = 0;
+
+ /* if there's already a file open, close it */
+ if (x->x_fd >= 0)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ close (x->x_fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ if (x->x_requestcode != REQUEST_BUSY)
+ continue;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->x_mutex);
+ fd = create_soundfile(canvas, filename, filetype, 0,
+ bytespersample, bigendian, sfchannels,
+ garray_ambigendian() != bigendian, samplerate);
+ pthread_mutex_lock(&x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("5\n");
+#endif
+
+ if (fd < 0)
+ {
+ x->x_fd = -1;
+ x->x_eof = 1;
+ x->x_fileerror = errno;
+#ifdef DEBUG_SOUNDFILE
+ pute("open failed\n");
+ pute(filename);
+#endif
+ x->x_requestcode = REQUEST_NOTHING;
+ continue;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->x_requestcode != REQUEST_BUSY)
+ continue;
+#ifdef DEBUG_SOUNDFILE
+ pute("6\n");
+#endif
+ x->x_fd = fd;
+ x->x_fifotail = 0;
+ x->x_itemswritten = 0;
+ x->x_swap = garray_ambigendian() != bigendian;
+ /* in a loop, wait for the fifo to have data and write it
+ to disk */
+ while (x->x_requestcode == REQUEST_BUSY ||
+ (x->x_requestcode == REQUEST_CLOSE &&
+ x->x_fifohead != x->x_fifotail))
+ {
+ int fifosize = x->x_fifosize, fifotail;
+ char *buf = x->x_buf;
+#ifdef DEBUG_SOUNDFILE
+ pute("77\n");
+#endif
+
+ /* if the head is < the tail, we can immediately write
+ from tail to end of fifo to disk; otherwise we hold off
+ writing until there are at least WRITESIZE bytes in the
+ buffer */
+ if (x->x_fifohead < x->x_fifotail ||
+ x->x_fifohead >= x->x_fifotail + WRITESIZE
+ || (x->x_requestcode == REQUEST_CLOSE &&
+ x->x_fifohead != x->x_fifotail))
+ {
+ writebytes = (x->x_fifohead < x->x_fifotail ?
+ fifosize : x->x_fifohead) - x->x_fifotail;
+ if (writebytes > READSIZE)
+ writebytes = READSIZE;
+ }
+ else
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("wait 7a ...\n");
+#endif
+ sfread_cond_signal(&x->x_answercondition);
+#ifdef DEBUG_SOUNDFILE
+ pute("signalled\n");
+#endif
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("7a done\n");
+#endif
+ continue;
+ }
+#ifdef DEBUG_SOUNDFILE
+ pute("8\n");
+#endif
+ fifotail = x->x_fifotail;
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ sysrtn = write(fd, buf + fifotail, writebytes);
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_requestcode != REQUEST_BUSY &&
+ x->x_requestcode != REQUEST_CLOSE)
+ break;
+ if (sysrtn < writebytes)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("fileerror\n");
+#endif
+ x->x_fileerror = errno;
+ break;
+ }
+ else
+ {
+ x->x_fifotail += sysrtn;
+ if (x->x_fifotail == fifosize)
+ x->x_fifotail = 0;
+ }
+ x->x_itemswritten +=
+ sysrtn / (x->x_bytespersample * x->x_sfchannels);
+ sprintf(boo, "after: head %d, tail %d\n",
+ x->x_fifohead, x->x_fifotail);
+#ifdef DEBUG_SOUNDFILE
+ pute(boo);
+#endif
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ }
+ else if (x->x_requestcode == REQUEST_CLOSE ||
+ x->x_requestcode == REQUEST_QUIT)
+ {
+ int quit = (x->x_requestcode == REQUEST_QUIT);
+ if (x->x_fd >= 0)
+ {
+ int bytesperframe = x->x_bytespersample * x->x_sfchannels;
+ int bigendian = x->x_bigendian;
+ char *filename = x->x_filename;
+ int fd = x->x_fd;
+ int filetype = x->x_filetype;
+ int itemswritten = x->x_itemswritten;
+ int swap = x->x_swap;
+ pthread_mutex_unlock(&x->x_mutex);
+
+ soundfile_finishwrite(x, filename, fd,
+ filetype, 0x7fffffff, itemswritten,
+ bytesperframe, swap);
+ close (fd);
+
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ if (quit)
+ break;
+ }
+ else
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("13\n");
+#endif
+ }
+ }
+#ifdef DEBUG_SOUNDFILE
+ pute("thread exit\n");
+#endif
+ pthread_mutex_unlock(&x->x_mutex);
+ return (0);
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void writesf_tick(t_writesf *x);
+
+static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize)
+{
+ t_writesf *x;
+ int nchannels = fnchannels, bufsize = fbufsize, i;
+ char *buf;
+
+ if (nchannels < 1)
+ nchannels = 1;
+ else if (nchannels > MAXSFCHANS)
+ nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE)
+ bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE)
+ bufsize = MAXBUFSIZE;
+ buf = getbytes(bufsize);
+ if (!buf) return (0);
+
+ x = (t_writesf *)pd_new(writesf_class);
+
+ for (i = 1; i < nchannels; i++)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+
+ x->x_f = 0;
+ x->x_sfchannels = nchannels;
+ pthread_mutex_init(&x->x_mutex, 0);
+ pthread_cond_init(&x->x_requestcondition, 0);
+ pthread_cond_init(&x->x_answercondition, 0);
+ x->x_vecsize = MAXVECSIZE;
+ x->x_insamplerate = x->x_samplerate = 0;
+ x->x_state = STATE_IDLE;
+ x->x_clock = 0; /* no callback needed here */
+ x->x_canvas = canvas_getcurrent();
+ x->x_bytespersample = 2;
+ x->x_fd = -1;
+ x->x_buf = buf;
+ x->x_bufsize = bufsize;
+ x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
+ pthread_create(&x->x_childthread, 0, writesf_child_main, x);
+ return (x);
+}
+
+static t_int *writesf_perform(t_int *w)
+{
+ t_writesf *x = (t_writesf *)(w[1]);
+ int vecsize = x->x_vecsize, sfchannels = x->x_sfchannels, i, j,
+ bytespersample = x->x_bytespersample,
+ bigendian = x->x_bigendian;
+ float *fp;
+ if (x->x_state == STATE_STREAM)
+ {
+ int wantbytes;
+ pthread_mutex_lock(&x->x_mutex);
+ wantbytes = sfchannels * vecsize * bytespersample;
+ while (x->x_fifotail > x->x_fifohead &&
+ x->x_fifotail < x->x_fifohead + wantbytes + 1)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("wait...\n");
+#endif
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+#ifdef DEBUG_SOUNDFILE
+ pute("done\n");
+#endif
+ }
+
+ soundfile_xferout(sfchannels, x->x_outvec,
+ (unsigned char *)(x->x_buf + x->x_fifohead), vecsize, 0,
+ bytespersample, bigendian, 1.);
+
+ x->x_fifohead += wantbytes;
+ if (x->x_fifohead >= x->x_fifosize)
+ x->x_fifohead = 0;
+ if ((--x->x_sigcountdown) <= 0)
+ {
+#ifdef DEBUG_SOUNDFILE
+ pute("signal 1\n");
+#endif
+ sfread_cond_signal(&x->x_requestcondition);
+ x->x_sigcountdown = x->x_sigperiod;
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ }
+ return (w+2);
+}
+
+static void writesf_start(t_writesf *x)
+{
+ /* start making output. If we're in the "startup" state change
+ to the "running" state. */
+ if (x->x_state == STATE_STARTUP)
+ x->x_state = STATE_STREAM;
+ else
+ pd_error(x, "writesf: start requested with no prior 'open'");
+}
+
+static void writesf_stop(t_writesf *x)
+{
+ /* LATER rethink whether you need the mutex just to set a Svariable? */
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_CLOSE;
+#ifdef DEBUG_SOUNDFILE
+ pute("signal 2\n");
+#endif
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+ /* open method. Called as: open [args] filename with args as in
+ soundfiler_writeargparse().
+ */
+
+static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *filesym;
+ int filetype, bytespersamp, swap, bigendian, normalize;
+ long onset, nframes;
+ float samplerate;
+ if (soundfiler_writeargparse(x, &argc,
+ &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian,
+ &normalize, &onset, &nframes, &samplerate))
+ {
+ pd_error(x,
+ "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
+ post("... [-big,-little] [-rate ####] filename");
+ }
+ if (normalize || onset || (nframes != 0x7fffffff))
+ pd_error(x, "normalize/onset/nframes argument to writesf~: ignored");
+ if (argc)
+ pd_error(x, "extra argument(s) to writesf~: ignored");
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_bytespersample = bytespersamp;
+ x->x_swap = swap;
+ x->x_bigendian = bigendian;
+ x->x_filename = filesym->s_name;
+ x->x_filetype = filetype;
+ x->x_itemswritten = 0;
+ x->x_requestcode = REQUEST_OPEN;
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+ x->x_eof = 0;
+ x->x_fileerror = 0;
+ x->x_state = STATE_STARTUP;
+ x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
+ if (samplerate > 0)
+ x->x_samplerate = samplerate;
+ else if (x->x_insamplerate > 0)
+ x->x_samplerate = x->x_insamplerate;
+ else x->x_samplerate = sys_getsr();
+ /* set fifosize from bufsize. fifosize must be a
+ multiple of the number of bytes eaten for each DSP
+ tick. */
+ x->x_fifosize = x->x_bufsize - (x->x_bufsize %
+ (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
+ /* arrange for the "request" condition to be signalled 16
+ times per buffer */
+ x->x_sigcountdown = x->x_sigperiod =
+ (x->x_fifosize /
+ (16 * x->x_bytespersample * x->x_sfchannels *
+ x->x_vecsize));
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void writesf_dsp(t_writesf *x, t_signal **sp)
+{
+ int i, ninlets = x->x_sfchannels;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vecsize = sp[0]->s_n;
+
+ x->x_sigperiod = (x->x_fifosize /
+ (x->x_bytespersample * ninlets * x->x_vecsize));
+ for (i = 0; i < ninlets; i++)
+ x->x_outvec[i] = sp[i]->s_vec;
+ x->x_insamplerate = sp[0]->s_sr;
+ pthread_mutex_unlock(&x->x_mutex);
+ dsp_add(writesf_perform, 1, x);
+}
+
+static void writesf_print(t_writesf *x)
+{
+ post("state %d", x->x_state);
+ post("fifo head %d", x->x_fifohead);
+ post("fifo tail %d", x->x_fifotail);
+ post("fifo size %d", x->x_fifosize);
+ post("fd %d", x->x_fd);
+ post("eof %d", x->x_eof);
+}
+
+static void writesf_free(t_writesf *x)
+{
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_QUIT;
+ /* post("stopping writesf thread..."); */
+ sfread_cond_signal(&x->x_requestcondition);
+ while (x->x_requestcode != REQUEST_NOTHING)
+ {
+ /* post("signalling..."); */
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ if (pthread_join(x->x_childthread, &threadrtn))
+ error("writesf_free: join failed");
+ /* post("... done."); */
+
+ pthread_cond_destroy(&x->x_requestcondition);
+ pthread_cond_destroy(&x->x_answercondition);
+ pthread_mutex_destroy(&x->x_mutex);
+ freebytes(x->x_buf, x->x_bufsize);
+}
+
+static void writesf_setup(void)
+{
+ writesf_class = class_new(gensym("writesf~"), (t_newmethod)writesf_new,
+ (t_method)writesf_free, sizeof(t_writesf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(writesf_class, (t_method)writesf_start, gensym("start"), 0);
+ class_addmethod(writesf_class, (t_method)writesf_stop, gensym("stop"), 0);
+ class_addmethod(writesf_class, (t_method)writesf_dsp, gensym("dsp"), 0);
+ class_addmethod(writesf_class, (t_method)writesf_open, gensym("open"),
+ A_GIMME, 0);
+ class_addmethod(writesf_class, (t_method)writesf_print, gensym("print"), 0);
+ CLASS_MAINSIGNALIN(writesf_class, t_writesf, x_f);
+}
+
+#endif
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_soundfile_setup(void)
+{
+ soundfiler_setup();
+#ifndef FIXEDPOINT
+ readsf_setup();
+ writesf_setup();
+#endif
+}
+
+/* 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. */
+
+/* this file contains, first, a collection of soundfile access routines, a
+sort of soundfile library. Second, the "soundfiler" object is defined which
+uses the routines to read or write soundfiles, synchronously, from garrays.
+These operations are not to be done in "real time" as they may have to wait
+for disk accesses (even the write routine.) Finally, the realtime objects
+readsf~ and writesf~ are defined which confine disk operations to a separate
+thread so that they can be used in real time. The readsf~ and writesf~
+objects use Posix-like threads. */
+
+#ifdef UNIX
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#include <pthread.h>
+#ifdef MSW
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "m_pd.h"
+
+#define MAXSFCHANS 64
+
+/***************** soundfile header structures ************************/
+
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+
+/* the NeXTStep sound header structure; can be big or little endian */
+
+typedef struct _nextstep
+{
+ char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
+ uint32 ns_onset; /* byte offset of first sample */
+ uint32 ns_length; /* length of sound in bytes */
+ uint32 ns_format; /* format; see below */
+ uint32 ns_sr; /* sample rate */
+ uint32 ns_nchans; /* number of channels */
+ char ns_info[4]; /* comment */
+} t_nextstep;
+
+#define NS_FORMAT_LINEAR_16 3
+#define NS_FORMAT_LINEAR_24 4
+#define NS_FORMAT_FLOAT 6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+/* the WAVE header. All Wave files are little endian. We assume
+ the "fmt" chunk comes first which is usually the case but perhaps not
+ always; same for AIFF and the "COMM" chunk. */
+
+typedef unsigned word;
+typedef unsigned long dword;
+
+typedef struct _wave
+{
+ char w_fileid[4]; /* chunk id 'RIFF' */
+ uint32 w_chunksize; /* chunk size */
+ char w_waveid[4]; /* wave chunk id 'WAVE' */
+ char w_fmtid[4]; /* format chunk id 'fmt ' */
+ uint32 w_fmtchunksize; /* format chunk size */
+ uint16 w_fmttag; /* format tag (WAV_INT etc) */
+ uint16 w_nchannels; /* number of channels */
+ uint32 w_samplespersec; /* sample rate in hz */
+ uint32 w_navgbytespersec; /* average bytes per second */
+ uint16 w_nblockalign; /* number of bytes per frame */
+ uint16 w_nbitspersample; /* number of bits in a sample */
+ char w_datachunkid[4]; /* data chunk id 'data' */
+ uint32 w_datachunksize; /* length of data chunk */
+} t_wave;
+
+typedef struct _fmt /* format chunk */
+{
+ uint16 f_fmttag; /* format tag, 1 for PCM */
+ uint16 f_nchannels; /* number of channels */
+ uint32 f_samplespersec; /* sample rate in hz */
+ uint32 f_navgbytespersec; /* average bytes per second */
+ uint16 f_nblockalign; /* number of bytes per frame */
+ uint16 f_nbitspersample; /* number of bits in a sample */
+} t_fmt;
+
+typedef struct _wavechunk /* ... and the last two items */
+{
+ char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
+ uint32 wc_size; /* length of data chunk */
+} t_wavechunk;
+
+#define WAV_INT 1
+#define WAV_FLOAT 3
+
+/* the AIFF header. I'm assuming AIFC is compatible but don't really know
+ that. */
+
+typedef struct _datachunk
+{
+ char dc_id[4]; /* data chunk id 'SSND' */
+ uint32 dc_size; /* length of data chunk */
+} t_datachunk;
+
+typedef struct _comm
+{
+ uint16 c_nchannels; /* number of channels */
+ uint16 c_nframeshi; /* # of sample frames (hi) */
+ uint16 c_nframeslo; /* # of sample frames (lo) */
+ uint16 c_bitspersamp; /* bits per sample */
+ unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
+} t_comm;
+
+ /* this version is more convenient for writing them out: */
+typedef struct _aiff
+{
+ char a_fileid[4]; /* chunk id 'FORM' */
+ uint32 a_chunksize; /* chunk size */
+ char a_aiffid[4]; /* aiff chunk id 'AIFF' */
+ char a_fmtid[4]; /* format chunk id 'COMM' */
+ uint32 a_fmtchunksize; /* format chunk size, 18 */
+ uint16 a_nchannels; /* number of channels */
+ uint16 a_nframeshi; /* # of sample frames (hi) */
+ uint16 a_nframeslo; /* # of sample frames (lo) */
+ uint16 a_bitspersamp; /* bits per sample */
+ unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
+} t_aiff;
+
+#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
+
+
+#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
+
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+
+#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
+
+#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
+
+#ifdef MSW
+#include <fcntl.h>
+#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
+#else
+#define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
+#endif
+
+/* this routine returns 1 if the high order byte comes at the lower
+address on our architecture (big-endianness.). It's 1 for Motorola,
+0 for Intel: */
+
+extern int garray_ambigendian(void);
+
+/* byte swappers */
+
+static uint32 swap4(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+ else return (n);
+}
+
+static uint16 swap2(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+ else return (n);
+}
+
+static void swapstring(char *foo, int doit)
+{
+ if (doit)
+ {
+ char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
+ foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
+ }
+}
+
+/******************** soundfile access routines **********************/
+
+/* This routine opens a file, looks for either a nextstep or "wave" header,
+* seeks to end of it, and fills in bytes per sample and number of channels.
+* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
+* are supported. If "headersize" is nonzero, the
+* caller should supply the number of channels, endinanness, and bytes per
+* sample; the header is ignored. Otherwise, the routine tries to read the
+* header and fill in the properties.
+*/
+
+int open_soundfile(const char *dirname, const char *filename, int headersize,
+ int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
+ long skipframes)
+{
+ char buf[OBUFSIZE], *bufptr;
+ int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn;
+ long bytelimit = 0x7fffffff;
+ errno = 0;
+ fd = open_via_path(dirname, filename,
+ "", buf, &bufptr, MAXPDSTRING, 1);
+ if (fd < 0)
+ return (-1);
+ if (headersize >= 0) /* header detection overridden */
+ {
+ bigendian = *p_bigendian;
+ nchannels = *p_nchannels;
+ bytespersamp = *p_bytespersamp;
+ bytelimit = *p_bytelimit;
+ }
+ else
+ {
+ int bytesread = read(fd, buf, READHDRSIZE);
+ int format;
+ if (bytesread < 4)
+ goto badheader;
+ if (!strncmp(buf, ".snd", 4))
+ format = FORMAT_NEXT, bigendian = 1;
+ else if (!strncmp(buf, "dns.", 4))
+ format = FORMAT_NEXT, bigendian = 0;
+ else if (!strncmp(buf, "RIFF", 4))
+ {
+ if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4))
+ goto badheader;
+ format = FORMAT_WAVE, bigendian = 0;
+ }
+ else if (!strncmp(buf, "FORM", 4))
+ {
+ if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4))
+ goto badheader;
+ format = FORMAT_AIFF, bigendian = 1;
+ }
+ else
+ goto badheader;
+ swap = (bigendian != garray_ambigendian());
+ if (format == FORMAT_NEXT) /* nextstep header */
+ {
+ uint32 param;
+ if (bytesread < (int)sizeof(t_nextstep))
+ goto badheader;
+ nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap);
+ format = swap4(((t_nextstep *)buf)->ns_format, swap);
+ headersize = swap4(((t_nextstep *)buf)->ns_onset, swap);
+ if (format == NS_FORMAT_LINEAR_16)
+ bytespersamp = 2;
+ else if (format == NS_FORMAT_LINEAR_24)
+ bytespersamp = 3;
+ else if (format == NS_FORMAT_FLOAT)
+ bytespersamp = 4;
+ else goto badheader;
+ bytelimit = 0x7fffffff;
+ }
+ else if (format == FORMAT_WAVE) /* wave header */
+ {
+ /* This is awful. You have to skip over chunks,
+ except that if one happens to be a "fmt" chunk, you want to
+ find out the format from that one. The case where the
+ "fmt" chunk comes after the audio isn't handled. */
+ headersize = 12;
+ if (bytesread < 20)
+ goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no "fmt" chunk to follow. */
+ nchannels = 1;
+ bytespersamp = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_wavechunk));
+ /* post("chunk %c %c %c %c",
+ ((t_wavechunk *)buf)->wc_id[0],
+ ((t_wavechunk *)buf)->wc_id[1],
+ ((t_wavechunk *)buf)->wc_id[2],
+ ((t_wavechunk *)buf)->wc_id[3]); */
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_wavechunk *)buf)->wc_id, "data", 4))
+ {
+ long chunksize = swap4(((t_wavechunk *)buf)->wc_size,
+ swap), seekto = headersize + chunksize + 8, seekout;
+
+ if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4))
+ {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt))
+ goto badheader;
+ nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap);
+ format = swap2(((t_fmt *)buf)->f_nbitspersample, swap);
+ if (format == 16)
+ bytespersamp = 2;
+ else if (format == 24)
+ bytespersamp = 3;
+ else if (format == 32)
+ bytespersamp = 4;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_wavechunk)) <
+ (int) sizeof(t_wavechunk))
+ goto badheader;
+ /* post("new chunk %c %c %c %c at %d",
+ ((t_wavechunk *)buf)->wc_id[0],
+ ((t_wavechunk *)buf)->wc_id[1],
+ ((t_wavechunk *)buf)->wc_id[2],
+ ((t_wavechunk *)buf)->wc_id[3], seekto); */
+ headersize = seekto;
+ }
+ bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
+ headersize += 8;
+ }
+ else
+ {
+ /* AIFF. same as WAVE; actually predates it. Disgusting. */
+ headersize = 12;
+ if (bytesread < 20)
+ goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no COMM block to follow. */
+ nchannels = 1;
+ bytespersamp = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_datachunk));
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_datachunk *)buf)->dc_id, "SSND", 4))
+ {
+ long chunksize = swap4(((t_datachunk *)buf)->dc_size,
+ swap), seekto = headersize + chunksize + 8, seekout;
+ /* post("chunk %c %c %c %c seek %d",
+ ((t_datachunk *)buf)->dc_id[0],
+ ((t_datachunk *)buf)->dc_id[1],
+ ((t_datachunk *)buf)->dc_id[2],
+ ((t_datachunk *)buf)->dc_id[3], seekto); */
+ if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4))
+ {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_comm)) <
+ (int) sizeof(t_comm))
+ goto badheader;
+ nchannels = swap2(((t_comm *)buf)->c_nchannels, swap);
+ format = swap2(((t_comm *)buf)->c_bitspersamp, swap);
+ if (format == 16)
+ bytespersamp = 2;
+ else if (format == 24)
+ bytespersamp = 3;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_datachunk)) <
+ (int) sizeof(t_datachunk))
+ goto badheader;
+ headersize = seekto;
+ }
+ bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
+ headersize += 8;
+ }
+ }
+ /* seek past header and any sample frames to skip */
+ sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0);
+ if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
+ return (-1);
+ bytelimit -= nchannels * bytespersamp * skipframes;
+ if (bytelimit < 0)
+ bytelimit = 0;
+ /* copy sample format back to caller */
+ *p_bigendian = bigendian;
+ *p_nchannels = nchannels;
+ *p_bytespersamp = bytespersamp;
+ *p_bytelimit = bytelimit;
+ return (fd);
+badheader:
+ /* the header wasn't recognized. We're threadable here so let's not
+ print out the error... */
+ errno = EIO;
+ return (-1);
+}
+
+static void soundfile_xferin(int sfchannels, int nvecs, t_sample **vecs,
+ long itemsread, unsigned char *buf, int nitems, int bytespersamp,
+ int bigendian)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ t_sample *fp;
+ int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
+ int bytesperframe = bytespersamp * sfchannels;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = ((short*)sp2)[0]<<(fix1-16);
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
+ | (sp2[0] << 8));
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8) | sp2[3]);
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
+ | (sp2[1] << 8) | sp2[0]);
+ }
+ }
+ }
+ /* zero out other outputs */
+ for (i = sfchannels; i < nvecs; i++)
+ for (j = nitems, fp = vecs[i]; j--; )
+ *fp++ = 0;
+
+}
+
+ /* soundfiler_write ...
+
+ usage: write [flags] filename table ...
+ flags:
+ -nframes <frames>
+ -skip <frames>
+ -bytes <bytes per sample>
+ -normalize
+ -nextstep
+ -wave
+ -big
+ -little
+ */
+
+ /* the routine which actually does the work should LATER also be called
+ from garray_write16. */
+
+
+ /* Parse arguments for writing. The "obj" argument is only for flagging
+ errors. For streaming to a file the "normalize", "onset" and "nframes"
+ arguments shouldn't be set but the calling routine flags this. */
+
+static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
+ t_symbol **p_filesym,
+ int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
+ int *p_normalize, long *p_onset, long *p_nframes, float *p_rate)
+{
+ int argc = *p_argc;
+ t_atom *argv = *p_argv;
+ int bytespersamp = 2, bigendian = 0,
+ endianness = -1, swap, filetype = -1, normalize = 0;
+ long onset = 0, nframes = 0x7fffffff;
+ t_symbol *filesym;
+ float rate = -1;
+
+ while (argc > 0 && argv->a_type == A_SYMBOL &&
+ *argv->a_w.w_symbol->s_name == '-')
+ {
+ char *flag = argv->a_w.w_symbol->s_name + 1;
+ if (!strcmp(flag, "skip"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((onset = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "nframes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((nframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "bytes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((bytespersamp = argv[1].a_w.w_float) < 2) ||
+ bytespersamp > 4)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "normalize"))
+ {
+ normalize = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "wave"))
+ {
+ filetype = FORMAT_WAVE;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "nextstep"))
+ {
+ filetype = FORMAT_NEXT;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "aiff"))
+ {
+ filetype = FORMAT_AIFF;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "big"))
+ {
+ endianness = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "little"))
+ {
+ endianness = 0;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "r") || !strcmp(flag, "rate"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((rate = argv[1].a_w.w_float) <= 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else goto usage;
+ }
+ if (!argc || argv->a_type != A_SYMBOL)
+ goto usage;
+ filesym = argv->a_w.w_symbol;
+
+ /* check if format not specified and fill in */
+ if (filetype < 0)
+ {
+ if (strlen(filesym->s_name) >= 5 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
+ filetype = FORMAT_AIFF;
+ if (strlen(filesym->s_name) >= 6 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
+ filetype = FORMAT_AIFF;
+ if (strlen(filesym->s_name) >= 5 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
+ filetype = FORMAT_NEXT;
+ if (strlen(filesym->s_name) >= 4 &&
+ (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
+ !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
+ filetype = FORMAT_NEXT;
+ if (filetype < 0)
+ filetype = FORMAT_WAVE;
+ }
+ /* don't handle AIFF floating point samples */
+ if (bytespersamp == 4)
+ {
+ if (filetype == FORMAT_AIFF)
+ {
+ pd_error(obj, "AIFF floating-point file format unavailable");
+ goto usage;
+ }
+ }
+ /* for WAVE force little endian; for nextstep use machine native */
+ if (filetype == FORMAT_WAVE)
+ {
+ bigendian = 0;
+ if (endianness == 1)
+ pd_error(obj, "WAVE file forced to little endian");
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ bigendian = 1;
+ if (endianness == 0)
+ pd_error(obj, "AIFF file forced to big endian");
+ }
+ else if (endianness == -1)
+ {
+ bigendian = garray_ambigendian();
+ }
+ else bigendian = endianness;
+ swap = (bigendian != garray_ambigendian());
+
+ argc--; argv++;
+
+ *p_argc = argc;
+ *p_argv = argv;
+ *p_filesym = filesym;
+ *p_filetype = filetype;
+ *p_bytespersamp = bytespersamp;
+ *p_swap = swap;
+ *p_normalize = normalize;
+ *p_onset = onset;
+ *p_nframes = nframes;
+ *p_bigendian = bigendian;
+ *p_rate = rate;
+ return (0);
+usage:
+ return (-1);
+}
+
+static int create_soundfile(t_canvas *canvas, const char *filename,
+ int filetype, int nframes, int bytespersamp,
+ int bigendian, int nchannels, int swap, float samplerate)
+{
+ char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
+ char headerbuf[WRITEHDRSIZE];
+ t_wave *wavehdr = (t_wave *)headerbuf;
+ t_nextstep *nexthdr = (t_nextstep *)headerbuf;
+ t_aiff *aiffhdr = (t_aiff *)headerbuf;
+ int fd, headersize = 0;
+
+ strncpy(filenamebuf, filename, MAXPDSTRING-10);
+ filenamebuf[MAXPDSTRING-10] = 0;
+
+ if (filetype == FORMAT_NEXT)
+ {
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
+ strcat(filenamebuf, ".snd");
+ if (bigendian)
+ strncpy(nexthdr->ns_fileid, ".snd", 4);
+ else strncpy(nexthdr->ns_fileid, "dns.", 4);
+ nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
+ nexthdr->ns_length = 0;
+ nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
+ (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);
+ nexthdr->ns_sr = swap4(samplerate, swap);
+ nexthdr->ns_nchans = swap4(nchannels, swap);
+ strcpy(nexthdr->ns_info, "Pd ");
+ swapstring(nexthdr->ns_info, swap);
+ headersize = sizeof(t_nextstep);
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ long longtmp;
+ static unsigned char dogdoo[] =
+ {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
+ strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
+ strcat(filenamebuf, ".aif");
+ strncpy(aiffhdr->a_fileid, "FORM", 4);
+ aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
+ strncpy(aiffhdr->a_aiffid, "AIFF", 4);
+ strncpy(aiffhdr->a_fmtid, "COMM", 4);
+ aiffhdr->a_fmtchunksize = swap4(18, swap);
+ aiffhdr->a_nchannels = swap2(nchannels, swap);
+ longtmp = swap4(nframes, swap);
+ memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
+ aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
+ memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
+ longtmp = swap4(datasize, swap);
+ memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
+ headersize = AIFFPLUS;
+ }
+ else /* WAVE format */
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
+ strcat(filenamebuf, ".wav");
+ strncpy(wavehdr->w_fileid, "RIFF", 4);
+ wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
+ strncpy(wavehdr->w_waveid, "WAVE", 4);
+ strncpy(wavehdr->w_fmtid, "fmt ", 4);
+ wavehdr->w_fmtchunksize = swap4(16, swap);
+ wavehdr->w_fmttag =
+ swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
+ wavehdr->w_nchannels = swap2(nchannels, swap);
+ wavehdr->w_samplespersec = swap4(samplerate, swap);
+ wavehdr->w_navgbytespersec =
+ swap4((int)(samplerate * nchannels * bytespersamp), swap);
+ wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap);
+ wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
+ strncpy(wavehdr->w_datachunkid, "data", 4);
+ wavehdr->w_datachunksize = swap4(datasize, swap);
+ headersize = sizeof(t_wave);
+ }
+
+ canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
+ sys_bashfilename(buf2, buf2);
+ if ((fd = open(buf2, BINCREATE, 0666)) < 0)
+ return (-1);
+
+ if (write(fd, headerbuf, headersize) < headersize)
+ {
+ close (fd);
+ return (-1);
+ }
+ return (fd);
+}
+
+static void soundfile_finishwrite(void *obj, char *filename, int fd,
+ int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
+{
+ if (itemswritten < nframes)
+ {
+ if (nframes < 0x7fffffff)
+ pd_error(obj, "soundfiler_write: %d out of %d bytes written",
+ itemswritten, nframes);
+ /* try to fix size fields in header */
+ if (filetype == FORMAT_WAVE)
+ {
+ long datasize = itemswritten * bytesperframe, mofo;
+
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ if (filetype == FORMAT_AIFF)
+ {
+ long mofo;
+ if (lseek(fd,
+ ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(nframes, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ if (filetype == FORMAT_NEXT)
+ {
+ /* do it the lazy way: just set the size field to 'unknown size'*/
+ uint32 nextsize = 0xffffffff;
+ if (lseek(fd, 8, SEEK_SET) == 0)
+ {
+ goto baddonewrite;
+ }
+ if (write(fd, &nextsize, 4) < 4)
+ {
+ goto baddonewrite;
+ }
+ }
+ }
+ return;
+baddonewrite:
+ post("%s: %s", filename, strerror(errno));
+}
+
+static void soundfile_xferout(int nchannels, t_sample **vecs,
+ unsigned char *buf, int nitems, long onset, int bytespersamp,
+ int bigendian, float normalfactor)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ t_sample *fp;
+ int bytesperframe = bytespersamp * nchannels;
+ long xx;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ float ff = normalfactor * 32768.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp = vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[0] = (xx >> 8);
+ sp2[1] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ float ff = normalfactor * 8388608.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[0] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[2] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[2] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[0] = (xx >> 24); sp2[1] = (xx >> 16);
+ sp2[2] = (xx >> 8); sp2[3] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[3] = (xx >> 24); sp2[2] = (xx >> 16);
+ sp2[1] = (xx >> 8); sp2[0] = xx;
+ }
+ }
+ }
+ }
+}
+
+
+/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
+#define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */
+#define SAMPBUFSIZE 1024
+
+
+static t_class *soundfiler_class;
+
+typedef struct _soundfiler
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+} t_soundfiler;
+
+static t_soundfiler *soundfiler_new(void)
+{
+ t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
+ x->x_canvas = canvas_getcurrent();
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+ /* soundfiler_read ...
+
+ usage: read [flags] filename table ...
+ flags:
+ -skip <frames> ... frames to skip in file
+ -nframes <frames>
+ -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian>
+ -resize
+ -maxsize <max-size>
+ */
+
+static void soundfiler_read(t_soundfiler *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
+ resize = 0, i, j;
+ long ski