aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/Makefile3
-rw-r--r--modules/bfft.c41
-rw-r--r--modules/bitsplit.c107
-rw-r--r--modules/blocknorm.c129
-rw-r--r--modules/cmath.c176
-rw-r--r--modules/dynwav.c2
-rw-r--r--modules/ead.c43
-rw-r--r--modules/eadsr.c47
-rw-r--r--modules/ear.c8
-rw-r--r--modules/eblosc.c599
-rw-r--r--modules/fdn.c4
-rw-r--r--modules/lattice.c11
-rw-r--r--modules/matrix.c4
-rw-r--r--modules/permut.c9
-rw-r--r--modules/ramp.c66
-rw-r--r--modules/resofilt.c397
-rw-r--r--modules/sbosc.c175
-rw-r--r--modules/scrollgrid1D.c220
-rw-r--r--modules/statwav.c8
19 files changed, 1946 insertions, 103 deletions
diff --git a/modules/Makefile b/modules/Makefile
index b5e6093..f054566 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -3,7 +3,8 @@ include ../Makefile.config
current: ead.o ear.o eadsr.o dist.o tabreadmix.o xfm.o qmult.o qnorm.o \
cheby.o abs.o ramp.o dwt.o bfft.o dynwav.o statwav.o bdiag.o \
diag.o matrix.o permut.o lattice.o ratio.o ffpoly.o fwarp.o \
- junction.o fdn.o window.o
+ junction.o fdn.o window.o cmath.o eblosc.o bitsplit.o sbosc.o \
+ blocknorm.o resofilt.o scrollgrid1D.o
clean:
diff --git a/modules/bfft.c b/modules/bfft.c
index 76b0254..750f020 100644
--- a/modules/bfft.c
+++ b/modules/bfft.c
@@ -1,5 +1,5 @@
/*
- * bfft.c - code for fourrier transform
+ * bfft.c - code for some fourrier transform variants and utility functions
* data organization is in (real, imag) pairs
* the first 2 components are (DC, NY)
* Copyright (c) 2000-2003 by Tom Schouten
@@ -29,17 +29,19 @@
typedef struct bfftctl
{
- t_int c_levels;
- char c_name[16];
- t_int *c_clutter;
- t_int *c_unclutter;
+ t_int c_levels;
+ char c_name[16];
+ t_int *c_clutter;
+ t_int *c_unclutter;
+ t_int c_kill_DC;
+ t_int c_kill_NY;
} t_bfftctl;
typedef struct bfft
{
- t_object x_obj;
- t_float x_f;
- t_bfftctl x_ctl;
+ t_object x_obj;
+ t_float x_f;
+ t_bfftctl x_ctl;
} t_bfft;
t_class *bfft_class, *ibfft_class, *fht_class;
@@ -127,10 +129,16 @@ static t_int *ibfft_perform(t_int *w)
t_float scale = sqrt(1.0f / (float)(n));
+ if (ctl->c_kill_DC) {out[0] = 0.0f;}
+ if (ctl->c_kill_NY) {out[1] = 0.0f;}
+
bfft_perform_permutation(out, n, ctl->c_clutter);
mayer_fht(out, n);
+
+
while (n--) *out++ *= scale;
+
return (w+5);
}
@@ -240,13 +248,22 @@ static void *bfft_new(void)
}
-static void *ibfft_new(void)
+static void *ibfft_new(t_symbol *s)
{
t_bfft *x = (t_bfft *)pd_new(ibfft_class);
int i;
outlet_new(&x->x_obj, gensym("signal"));
+ if (s == gensym("killDCNY")){
+ x->x_ctl.c_kill_DC = 1;
+ x->x_ctl.c_kill_NY = 1;
+ post("ibfft: removing DC and NY components.");
+ }
+ else{
+ x->x_ctl.c_kill_DC = 0;
+ x->x_ctl.c_kill_NY = 0;
+ }
x->x_ctl.c_clutter = NULL;
x->x_ctl.c_unclutter = NULL;
@@ -286,7 +303,11 @@ void bfft_tilde_setup(void)
ibfft_class = class_new(gensym("ibfft~"), (t_newmethod)ibfft_new,
- (t_method)bfft_free, sizeof(t_bfft), 0, 0);
+ (t_method)bfft_free, sizeof(t_bfft), 0, A_DEFSYMBOL, A_NULL);
+
+ /* add the more logical bifft~ alias */
+ class_addcreator((t_newmethod)ibfft_new,
+ gensym("bifft~"), 0, A_DEFSYMBOL, A_NULL);
CLASS_MAINSIGNALIN(ibfft_class, t_bfft, x_f);
class_addmethod(ibfft_class, (t_method)ibfft_dsp, gensym("dsp"), 0);
diff --git a/modules/bitsplit.c b/modules/bitsplit.c
new file mode 100644
index 0000000..9239d0b
--- /dev/null
+++ b/modules/bitsplit.c
@@ -0,0 +1,107 @@
+/*
+ * bitsplit.c - convert a signal to a binary vector
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#define MAXCHANNELS 24
+
+typedef struct bitsplitctl
+{
+ t_int c_outputs;
+ t_float *c_input;
+ t_float **c_output;
+} t_bitsplitctl;
+
+typedef struct bitsplit
+{
+ t_object x_obj;
+ t_float x_f;
+ t_bitsplitctl x_ctl;
+} t_bitsplit;
+
+
+static t_int *bitsplit_perform(t_int *word)
+{
+
+ t_bitsplitctl *ctl = (t_bitsplitctl *)(word[1]);
+ t_int n = (t_int)(word[2]);
+ t_float *in = ctl->c_input;
+ t_int outputs = ctl->c_outputs;
+ t_float **out = ctl->c_output;
+ t_int i,j;
+
+ for (i=0;i<n;i++){
+ long word = (in[i] * (float)(0x7fffffff));
+ for (j=0; j<outputs; j++){
+ out[j][i] = (float)((word >> 31) & 1);
+ word <<= 1;
+ }
+ }
+
+ return (word+3);
+}
+
+
+
+static void bitsplit_dsp(t_bitsplit *x, t_signal **sp)
+{
+
+ int i;
+ x->x_ctl.c_input = sp[0]->s_vec;
+ for (i=0;i<x->x_ctl.c_outputs;i++){
+ x->x_ctl.c_output[i] = sp[i+1]->s_vec;
+ }
+ dsp_add(bitsplit_perform, 2, &x->x_ctl, sp[0]->s_n);
+}
+
+
+static void bitsplit_free(t_bitsplit *x)
+{
+ free (x->x_ctl.c_output);
+}
+
+t_class *bitsplit_class;
+
+static void *bitsplit_new(t_floatarg channels)
+{
+ int i = (int)channels;
+ t_bitsplit *x = (t_bitsplit *)pd_new(bitsplit_class);
+
+ if (i<1) i = 1;
+ if (i>MAXCHANNELS) i = MAXCHANNELS;
+ x->x_ctl.c_outputs = i;
+ x->x_ctl.c_output = malloc(sizeof(float)*i);
+
+ while (i--) outlet_new(&x->x_obj, gensym("signal"));
+
+ return (void *)x;
+}
+
+void bitsplit_tilde_setup(void)
+{
+ bitsplit_class = class_new(gensym("bitsplit~"), (t_newmethod)bitsplit_new,
+ (t_method)bitsplit_free, sizeof(t_bitsplit), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(bitsplit_class, t_bitsplit, x_f);
+ class_addmethod(bitsplit_class, (t_method)bitsplit_dsp, gensym("dsp"), 0);
+}
+
diff --git a/modules/blocknorm.c b/modules/blocknorm.c
new file mode 100644
index 0000000..bcf695a
--- /dev/null
+++ b/modules/blocknorm.c
@@ -0,0 +1,129 @@
+/*
+ * blocknorm.c - normalize an array of dsp blocks (for spectral processing)
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#define MAXCHANNELS 32
+
+typedef struct blocknormctl
+{
+ t_int c_channels;
+ t_float **c_input;
+ t_float **c_output;
+} t_blocknormctl;
+
+typedef struct blocknorm
+{
+ t_object x_obj;
+ t_float x_f;
+ t_blocknormctl x_ctl;
+} t_blocknorm;
+
+
+static t_int *blocknorm_perform(t_int *word)
+{
+
+ t_blocknormctl *ctl = (t_blocknormctl *)(word[1]);
+ t_int n = (t_int)(word[2]);
+ t_float **in = ctl->c_input;
+ t_float **out = ctl->c_output;
+ t_int c = ctl->c_channels;
+ t_int i,j;
+
+ t_float p = 0.0f;
+ t_float x, s;
+
+ /* get power */
+ for (j=0;j<c;j++){
+ for (i=0;i<n;i++){
+ x = in[j][i];
+ p += x*x;
+ }
+ }
+
+ /* compute normalization */
+ if (p == 0.0f) s = 1.0f;
+ else s =sqrt(((float)(c * n)) / p);
+
+ /* normalize */
+ for (j=0;j<c;j++){
+ for (i=0;i<n;i++){
+ out[j][i] *= s;
+ }
+ }
+
+
+
+ return (word+3);
+}
+
+
+
+static void blocknorm_dsp(t_blocknorm *x, t_signal **sp)
+{
+
+ int i;
+ int c = x->x_ctl.c_channels;
+ for (i=0;i<c;i++){
+ x->x_ctl.c_input[i] = sp[i]->s_vec;
+ x->x_ctl.c_output[i] = sp[c+i]->s_vec;
+ }
+ dsp_add(blocknorm_perform, 2, &x->x_ctl, sp[0]->s_n);
+}
+
+
+static void blocknorm_free(t_blocknorm *x)
+{
+ free (x->x_ctl.c_output);
+ free (x->x_ctl.c_input);
+}
+
+t_class *blocknorm_class;
+
+static void *blocknorm_new(t_floatarg channels)
+{
+ int i = (int)channels;
+ int j;
+ t_blocknorm *x = (t_blocknorm *)pd_new(blocknorm_class);
+
+ if (i<1) i = 1;
+ if (i>MAXCHANNELS) i = MAXCHANNELS;
+ x->x_ctl.c_channels = i;
+ x->x_ctl.c_input = malloc(sizeof(float)*i);
+ x->x_ctl.c_output = malloc(sizeof(float)*i);
+
+ j = i;
+ while (--j) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ while (i--) outlet_new(&x->x_obj, gensym("signal"));
+
+ return (void *)x;
+}
+
+void blocknorm_tilde_setup(void)
+{
+ blocknorm_class = class_new(gensym("blocknorm~"), (t_newmethod)blocknorm_new,
+ (t_method)blocknorm_free, sizeof(t_blocknorm), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(blocknorm_class, t_blocknorm, x_f);
+ class_addmethod(blocknorm_class, (t_method)blocknorm_dsp, gensym("dsp"), 0);
+}
+
diff --git a/modules/cmath.c b/modules/cmath.c
new file mode 100644
index 0000000..3bd63a9
--- /dev/null
+++ b/modules/cmath.c
@@ -0,0 +1,176 @@
+/*
+ * cmath.c - some complex math dsp objects
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+
+#define MINNORM 0.0000000001
+
+typedef struct cmath
+{
+ t_object x_obj;
+ t_float x_f;
+ t_perfroutine x_perf;
+} t_cmath;
+
+
+static t_int *cmath_perform_clog(t_int *w)
+{
+ t_float *inx = (float *)(w[2]);
+ t_float *iny = (float *)(w[3]);
+ t_float *outx = (float *)(w[4]);
+ t_float *outy = (float *)(w[5]);
+ t_int i;
+ t_int n = (t_int)(w[1]);
+ t_float x;
+
+ while (n--){
+ float x = *inx++;
+ float y = *iny++;
+ float norm = sqrt(x*x + y*y);
+ float arg = atan2(y, x);
+ if (norm < MINNORM){
+ norm = MINNORM;
+ }
+ *outx++ = log(norm);
+ *outy++ = arg;
+ }
+
+ return (w+6);
+}
+
+
+static t_int *cmath_perform_cexp(t_int *w)
+{
+ t_float *inx = (float *)(w[2]);
+ t_float *iny = (float *)(w[3]);
+ t_float *outx = (float *)(w[4]);
+ t_float *outy = (float *)(w[5]);
+ t_int i;
+ t_int n = (t_int)(w[1]);
+ t_float x;
+
+ while (n--){
+ float x = *inx++;
+ float y = *iny++;
+ float norm = exp(x);
+ *outx++ = norm * cos(y);
+ *outy++ = norm * sin(y);
+ }
+
+ return (w+6);
+}
+
+static t_int *cmath_perform_nfft(t_int *w)
+{
+ t_float *inx = (float *)(w[2]);
+ t_float *iny = (float *)(w[3]);
+ t_float *outx = (float *)(w[4]);
+ t_float *outy = (float *)(w[5]);
+ t_int i;
+ t_int n = (t_int)(w[1]);
+ t_float x;
+ t_float scale = 1.0f / (sqrt((float)n));
+
+ mayer_fft(n, inx, outx);
+
+ while (n--){
+ float x = *inx++;
+ float y = *iny++;
+ *outx++ = scale * x;
+ *outy++ = scale * y;
+ }
+
+ return (w+6);
+}
+
+static t_int *cmath_perform_nifft(t_int *w)
+{
+ t_float *inx = (float *)(w[2]);
+ t_float *iny = (float *)(w[3]);
+ t_float *outx = (float *)(w[4]);
+ t_float *outy = (float *)(w[5]);
+ t_int i;
+ t_int n = (t_int)(w[1]);
+ t_float x;
+ t_float scale = 1.0f / (sqrt((float)n));
+
+ mayer_ifft(n, inx, outx);
+
+ while (n--){
+ float x = *inx++;
+ float y = *iny++;
+ *outx++ = scale * x;
+ *outy++ = scale * y;
+ }
+
+ return (w+6);
+}
+
+static void cmath_dsp(t_cmath *x, t_signal **sp)
+{
+ dsp_add(x->x_perf, 5, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+
+}
+void cmath_free(void)
+{
+
+}
+
+t_class *cmath_class;
+
+t_cmath *cmath_new_common(void)
+{
+ t_cmath *x = (t_cmath *)pd_new(cmath_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ return x;
+}
+
+#define DEFNEWCMATH(name, perfmethod) \
+void * name (void) \
+{ \
+ t_cmath *x = cmath_new_common(); \
+ x->x_perf = perfmethod ; \
+ return (void*)x; \
+}
+
+DEFNEWCMATH(cmath_new_clog, cmath_perform_clog)
+DEFNEWCMATH(cmath_new_cexp, cmath_perform_cexp)
+DEFNEWCMATH(cmath_new_nfft, cmath_perform_nfft)
+DEFNEWCMATH(cmath_new_nifft, cmath_perform_nifft)
+
+
+void cmath_tilde_setup(void)
+{
+ //post("cmath~ v0.1");
+ cmath_class = class_new(gensym("clog~"), (t_newmethod)cmath_new_clog,
+ (t_method)cmath_free, sizeof(t_cmath), 0, 0);
+
+ class_addcreator((t_newmethod)cmath_new_cexp, gensym("cexp~"), A_NULL);
+ class_addcreator((t_newmethod)cmath_new_nfft, gensym("nfft~"), A_NULL);
+ class_addcreator((t_newmethod)cmath_new_nifft, gensym("nifft~"), A_NULL);
+
+ CLASS_MAINSIGNALIN(cmath_class, t_cmath, x_f);
+
+ class_addmethod(cmath_class, (t_method)cmath_dsp, gensym("dsp"), 0);
+}
+
diff --git a/modules/dynwav.c b/modules/dynwav.c
index 0ff75f3..9157f12 100644
--- a/modules/dynwav.c
+++ b/modules/dynwav.c
@@ -1,5 +1,5 @@
/*
- * dynwav.c - dynamic wavetable oscillator
+ * blosc.c - bandlimited oscillators
* data organization is in (real, imag) pairs
* the first 2 components are (DC, NY)
* Copyright (c) 2000-2003 by Tom Schouten
diff --git a/modules/ead.c b/modules/ead.c
index 4d301b8..88fc6ec 100644
--- a/modules/ead.c
+++ b/modules/ead.c
@@ -29,7 +29,7 @@ typedef struct eadctl
t_float c_attack;
t_float c_decay;
t_float c_state;
- t_float c_target;
+ t_int c_target;
} t_eadctl;
@@ -54,7 +54,13 @@ static void ead_decay(t_ead *x, t_floatarg f)
static void ead_start(t_ead *x)
{
- x->x_ctl.c_target = 1;
+ /* reset state if necessary to prevent skipping */
+
+ // always reset, seems to be safest
+ //if (x->x_ctl.c_target == 1)
+
+ x->x_ctl.c_state = 0.0f;
+ x->x_ctl.c_target = 1;
}
@@ -68,7 +74,6 @@ static t_int *ead_perform(t_int *w)
t_float attack = ctl->c_attack;
t_float decay = ctl->c_decay;
t_float state = ctl->c_state;
- t_float target = ctl->c_target;
t_int n = (t_int)(w[2]);
t_int i;
@@ -76,29 +81,27 @@ static t_int *ead_perform(t_int *w)
/* A/D code */
- if (target == 1)
- /* attack phase */
- {
- for (i = 0; i < n; i++)
- {
+ for (i = 0; i < n; i++){
+ switch(ctl->c_target){
+ case 1:
+ /* attack phase */
*out++ = state;
state += attack*(1 - state);
- }
- if (state > ENVELOPE_MAX)
- ctl->c_target = 0;
- }
-
- else
- /* decay phase */
- for (i = 0; i < n; i++)
- {
- *out++ = state;
- state -= decay*state;
+ ctl->c_target = (state <= ENVELOPE_MAX);
+ break;
+ default:
+ /* decay phase */
+ *out++ = state;
+ state -= decay*state;
+ break;
}
+
+ }
+ /* save state */
ctl->c_state = IS_DENORMAL(state) ? 0 : state;
- return (w+4); /* pd quirk: pointer for sequencer */
+ return (w+4);
}
diff --git a/modules/eadsr.c b/modules/eadsr.c
index bba96cd..332ddf4 100644
--- a/modules/eadsr.c
+++ b/modules/eadsr.c
@@ -63,6 +63,7 @@ void eadsr_release(t_eadsr *x, t_floatarg f)
void eadsr_start(t_eadsr *x)
{
x->x_ctl.c_target = 1;
+ x->x_ctl.c_state = 0.0f;
}
@@ -72,6 +73,12 @@ void eadsr_stop(t_eadsr *x)
}
+void eadsr_float(t_eadsr *x, t_floatarg f)
+{
+ if (f == 0.0f) eadsr_stop(x);
+ else eadsr_start(x);
+}
+
static t_int *eadsr_perform(t_int *w)
{
t_float *out = (float *)(w[3]);
@@ -87,35 +94,28 @@ static t_int *eadsr_perform(t_int *w)
t_int i;
- if (target == 1)
- /* attack phase */
- {
- for (i = 0; i < n; i++)
- {
+ for (i = 0; i < n; i++){
+ if (target == 1.0f){
+ /* attack */
*out++ = state;
state += attack*(1 - state);
- }
- if (state > ENVELOPE_MAX)
- ctl->c_target = sustain;
- }
-
- else if (target == 0)
- /* release phase */
- for (i = 0; i < n; i++)
- {
- *out++ = state;
- state -= release*state;
+ target = (state > ENVELOPE_MAX) ? sustain : 1.0f;
}
-
- else
- /* decay phase */
- for (i = 0; i < n; i++)
- {
- *out++ = state;
- state -= decay*(state-sustain);
+ else if (target == 0.0f){
+ /* release */
+ *out++ = state;
+ state -= release*state;
+ }
+ else{
+ /* decay */
+ *out++ = state;
+ state -= decay*(state-sustain);
}
+ }
+ /* save state */
ctl->c_state = IS_DENORMAL(state) ? 0 : state;
+ ctl->c_target = target;
return (w+4);
}
@@ -157,6 +157,7 @@ void eadsr_tilde_setup(void)
//post("eadsr~ v0.1");
eadsr_class = class_new(gensym("eadsr~"), (t_newmethod)eadsr_new,
(t_method)eadsr_free, sizeof(t_eadsr), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(eadsr_class, (t_method)eadsr_float, gensym("float"), A_FLOAT, 0);
class_addmethod(eadsr_class, (t_method)eadsr_start, gensym("start"), 0);
class_addmethod(eadsr_class, (t_method)eadsr_start, gensym("bang"), 0);
class_addmethod(eadsr_class, (t_method)eadsr_stop, gensym("stop"), 0);
diff --git a/modules/ear.c b/modules/ear.c
index d842065..28fe097 100644
--- a/modules/ear.c
+++ b/modules/ear.c
@@ -47,6 +47,7 @@ void ear_release(t_ear *x, t_floatarg f)
void ear_start(t_ear *x)
{
x->x_ctl.c_target = 1;
+ x->x_ctl.c_state = 0.0f;
}
@@ -56,6 +57,12 @@ void ear_stop(t_ear *x)
}
+void ear_float(t_ear *x, t_floatarg f)
+{
+ if (f == 0.0f) ear_stop(x);
+ else ear_start(x);
+}
+
static t_int *ear_perform(t_int *w)
{
t_float *out = (float *)(w[3]);
@@ -120,6 +127,7 @@ void ear_tilde_setup(void)
//post("ear~ v0.1");
ear_class = class_new(gensym("ear~"), (t_newmethod)ear_new,
(t_method)ear_free, sizeof(t_ear), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(ear_class, (t_method)ear_float, gensym("float"), A_FLOAT, 0);
class_addmethod(ear_class, (t_method)ear_start, gensym("start"), 0);
class_addmethod(ear_class, (t_method)ear_start, gensym("bang"), 0);
class_addmethod(ear_class, (t_method)ear_stop, gensym("stop"), 0);
diff --git a/modules/eblosc.c b/modules/eblosc.c
new file mode 100644
index 0000000..df1b059
--- /dev/null
+++ b/modules/eblosc.c
@@ -0,0 +1,599 @@
+/*
+ * eblosc.c - bandlimited oscillators with infinite support discontinuities
+ * using minimum phase impulse, step & ramp
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "filters.h"
+
+
+typedef unsigned long long u64;
+typedef unsigned long u32;
+
+
+
+#define LPHASOR (8*sizeof(u32)) // the phasor logsize
+#define VOICES 8 // the number of oscillators
+#define CUTOFF 0.8f // fraction of nyquist for impulse cutoff
+
+
+
+typedef struct ebloscctl
+{
+ t_float c_pole[VOICES*2]; // complex poles
+ t_float c_gain[VOICES*2]; // complex gains (waveform specific constants)
+ t_float c_state[VOICES*2]; // complex state
+
+ u32 c_phase; // phase of main oscillator
+ u32 c_phase2; // phase of secondairy oscillator
+ t_float c_prev_amp; // previous input of comparator
+ t_float c_phase_inc_scale;
+ t_float c_scale;
+ t_float c_scale_update;
+ t_symbol *c_waveform;
+
+} t_ebloscctl;
+
+typedef struct eblosc
+{
+ t_object x_obj;
+ t_float x_f;
+ t_ebloscctl x_ctl;
+} t_eblosc;
+
+
+/* phase converters */
+static inline float _phase_to_float(u32 p){return ((float)p) * (1.0f / 4294967296.0f);}
+static inline u32 _float_to_phase(float f){return (u32)(f * 4294967296.0f);}
+
+
+
+/* get one sample from the oscillator bank and perform time tick */
+static inline t_float _osc_tick(t_ebloscctl *ctl)
+{
+ float sum = 0.0f;
+ int i;
+ /* sum all voices */
+ for (i=0; i<VOICES*2; i+=2){
+ /* rotate state */
+ vcmul2(ctl->c_state+i, ctl->c_pole+i);
+
+ /* get real part and add to output */
+ sum += ctl->c_state[0];
+ }
+
+ return sum;
+}
+
+/* add shifted impulse */
+static inline void _add_impulse(t_ebloscctl *ctl, t_float t0)
+{
+ int i;
+ for (i=0; i<VOICES*2; i+=2){
+ /* contribution is a_i z_i^t_0 */
+
+ float real = 1.0f;
+ float imag = 0.0f;
+
+ ctl->c_state[0] += real;
+ ctl->c_state[1] += imag;
+ }
+}
+
+
+/* add step */
+static inline void _add_step(t_ebloscctl *ctl)
+{
+ int i;
+ for (i=0; i<VOICES*2; i+=2){
+ /* contribution is a_i (1 - z_i) */
+
+ float real = 1.0f;
+ float imag = 0.0f;
+
+ ctl->c_state[0] += real;
+ ctl->c_state[1] += imag;
+ }
+}
+
+
+/* add shifted step */
+static inline void _add_shifted_step(t_ebloscctl *ctl, t_float t0)
+{
+ int i;
+ for (i=0; i<VOICES*2; i+=2){
+ /* contribution is a_i (1 - z_i^t_0) */
+
+ float real = 1.0f;
+ float imag = 0.0f;
+
+ ctl->c_state[0] += real;
+ ctl->c_state[1] += imag;
+ }
+}
+
+
+#if 0
+/* update waveplayers on zero cross */
+static void _bang_comparator(t_ebloscctl *ctl, float prev, float curr)
+{
+
+ /* check for sign change */
+ if ((prev * curr) < 0.0f){
+
+ int voice;
+
+ /* determine the location of the discontinuity (in oversampled coordiates
+ using linear interpolation */
+
+ float f = (float)S * curr / (curr - prev);
+
+ /* get the offset in the oversample table */
+
+ u32 table_index = (u32)f;
+
+ /* determine the fractional part (in oversampled coordinates)
+ for linear interpolation */
+
+ float table_frac_index = f - (float)table_index;
+
+ /* set state (+ or -) */
+
+ ctl->c_state = (curr > 0.0f) ? 0.5f : -0.5f;
+
+ /* steal the oldest voice */
+
+ voice = ctl->c_next_voice++;
+ ctl->c_next_voice &= VOICES-1;
+
+ /* initialize the new voice index and interpolation fraction */
+
+ ctl->c_index[voice] = table_index;
+ ctl->c_frac[voice] = table_frac_index;
+ ctl->c_vscale[voice] = -ctl->c_scale * 2.0f * ctl->c_state;
+
+ }
+
+}
+
+/* advance phasor and update waveplayers on phase wrap */
+static void _bang_phasor(t_ebloscctl *ctl, float freq)
+{
+ u32 phase = ctl->c_phase;
+ u32 phase_inc;
+ u32 oldphase;
+ int voice;
+ float scale = ctl->c_scale;
+
+ /* get increment */
+ float inc = freq * ctl->c_phase_inc_scale;
+
+ /* calculate new phase
+ the increment (and the phase) should be a multiple of S */
+ if (inc < 0.0f) inc = -inc;
+ phase_inc = ((u32)inc) & ~(S-1);
+ oldphase = phase;
+ phase += phase_inc;
+
+
+ /* check for phase wrap */
+ if (phase < oldphase){
+ u32 phase_inc_decimated = phase_inc >> LOVERSAMPLE;
+ u32 table_index;
+ u32 table_phase;
+
+ /* steal the oldest voice if we have a phase wrap */
+
+ voice = ctl->c_next_voice++;
+ ctl->c_next_voice &= VOICES-1;
+
+ /* determine the location of the discontinuity (in oversampled coordinates)
+ which is S * (new phase) / (increment) */
+
+ table_index = phase / phase_inc_decimated;
+
+ /* determine the fractional part (in oversampled coordinates)
+ for linear interpolation */
+
+ table_phase = phase - (table_index * phase_inc_decimated);
+
+ /* use it to initialize the new voice index and interpolation fraction */
+
+ ctl->c_index[voice] = table_index;
+ ctl->c_frac[voice] = (float)table_phase / (float)phase_inc_decimated;
+ ctl->c_vscale[voice] = scale;
+ scale = scale * ctl->c_scale_update;
+
+ }
+
+ /* save state */
+ ctl->c_phase = phase;
+ ctl->c_scale = scale;
+}
+
+
+/* the 2 oscillator version:
+ the second osc can reset the first osc's phase (hence it determines the pitch)
+ the first osc determines the waveform */
+
+static void _bang_hardsync_phasor(t_ebloscctl *ctl, float freq, float freq2)
+{
+ u32 phase = ctl->c_phase;
+ u32 phase2 = ctl->c_phase2;
+ u32 phase_inc;
+ u32 phase_inc2;
+ u32 oldphase;
+ u32 oldphase2;
+ int voice;
+ float scale = ctl->c_scale;
+
+
+ /* get increment */
+ float inc = freq * ctl->c_phase_inc_scale;
+ float inc2 = freq2 * ctl->c_phase_inc_scale;
+
+ /* calculate new phases
+ the increment (and the phase) should be a multiple of S */
+
+ /* save previous phases */
+ oldphase = phase;
+ oldphase2 = phase2;
+
+ /* update second osc */
+ if (inc2 < 0.0f) inc2 = -inc2;
+ phase_inc2 = ((u32)inc2) & ~(S-1);
+ phase2 += phase_inc2;
+
+ /* update first osc (freq should be >= freq of sync osc */
+ if (inc < 0.0f) inc = -inc;
+ phase_inc = ((u32)inc) & ~(S-1);
+ if (phase_inc < phase_inc2) phase_inc = phase_inc2;
+ phase += phase_inc;
+
+
+ /* check for sync discontinuity (osc 2) */
+ if (phase2 < oldphase2) {
+
+ /* adjust phase depending on the location of the discontinuity in phase2:
+ phase/phase_inc == phase2/phase_inc2 */
+
+ u64 pi = phase_inc >> LOVERSAMPLE;
+ u64 pi2 = phase_inc2 >> LOVERSAMPLE;
+ u64 lphase = ((u64)phase2 * pi) / pi2;
+ phase = lphase & ~(S-1);
+ }
+
+
+ /* check for phase discontinuity (osc 1) */
+ if (phase < oldphase){
+ u32 phase_inc_decimated = phase_inc >> LOVERSAMPLE;
+ u32 table_index;
+ u32 table_phase;
+ float stepsize;
+
+ /* steal the oldest voice if we have a phase wrap */
+
+ voice = ctl->c_next_voice++;
+ ctl->c_next_voice &= VOICES-1;
+
+ /* determine the location of the discontinuity (in oversampled coordinates)
+ which is S * (new phase) / (increment) */
+
+ table_index = phase / phase_inc_decimated;
+
+ /* determine the fractional part (in oversampled coordinates)
+ for linear interpolation */
+
+ table_phase = phase - (table_index * phase_inc_decimated);
+
+ /* determine the step size
+ as opposed to saw/impulse waveforms, the step is not always equal to one. it is:
+ oldphase - phase + phase_inc
+ but for the unit step this will overflow to zero, so we
+ reduce the bit depth to prevent overflow */
+
+ stepsize = _phase_to_float(((oldphase-phase) >> LOVERSAMPLE)
+ + phase_inc_decimated) * (float)S;
+
+ /* use it to initialize the new voice index and interpolation fraction */
+
+ ctl->c_index[voice] = table_index;
+ ctl->c_frac[voice] = (float)table_phase / (float)phase_inc_decimated;
+ ctl->c_vscale[voice] = scale * stepsize;
+ scale = scale * ctl->c_scale_update;
+
+ }
+
+ /* save state */
+ ctl->c_phase = phase;
+ ctl->c_phase2 = phase2;
+ ctl->c_scale = scale;
+}
+
+
+static t_int *eblosc_perform_hardsync_saw(t_int *w)
+{
+ t_float *freq = (float *)(w[3]);
+ t_float *freq2 = (float *)(w[4]);
+ t_float *out = (float *)(w[5]);
+ t_ebloscctl *ctl = (t_ebloscctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+
+ /* set postfilter cutoff */
+ ctl->c_butter->setButterHP(0.85f * (*freq / sys_getsr()));
+
+ while (n--) {
+ float frequency = *freq++;
+ float frequency2 = *freq2++;
+
+ /* get the bandlimited discontinuity */
+ float sample = _get_bandlimited_discontinuity(ctl, bls);
+
+ /* add aliased sawtooth wave */
+ sample += _phase_to_float(ctl->c_phase) - 0.5f;
+
+ /* highpass filter output to remove DC offset and low frequency aliasing */
+ ctl->c_butter->BangSmooth(sample, sample, 0.05f);
+
+ /* send to output */
+ *out++ = sample;
+
+ /* advance phasor */
+ _bang_hardsync_phasor(ctl, frequency2, frequency);
+
+ }
+
+ return (w+6);
+}
+
+static t_int *eblosc_perform_saw(t_int *w)
+{
+ t_float *freq = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_ebloscctl *ctl = (t_ebloscctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+
+ while (n--) {
+ float frequency = *freq++;
+
+ /* get the bandlimited discontinuity */
+ float sample = _get_bandlimited_discontinuity(ctl, bls);
+
+ /* add aliased sawtooth wave */
+ sample += _phase_to_float(ctl->c_phase) - 0.5f;
+
+ /* send to output */
+ *out++ = sample;
+
+ /* advance phasor */
+ _bang_phasor(ctl, frequency);
+
+ }
+
+ return (w+5);
+}
+
+
+
+static t_int *eblosc_perform_pulse(t_int *w)
+{
+ t_float *freq = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_ebloscctl *ctl = (t_ebloscctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+
+
+ /* set postfilter cutoff */
+ ctl->c_butter->setButterHP(0.85f * (*freq / sys_getsr()));
+
+ while (n--) {
+ float frequency = *freq++;
+
+ /* get the bandlimited discontinuity */
+ float sample = _get_bandlimited_discontinuity(ctl, bli);
+
+ /* highpass filter output to remove DC offset and low frequency aliasing */
+ ctl->c_butter->BangSmooth(sample, sample, 0.05f);
+
+ /* send to output */
+ *out++ = sample;
+
+ /* advance phasor */
+ _bang_phasor(ctl, frequency);
+
+ }
+
+ return (w+5);
+}
+
+static t_int *eblosc_perform_comparator(t_int *w)
+{
+ t_float *amp = (float *)(w[3]);
+ t_float *out = (float *)(w[4]);
+ t_ebloscctl *ctl = (t_ebloscctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i;
+ t_float prev_amp = ctl->c_prev_amp;
+
+ while (n--) {
+ float curr_amp = *amp++;
+
+ /* exact zero won't work for zero detection (sic) */
+ if (curr_amp == 0.0f) curr_amp = 0.0000001f;
+
+ /* get the bandlimited discontinuity */
+ float sample = _get_bandlimited_discontinuity(ctl, bls);
+
+ /* add the block wave state */
+ sample += ctl->c_state;
+
+ /* send to output */
+ *out++ = sample;
+
+ /* advance phasor */
+ _bang_comparator(ctl, prev_amp, curr_amp);
+
+ prev_amp = curr_amp;
+
+ }
+
+ ctl->c_prev_amp = prev_amp;
+
+ return (w+5);
+}
+
+static void eblosc_phase(t_eblosc *x, t_float f)
+{
+ x->x_ctl.c_phase = _float_to_phase(f);
+ x->x_ctl.c_phase2 = _float_to_phase(f);
+}
+
+static void eblosc_phase1(t_eblosc *x, t_float f)
+{
+ x->x_ctl.c_phase = _float_to_phase(f);
+}
+
+static void eblosc_phase2(t_eblosc *x, t_float f)
+{
+ x->x_ctl.c_phase2 = _float_to_phase(f);
+}
+
+static void eblosc_dsp(t_eblosc *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+
+ /* set sampling rate scaling for phasors */
+ x->x_ctl.c_phase_inc_scale = 4.0f * (float)(1<<(LPHASOR-2)) / sys_getsr();
+
+
+ /* setup & register the correct process routine depending on the waveform */
+
+ /* 2 osc */
+ if (x->x_ctl.c_waveform == gensym("syncsaw")){
+ x->x_ctl.c_scale = 1.0f;
+ x->x_ctl.c_scale_update = 1.0f;
+ dsp_add(eblosc_perform_hardsync_saw, 5, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+ }
+
+ /* 1 osc */
+ else if (x->x_ctl.c_waveform == gensym("pulse")){
+ x->x_ctl.c_scale = 1.0f;
+ x->x_ctl.c_scale_update = 1.0f;
+ dsp_add(eblosc_perform_pulse, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ }
+ else if (x->x_ctl.c_waveform == gensym("pulse2")){
+ x->x_ctl.c_phase_inc_scale *= 2;
+ x->x_ctl.c_scale = 1.0f;
+ x->x_ctl.c_scale_update = -1.0f;
+ dsp_add(eblosc_perform_pulse, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ }
+ else if (x->x_ctl.c_waveform == gensym("comparator")){
+ x->x_ctl.c_scale = 1.0f;
+ x->x_ctl.c_scale_update = 1.0f;
+ dsp_add(eblosc_perform_comparator, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ }
+ else{
+ x->x_ctl.c_scale = 1.0f;
+ x->x_ctl.c_scale_update = 1.0f;
+ dsp_add(eblosc_perform_saw, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ }
+
+
+
+}
+static void eblosc_free(t_eblosc *x)
+{
+ delete x->x_ctl.c_butter;
+}
+
+t_class *eblosc_class;
+
+static void *eblosc_new(t_symbol *s)
+{
+ t_eblosc *x = (t_eblosc *)pd_new(eblosc_class);
+ int i;
+
+ /* out 1 */
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ /* optional signal inlets */
+ if (s == gensym("syncsaw")){
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ }
+
+ /* optional phase inlet */
+ if (s != gensym("comparator")){
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("phase"));
+ }
+
+ /* create the postfilter */
+ x->x_ctl.c_butter = new DSPIfilterSeries(3);
+
+ /* init oscillators */
+ for (i=0; i<VOICES; i++) {
+ x->x_ctl.c_index[i] = N-2;
+ x->x_ctl.c_frac[i] = 0.0f;
+ }
+
+ /* init rest of state data */
+ eblosc_phase(x, 0);
+ eblosc_phase2(x, 0);
+ x->x_ctl.c_state = 0.0;
+ x->x_ctl.c_prev_amp = 0.0;
+ x->x_ctl.c_next_voice = 0;
+ x->x_ctl.c_scale = 1.0f;
+ x->x_ctl.c_scale_update = 1.0f;
+ x->x_ctl.c_waveform = s;
+
+ return (void *)x;
+}
+
+
+
+
+
+extern "C"
+{
+ void eblosc_tilde_setup(void)
+ {
+ //post("eblosc~ v0.1");
+
+ build_tables();
+
+ eblosc_class = class_new(gensym("eblosc~"), (t_newmethod)eblosc_new,
+ (t_method)eblosc_free, sizeof(t_eblosc), 0, A_DEFSYMBOL, A_NULL);
+ CLASS_MAINSIGNALIN(eblosc_class, t_eblosc, x_f);
+ class_addmethod(eblosc_class, (t_method)eblosc_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(eblosc_class, (t_method)eblosc_phase, gensym("phase"), A_FLOAT, A_NULL);
+ class_addmethod(eblosc_class, (t_method)eblosc_phase2, gensym("phase2"), A_FLOAT, A_NULL);
+
+
+ }
+
+}
+
+#endif
diff --git a/modules/fdn.c b/modules/fdn.c
index 22fcc40..9fbfee7 100644
--- a/modules/fdn.c
+++ b/modules/fdn.c
@@ -311,11 +311,11 @@ static void fdn_updatedamping(t_fdn *x)
}
static void fdn_timelow(t_fdn *x, t_float f){
- x->x_ctl.c_timelow = f;
+ x->x_ctl.c_timelow = fabs(f);
fdn_updatedamping(x);
}
static void fdn_timehigh(t_fdn *x, t_float f){
- x->x_ctl.c_timehigh = f;
+ x->x_ctl.c_timehigh = fabs(f);
fdn_updatedamping(x);
}
diff --git a/modules/lattice.c b/modules/lattice.c
index 9403393..6f8e816 100644
--- a/modules/lattice.c
+++ b/modules/lattice.c
@@ -22,7 +22,8 @@
#include "m_pd.h"
#include <math.h>
-#define maxorder 1024
+#define MAXORDER 1024
+#define MAXREFCO 0.9999f
typedef struct latticesegment
{
@@ -32,7 +33,7 @@ typedef struct latticesegment
typedef struct latticectl
{
- t_latticesegment c_segment[maxorder]; // array of lattice segment data
+ t_latticesegment c_segment[MAXORDER]; // array of lattice segment data
t_int c_segments;
} t_latticectl;
@@ -98,8 +99,8 @@ static void lattice_rc(t_lattice *x, t_float segment, t_float refco)
{
t_int seg = (t_float)segment;
if ((seg >= 0) && (seg < x->x_ctl.c_segments)){
- if (refco > 1.0f) refco = 1.0f;
- if (refco < -1.0f) refco = -1.0f;
+ if (refco >= MAXREFCO) refco = MAXREFCO;
+ if (refco <= -MAXREFCO) refco = -MAXREFCO;
x->x_ctl.c_segment[seg].rc = refco;
}
}
@@ -120,7 +121,7 @@ static void *lattice_new(t_floatarg segments)
outlet_new(&x->x_obj, gensym("signal"));
if (seg < 1) seg = 1;
- if (seg > maxorder) seg = maxorder;
+ if (seg > MAXORDER) seg = MAXORDER;
x->x_ctl.c_segments = seg;
diff --git a/modules/matrix.c b/modules/matrix.c
index 6fd55b7..b59d4d6 100644
--- a/modules/matrix.c
+++ b/modules/matrix.c
@@ -140,10 +140,10 @@ static void *matrix_new(t_floatarg order)
return (void *)x;
}
-void matrix_tilde_setup(void)
+void bmatrix_tilde_setup(void)
{
//post("matrix~ v0.1");
- matrix_class = class_new(gensym("matrix~"), (t_newmethod)matrix_new,
+ matrix_class = class_new(gensym("bmatrix~"), (t_newmethod)matrix_new,
(t_method)matrix_free, sizeof(t_matrix), 0, A_DEFFLOAT, 0);
CLASS_MAINSIGNALIN(matrix_class, t_matrix, x_f);
class_addmethod(matrix_class, (t_method)matrix_dsp, gensym("dsp"), 0);
diff --git a/modules/permut.c b/modules/permut.c
index bc143d2..7738f84 100644
--- a/modules/permut.c
+++ b/modules/permut.c
@@ -20,9 +20,10 @@
*/
-#include "m_pd.h"
#include <math.h>
#include <stdlib.h>
+//#include "m_pd.h"
+#include "extlib_util.h"
@@ -64,7 +65,8 @@ static void permut_random(t_permut *x, t_floatarg seed)
int *p = x->x_ctl.c_permutationtable;
int r, last = 0;
- srand(* ((unsigned int *)(&seed)));
+ //srand(* ((unsigned int *)(&seed)));
+ srand (((t_flint)seed).i);
if(p)
{
@@ -91,7 +93,8 @@ static void permut_random(t_permut *x, t_floatarg seed)
static void permut_bang(t_permut *x)
{
unsigned int r = rand();
- permut_random(x, *((float *)(&r)));
+ //permut_random(x, *((float *)(&r)));
+ permut_random(x, ((t_flint)r).f);
}
static void permut_resize_table(t_permut *x, int size)
diff --git a/modules/ramp.c b/modules/ramp.c
index ad13582..526ec4e 100644
--- a/modules/ramp.c
+++ b/modules/ramp.c
@@ -24,64 +24,53 @@
typedef struct rampctl
{
- t_float c_offset;
- t_float c_looppoint;
+ t_float c_offset;
+ t_int c_blockscale;
} t_rampctl;
typedef struct ramp
{
- t_object x_obj;
- t_float x_f;
- t_rampctl x_ctl;
+ t_object x_obj;
+ t_float x_f;
+ t_rampctl x_ctl;
} t_ramp;
void ramp_offset(t_ramp *x, t_floatarg f)
{
-
- x->x_ctl.c_offset = f;
-
-}
-
-void ramp_looppoint(t_ramp *x, t_floatarg f)
-{
-
- x->x_ctl.c_looppoint = f;
-
+ x->x_ctl.c_offset = f;
}
void ramp_bang(t_ramp *x)
{
- ramp_offset(x, 0);
-
+ ramp_offset(x, 0);
}
static t_int *ramp_perform(t_int *w)
{
+ t_float *out = (float *)(w[3]);
+ t_rampctl *ctl = (t_rampctl *)(w[1]);
+ t_int i;
+ t_int n = (t_int)(w[2]);
+ t_float x;
-
- t_float *out = (float *)(w[3]);
- t_rampctl *ctl = (t_rampctl *)(w[1]);
- t_int i;
- t_int n = (t_int)(w[2]);
- t_float x;
-
+ t_float scale = ctl->c_blockscale ? 1.0f / (float)n : 1.0f;
- x = ctl->c_offset;
-
- for (i = 0; i < n; i++)
- {
- *out++ = (float)x++;
- }
+ x = ctl->c_offset;
+
+ for (i = 0; i < n; i++)
+ {
+ *out++ = ((float)x++) * scale;
+ }
- ctl->c_offset = x; /* save state */
+ ctl->c_offset = x; /* save state */
- return (w+4);
+ return (w+4);
}
static void ramp_dsp(t_ramp *x, t_signal **sp)
@@ -99,18 +88,27 @@ t_class *ramp_class;
void *ramp_new(void)
{
t_ramp *x = (t_ramp *)pd_new(ramp_class);
- /* inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("looppoint"));*/
outlet_new(&x->x_obj, gensym("signal"));
-
+ x->x_ctl.c_blockscale = 0;
ramp_bang(x);
return (void *)x;
}
+void *blockramp_new(void)
+{
+ t_ramp *x = (t_ramp *)ramp_new();
+ x->x_ctl.c_blockscale = 1;
+ return (void *)x;
+}
+
void ramp_tilde_setup(void)
{
//post("ramp~ v0.1");
ramp_class = class_new(gensym("ramp~"), (t_newmethod)ramp_new,
(t_method)ramp_free, sizeof(t_ramp), 0, 0);
+
+ class_addcreator((t_newmethod)blockramp_new, gensym("blockramp~"), A_NULL);
+
class_addmethod(ramp_class, (t_method)ramp_bang, gensym("bang"), 0);
class_addmethod(ramp_class, (t_method)ramp_dsp, gensym("dsp"), 0);
class_addfloat(ramp_class, (t_method)ramp_offset);
diff --git a/modules/resofilt.c b/modules/resofilt.c
new file mode 100644
index 0000000..ba74532
--- /dev/null
+++ b/modules/resofilt.c
@@ -0,0 +1,397 @@
+/*
+ * resofilt.c - some high quality time variant filters
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* some (expensive) time variant iir filters,
+ i.e. moog 4-pole transfer function using the impulse
+ invariant transform with self osc and
+ signal freq and reso inputs */
+
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "filters.h"
+
+
+typedef struct resofiltctl
+{
+ t_float c_state[4]; /* filter state */
+ t_float c_f_prev;
+ t_float c_r_prev;
+
+} t_resofiltctl;
+
+typedef struct resofilt
+{
+ t_object x_obj;
+ t_float x_f;
+ t_resofiltctl x_ctl;
+ t_perfroutine x_dsp;
+} t_resofilt;
+
+
+static inline void _sat_state(t_float *x)
+{
+ const float norm_squared_max = 1.0f;
+ float norm_squared = x[0] * x[0] + x[1] * x[1];
+
+ if (norm_squared > norm_squared_max){
+ float scale = 1.0f / sqrt(norm_squared);
+ x[0] *= scale;
+ x[1] *= scale;
+ }
+}
+
+
+/* the moog vcf discretized with an impulse invariant transform */
+
+static t_int *resofilt_perform_fourpole(t_int *w)
+{
+
+ t_resofiltctl *ctl = (t_resofiltctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_float *in = (float *)(w[3]);
+ t_float *freq = (float *)(w[4]);
+ t_float *reso = (float *)(w[5]);
+ t_float *out = (float *)(w[6]);
+
+ int i;
+ t_float inv_n = 1.0f / ((float)n);
+ t_float inv_sr = 1.0f / sys_getsr();
+
+ t_float phasor[2], phasor_rot[2];
+ t_float radior[2], radior_rot[2];
+ t_float scalor, scalor_inc;
+
+ t_float f,r,freq_rms,reso_rms;
+ t_float f_prev = ctl->c_f_prev;
+ t_float r_prev = ctl->c_r_prev;
+
+ /* use rms of input to drive freq and reso
+ this is such that connecting a dsp signal to the inlets has a reasonable result,
+ even if the inputs are oscillatory. the rms values will be interpolated linearly
+ (that is, linearly in the "analog" domain, so exponentially in the z-domain) */
+
+ reso_rms = freq_rms = 0.0f;
+ for (i=0; i<n; i++){
+ t_float _freq = *freq++; /* first input is the reso frequency (absolute) */
+ t_float _reso = *reso++; /* second input is the resonnance (0->1), >1 == self osc */
+ freq_rms += _freq * _freq;
+ reso_rms += _reso * _reso;
+ }
+ freq_rms = sqrt(freq_rms * inv_n) * inv_sr;
+ reso_rms = sqrt(reso_rms * inv_n);
+ f = (freq_rms > 0.5f) ? 0.5f : freq_rms;
+ r = sqrt(sqrt(reso_rms));
+
+
+ /* calculate the new pole locations
+ we use an impulse invariant transform: the moog vcf poles are located at
+ s_p = (-1 +- r \sqrt{+- j}, with r = (k/4)^(1/4) \in [0,1]
+
+ the poles are always complex, so we can use an orthogonal implementation
+ both conj pole pairs have the same angle, so we can use one phasor and 2 radii
+ */
+
+ /* compute phasor, radius and update eqs
+ since these are at k-rate, the expense is justifyable */
+ phasor[0] = cos(2.0 * M_PI * r_prev * f_prev);
+ phasor[1] = sin(2.0 * M_PI * r_prev * f_prev);
+ phasor_rot[0] = cos(2.0 * M_PI * (r*f - r_prev*f_prev) * inv_n);
+ phasor_rot[1] = sin(2.0 * M_PI * (r*f - r_prev*f_prev) * inv_n);
+
+ radior[0] = exp(f_prev * (-1.0 + r_prev)); /* dominant radius */
+ radior[1] = exp(f_prev * (-1.0 - r_prev));
+ radior_rot[0] = exp((f*(-1.0f + r) - f_prev * (-1.0 + r_prev)) * inv_n);
+ radior_rot[1] = exp((f*(-1.0f - r) - f_prev * (-1.0 - r_prev)) * inv_n);
+
+ /* moog like scaling */
+ if (1){
+ float r2 = r_prev * r_prev;
+ float r4 = r2 * r2;
+ scalor = 1.0f + (1.0f + 4.0f * r4);
+ r2 = r * r;
+ r4 = r2 * r2;
+ scalor_inc = ((1.0f + (1.0f + 4.0f * r4)) - scalor) * inv_n;
+ }
+
+ /* no scaling */
+ else{
+ scalor = 1.0f;
+ scalor_inc = 0.0f;
+ }
+
+ ctl->c_f_prev = f;
+ ctl->c_r_prev = r;
+
+
+
+
+
+ /* perform filtering */
+ for (i=0; i<n; i++){
+ float poleA[2], poleB[2];
+ float *stateA = ctl->c_state;
+ float *stateB = ctl->c_state+2;
+
+ float x;
+
+ /* compute poles */
+ poleA[0] = radior[0] * phasor[0];
+ poleA[1] = radior[0] * phasor[1];
+ poleB[0] = radior[1] * phasor[0];
+ poleB[1] = radior[1] * phasor[1];
+
+
+ /* perform filtering: use 2 DC normalized complex one-poles:
+ y[k] = x[k] + a(y[k-1] - x[k]) or y(z) = (1-a)/(1-az^{-1}) x(z) */
+
+ x = *in++ * scalor;
+
+ /* nondominant pole first */
+ stateB[0] -= x;
+ vcmul2(stateB, poleB);
+ x = stateB[0] += x;
+
+ /* dominant pole second */
+ stateA[0] -= x;
+ vcmul2(stateA, poleA);
+ x = stateA[0] += x;
+
+ *out++ = x;
+
+ /* saturate (normalize if pow > 1) state to prevent explosion and to allow self-osc */
+ _sat_state(stateA);
+ _sat_state(stateB);
+
+ /* interpolate filter coefficients */
+ vcmul2(phasor, phasor_rot);
+ radior[0] *= radior_rot[0];
+ radior[1] *= radior_rot[1];
+ scalor += scalor_inc;
+
+ }
+
+ return (w+7);
+}
+
+
+
+
+
+/* 303-style modified moog vcf (3-pole) */
+
+static t_int *resofilt_perform_threepole(t_int *w)
+{
+
+ t_resofiltctl *ctl = (t_resofiltctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_float *in = (float *)(w[3]);
+ t_float *freq = (float *)(w[4]);
+ t_float *reso = (float *)(w[5]);
+ t_float *out = (float *)(w[6]);
+
+ int i;
+ t_float inv_n = 1.0f / ((float)n);
+ t_float inv_sr = 1.0f / sys_getsr();
+
+ t_float phasor[2], phasor_rot[2];
+ t_float radior[2], radior_rot[2];
+ t_float scalor, scalor_inc;
+
+ t_float f,r,freq_rms,reso_rms;
+ t_float f_prev = ctl->c_f_prev;
+ t_float r_prev = ctl->c_r_prev;
+
+ t_float sqrt5 = sqrtf(5.0f);
+
+ /* use rms of input to drive freq and reso */
+ reso_rms = freq_rms = 0.0f;
+ for (i=0; i<n; i++){
+ t_float _freq = *freq++; /* first input is the reso frequency (absolute) */
+ t_float _reso = *reso++; /* second input is the resonnance (0->1), >1 == self osc */
+ freq_rms += _freq * _freq;
+ reso_rms += _reso * _reso;
+ }
+ freq_rms = sqrt(freq_rms * inv_n) * inv_sr;
+ reso_rms = sqrt(reso_rms * inv_n);
+ f = (freq_rms > 0.5f) ? 0.25f : freq_rms * 0.5f;
+ r = cbrt(reso_rms);
+
+
+ /* calculate the new pole locations
+ we use an impulse invariant transform: the 303 vcf poles are located at
+ s_p = omega(-1 + r sqrt(5) e^{pi/3(1+2p)})
+
+ real pole: omega * (-1 -r)
+ complex pole:
+ real = omega (-1 + r)
+ imag = omega (+- 2 r)
+
+
+ this is a strange beast. legend goes it was "invented" by taking the moog vcf
+ and moving one cap up, such that the not-so controllable 3-pole that emerged
+ would avoid the moog patent..
+
+ so, the sound is not so much the locations of the poles, but how the filter
+ reacts to time varying controls. i.e. the pole movement with constant reso,
+ used in the tb-303.
+
+ */
+
+ /* compute phasor, radius and update eqs */
+ phasor[0] = cos(2.0 * M_PI * r_prev * f_prev * 2.0f);
+ phasor[1] = sin(2.0 * M_PI * r_prev * f_prev * 2.0f);
+ phasor_rot[0] = cos(2.0 * M_PI * (r*f - r_prev*f_prev) * 2.0f * inv_n);
+ phasor_rot[1] = sin(2.0 * M_PI * (r*f - r_prev*f_prev) * 2.0f * inv_n);
+
+ radior[0] = exp(f_prev * (-1.0 + r_prev)); /* dominant radius */
+ radior[1] = exp(f_prev * (-1.0 - sqrt5 * r_prev));
+ radior_rot[0] = exp((f*(-1.0f + r) - f_prev * (-1.0 + r_prev)) * inv_n);
+ radior_rot[1] = exp((f*(-1.0f - r) - f_prev * (-1.0 - sqrt5 * r_prev)) * inv_n);
+
+ /* 303 like scaling */
+ if (1){
+ float r3 = r_prev * r_prev * r_prev;
+ scalor = 1.0f + (1.0f + 3.0f * r_prev);
+ r3 = r * r * r;
+ scalor_inc = ((1.0f + (1.0f + 3.0f * r3)) - scalor) * inv_n;
+ }
+
+ /* no scaling */
+ else{
+ scalor = 1.0f;
+ scalor_inc = 0.0f;
+ }
+
+ ctl->c_f_prev = f;
+ ctl->c_r_prev = r;
+
+
+ ctl->c_state[3] = 0.0f;
+ /* perform filtering */
+ for (i=0; i<n; i++){
+ float poleA[2], poleB[2];
+ float *stateA = ctl->c_state;
+ float *stateB = ctl->c_state+2;
+
+ float x;
+
+ /* compute poles */
+ poleA[0] = radior[0] * phasor[0];
+ poleA[1] = radior[0] * phasor[1];
+
+ poleB[0] = radior[1];
+
+
+ /* perform filtering: use (real part of) 2 DC normalized complex one-poles:
+ y[k] = x[k] + a(y[k-1] - x[k]) or y(z) = (1-a)/(1-az^{-1}) x(z) */
+
+ x = *in++ * scalor;
+
+ /* nondominant pole first */
+ stateB[0] -= x;
+ stateB[0] *= poleB[0];
+ x = stateB[0] += x;
+
+ /* dominant pole second */
+ stateA[0] -= x;
+ vcmul2(stateA, poleA);
+ x = stateA[0] += x;
+
+ *out++ = x;
+
+ /* saturate (normalize if pow > 1) state to prevent explosion and to allow self-osc */
+ _sat_state(stateA);
+ _sat_state(stateB);
+
+ /* interpolate filter coefficients */
+ vcmul2(phasor, phasor_rot);
+ radior[0] *= radior_rot[0];
+ radior[1] *= radior_rot[1];
+ scalor += scalor_inc;
+
+ }
+
+ return (w+7);
+}
+
+
+
+
+
+static void resofilt_dsp(t_resofilt *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+
+ dsp_add(x->x_dsp,
+ 6,
+ &x->x_ctl,
+ sp[0]->s_n,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec);
+
+}
+static void resofilt_free(t_resofilt *x)
+{
+
+
+}
+
+t_class *resofilt_class;
+
+static void *resofilt_new(t_floatarg algotype)
+{
+ t_resofilt *x = (t_resofilt *)pd_new(resofilt_class);
+
+ /* in */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+
+ /* out */
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+ /* set algo type */
+ if (algotype == 3.0f){
+ post("resofilt~: 3-pole lowpass ladder vcf");
+ x->x_dsp = resofilt_perform_threepole;
+ }
+ else {
+ post("resofilt~: 4-pole lowpass ladder vcf");
+ x->x_dsp = resofilt_perform_fourpole;
+ }
+
+
+ return (void *)x;
+}
+
+void resofilt_tilde_setup(void)
+{
+ resofilt_class = class_new(gensym("resofilt~"), (t_newmethod)resofilt_new,
+ (t_method)resofilt_free, sizeof(t_resofilt), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(resofilt_class, t_resofilt, x_f);
+ class_addmethod(resofilt_class, (t_method)resofilt_dsp, gensym("dsp"), 0);
+}
+
diff --git a/modules/sbosc.c b/modules/sbosc.c
new file mode 100644
index 0000000..511c770
--- /dev/null
+++ b/modules/sbosc.c
@@ -0,0 +1,175 @@
+/*
+ * sbosc.c - smallband oscillator. periodic, linear interpolated frequency center.
+ * data organization is in (real, imag) pairs
+ * the first 2 components are (DC, NY)
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define LOGTABSIZE 10
+#define TABSIZE (1<<LOGTABSIZE)
+#define MASKTABSIZE (TABSIZE-1)
+
+#define SHIFTTABSIZE ((sizeof(unsigned int) * 8) - LOGTABSIZE)
+#define FRACTABSIZE (1<<SHIFTTABSIZE)
+#define INVFRACTABSIZE (1.0f / (float)(FRACTABSIZE))
+#define MASKFRACTABSIZE (FRACTABSIZE-1)
+
+#define PITCHLIMIT 20.0f
+
+static float costable[TABSIZE];
+
+static inline void _exp_j2pi(unsigned int t, float *real, float *imag)
+{
+ unsigned int i1 = t >> SHIFTTABSIZE;
+ float f2 = (t & MASKFRACTABSIZE) * INVFRACTABSIZE;
+ unsigned int i2 = (i1+1) & MASKTABSIZE;
+ unsigned int i3 = (i1 - (TABSIZE>>2)) & MASKTABSIZE;
+ unsigned int i4 = (i2 + 1 - (TABSIZE>>2)) & MASKTABSIZE;
+ float f1 = 1.0f - f2;
+ float a1 = f1 * costable[i1];
+ float a2 = f2 * costable[i2];
+ float b1 = f1 * costable[i3];
+ float b2 = f2 * costable[i4];
+ *real = a1 + a2;
+ *imag = b1 + b2;
+}
+
+static t_class *sbosc_tilde_class;
+
+typedef struct _sbosc_tilde
+{
+ t_object x_obj;
+ float x_f;
+
+ /* state vars */
+ unsigned int x_phase; // phase of main pitch osc
+ unsigned int x_phase_inc; // frequency of main pitch osc
+ unsigned int x_harmonic; // first harmonic
+ float x_frac; // fraction of first harmonic
+
+
+} t_sbosc_tilde;
+
+static void *sbosc_tilde_new(void)
+{
+ t_sbosc_tilde *x = (t_sbosc_tilde *)pd_new(sbosc_tilde_class);
+ x->x_phase = 0;
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("phase"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+
+static t_int *sbosc_tilde_perform(t_int *w)
+{
+ t_sbosc_tilde *x = (t_sbosc_tilde *)(w[1]);
+ t_float *pitch = (t_float *)(w[2]);
+ t_float *center= (t_float *)(w[3]);
+ t_float *out_real = (t_float *)(w[4]);
+ t_float *out_imag = (t_float *)(w[5]);
+ int n = (int)(w[6]);
+ int i;
+
+ t_float pitch_to_phase = 4294967295.0f / sys_getsr();
+
+ for (i = 0; i < n; i++)
+ {
+ float p = *pitch++;
+ float c = *center++;
+ float r1,r2,i1,i2;
+
+ /* compute harmonic mixture */
+ unsigned int h1 = x->x_phase * x->x_harmonic;
+ unsigned int h2 = h1 + x->x_phase;
+ _exp_j2pi(h1, &r1, &i1);
+ _exp_j2pi(h2, &r2, &i2);
+ r1 *= x->x_frac;
+ i1 *= x->x_frac;
+ r2 *= 1.0f - x->x_frac;
+ i2 *= 1.0f - x->x_frac;
+
+ *out_real++ = r1 + r2;
+ *out_imag++ = i1 + i2;
+
+
+ x->x_phase += x->x_phase_inc;
+
+ /* check for phase wrap & update osc */
+ if ((x->x_phase <= x->x_phase_inc))
+ {
+ float p_plus = (p < 0.0f) ? -p : p;
+ float p_limit = (p_plus < PITCHLIMIT) ? PITCHLIMIT : p_plus;
+ float c_plus = (c < 0.0f) ? -c : c;
+ float harmonic = c_plus/p_limit;
+ x->x_phase_inc = pitch_to_phase * p_limit;
+ x->x_harmonic = harmonic;
+ x->x_frac = 1.0f - (harmonic - x->x_harmonic);
+ }
+
+
+ }
+
+ return (w+7);
+}
+
+static void sbosc_tilde_dsp(t_sbosc_tilde *x, t_signal **sp)
+{
+ dsp_add(sbosc_tilde_perform, 6, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n);
+
+}
+
+static void sbosc_tilde_free(t_sbosc_tilde *x)
+{
+}
+
+static void sbosc_tilde_phase(t_sbosc_tilde *x, t_floatarg f)
+{
+ x->x_phase = f * (1.0f / 4294967295.0f);
+}
+
+void sbosc_tilde_setup(void)
+{
+ int i;
+
+ // init tables
+ for (i=0; i<TABSIZE; i++)
+ costable[i] = cos(2.0 * M_PI * (double)i / (double)TABSIZE);
+
+
+
+ // class setup
+ sbosc_tilde_class = class_new(gensym("sbosc~"),
+ (t_newmethod)sbosc_tilde_new, (t_method)sbosc_tilde_free,
+ sizeof(t_sbosc_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(sbosc_tilde_class, t_sbosc_tilde, x_f);
+ class_addmethod(sbosc_tilde_class, (t_method)sbosc_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(sbosc_tilde_class, (t_method)sbosc_tilde_phase,
+ gensym("phase"), A_FLOAT, 0);
+}
+
diff --git a/modules/scrollgrid1D.c b/modules/scrollgrid1D.c
new file mode 100644
index 0000000..bcac7fe
--- /dev/null
+++ b/modules/scrollgrid1D.c
@@ -0,0 +1,220 @@
+/*
+ * scrollgrid1D.c - 1D scroll grid attractor
+ * Copyright (c) 2000-2003 by Tom Schouten
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* 1D scroll grid attractor
+ for more information see:
+
+ Yalcin M., Ozoguz S., Suykens J.A.K., Vandewalle J.,
+ ``Families of Scroll Grid Attractors'',
+ International Journal of Bifurcation and Chaos, vol. 12, no. 1, Jan. 2002, pp. 23-41.
+
+ this file implements a digital variant of the method introduced in the paper,
+ so that it can be used as a parametrizable, bounded chatotic oscillator.
+ in short it is a switched linear system, with some added hard limiting to
+ convert unstable oscillations into stable ones.
+
+*/
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "filters.h"
+
+
+typedef struct scrollgrid1Dctl
+{
+ t_float c_x, c_y, c_z; /* state */
+
+} t_scrollgrid1Dctl;
+
+typedef struct scrollgrid1D
+{
+ t_object x_obj;
+ t_float x_f;
+ t_scrollgrid1Dctl x_ctl;
+} t_scrollgrid1D;
+
+
+static inline float _fixedpoint(float x, int n)
+{
+ int ix = (x + 0.5f);
+ if (ix < 0) ix = 0;
+ else if (ix >= n) ix = n-1;
+ return (float)ix;
+}
+
+static inline float _sat(float x, float upper)
+{
+ float lower = -1.0f;
+ if (x < lower) x = lower;
+ else if (x > upper) x = upper;
+ return x;
+}
+
+static t_int *scrollgrid1D_perform(t_int *w)
+{
+
+
+ t_float *freq = (float *)(w[3]);
+ t_float *t1 = (float *)(w[4]);
+ t_float *t2 = (float *)(w[5]);
+ t_float *order = (float *)(w[6]);
+ t_float *outx = (float *)(w[7]);
+ t_float *outy = (float *)(w[8]);
+ t_float *outz = (float *)(w[9]);
+ t_scrollgrid1Dctl *ctl = (t_scrollgrid1Dctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+
+ t_int i;
+ t_float inv_sr = 1.0f /sys_getsr();
+ t_float state[3] = {ctl->c_x, ctl->c_y, ctl->c_z};
+ t_float c,f;
+ t_float pole[2], r1, r2;
+ t_int o;
+ t_float x,y,z;
+
+
+ for (i=0; i<n; i++){
+
+ /* get params */
+ r1 = exp(1000.0f * inv_sr / (0.01f + fabs(*t1++)));
+ r2 = exp(-1000.0f * inv_sr / (0.01f + fabs(*t2++)));
+ f = *freq++;
+ o = (int)(*order++);
+ if (o < 2) o = 2;
+ pole[0] = r1 * cos(2.0f * M_PI * inv_sr * f);
+ pole[1] = r1 * sin(2.0f * M_PI * inv_sr * f);
+
+ /* debug */
+ //post("%f", r1);
+
+ /* base transform + clipping to prevent blowup */
+ x = _sat(0.5f * (state[0] - state[2]), (float)o); /* projection onto axis containing fixed */
+ y = _sat(0.5f * state[1], 1.0f); /* the "pure" oscillation axis */
+ z = _sat(0.5f * (state[0] + state[2]), 1.0f); /* orthogonal complement of x */
+
+ /* output */
+ *outx++ = x;
+ *outy++ = y;
+ *outz++ = z;
+
+
+ /* calculate fixed point location (c, 0, -c) */
+ c = _fixedpoint(x, o);
+
+ /* inverse base transform */
+ state[0] = x + z;
+ state[1] = 2.0f * y;
+ state[2] = -x + z;
+
+
+ /* update transformed linear system around unstable fixed point */
+ state[0] -= c;
+ state[2] += c;
+ vcmul2(state, pole);
+ state[2] *= r2;
+ state[0] += c;
+ state[2] -= c;
+
+ }
+
+
+
+ ctl->c_x = state[0];
+ ctl->c_y = state[1];
+ ctl->c_z = state[2];
+
+ return (w+10);
+}
+
+static void scrollgrid1D_dsp(t_scrollgrid1D *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ int k;
+
+
+ dsp_add(scrollgrid1D_perform,
+ 9,
+ &x->x_ctl,
+ sp[0]->s_n,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec,
+ sp[3]->s_vec,
+ sp[4]->s_vec,
+ sp[5]->s_vec,
+ sp[6]->s_vec);
+
+
+}
+static void scrollgrid1D_free(t_scrollgrid1D *x)
+{
+
+
+}
+
+
+
+
+static void scrollgrid1D_reset(t_scrollgrid1D *x)
+{
+ x->x_ctl.c_x = 1;
+ x->x_ctl.c_y = 1;
+ x->x_ctl.c_z = 1;
+}
+
+
+t_class *scrollgrid1D_class;
+
+static void *scrollgrid1D_new(t_floatarg algotype)
+{
+ t_scrollgrid1D *x = (t_scrollgrid1D *)pd_new(scrollgrid1D_class);
+
+ /* ins */
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+
+ /* outs */
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+
+
+ /* init data */
+ scrollgrid1D_reset(x);
+
+ return (void *)x;
+}
+
+void scrollgrid1D_tilde_setup(void)
+{
+ //post("scrollgrid1D~ v0.1");
+ scrollgrid1D_class = class_new(gensym("scrollgrid1D~"), (t_newmethod)scrollgrid1D_new,
+ (t_method)scrollgrid1D_free, sizeof(t_scrollgrid1D), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(scrollgrid1D_class, t_scrollgrid1D, x_f);
+ class_addmethod(scrollgrid1D_class, (t_method)scrollgrid1D_dsp, gensym("dsp"), 0);
+ class_addmethod(scrollgrid1D_class, (t_method)scrollgrid1D_reset, gensym("reset"), 0);
+
+
+}
+
diff --git a/modules/statwav.c b/modules/statwav.c
index 52c6a0b..13d9c9f 100644
--- a/modules/statwav.c
+++ b/modules/statwav.c
@@ -67,11 +67,15 @@ static t_int *statwav_tilde_perform(t_int *w)
{
float phase = *in++;
float modphase = phase - (int)phase;
- float findex = modphase * maxindex;
- int index = findex;
+ float findex;
+ int index;
int ia, ib, ic, id;
float frac, a, b, c, d, cminusb;
static int count;
+
+ if (modphase < 0.0f) modphase += 1.0f;
+ findex = modphase * maxindex;
+ index = findex;
frac = findex - index;