aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.config5
-rw-r--r--doc/fdn~.pd61
-rw-r--r--doc/junction~.pd56
-rw-r--r--doc/reference.txt2
-rw-r--r--include/extlib_util.h3
-rw-r--r--modules/Makefile3
-rw-r--r--modules/abs.c23
-rw-r--r--modules/bdiag.c7
-rw-r--r--modules/diag.c14
-rw-r--r--modules/dist.c14
-rw-r--r--modules/ead.c2
-rw-r--r--modules/eadsr.c2
-rw-r--r--modules/ear.c2
-rw-r--r--modules/fdn.c497
-rw-r--r--modules/junction.c207
-rw-r--r--system/setup.c10
16 files changed, 871 insertions, 37 deletions
diff --git a/Makefile.config b/Makefile.config
index 5dee604..a57eeb5 100644
--- a/Makefile.config
+++ b/Makefile.config
@@ -1,8 +1,9 @@
PD_DIR = /home/tom/pd/distro/pd/src
CREB_DIR = /home/tom/pd/extlib
-CREB_VERSION = 0.6
+CREB_VERSION = 0.7
-DEFS = -DPD -DCREB_VERSION=\"$(CREB_VERSION)\"
+DEFS = -DPD -DCREB_VERSION=\"$(CREB_VERSION)\"
+#-DHAVE_ABS_TILDE
LINUXCFLAGS = $(DEFS) -O2 -funroll-loops -fomit-frame-pointer \
-Wall -W -Wstrict-prototypes -Werror \
diff --git a/doc/fdn~.pd b/doc/fdn~.pd
new file mode 100644
index 0000000..32bee94
--- /dev/null
+++ b/doc/fdn~.pd
@@ -0,0 +1,61 @@
+#N canvas 310 312 826 610 10;
+#X obj 146 529 vols~;
+#X floatatom 203 509 5 0 0;
+#X obj 143 562 dac~;
+#X obj 128 131 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 10 415 print;
+#X floatatom 216 431 5 0 0;
+#X floatatom 267 432 5 0 0;
+#X obj 54 144 noise~;
+#X obj 94 190 *~;
+#X floatatom 203 111 5 0 0;
+#X obj 146 157 ead~;
+#X msg 360 119 lines 501 752 5003 7504 105 206 307 408;
+#X floatatom 152 110 5 0 0;
+#X msg 361 248 linear 32 100 105;
+#X msg 360 271 linear 32 1000 1005;
+#X msg 12 465 reset;
+#X obj 142 463 fdn~ 64 40000;
+#X msg 358 351 exponential 64 10 1000;
+#X msg 358 327 exponential 32 10 5000;
+#X msg 360 292 linear 32 100 2015;
+#X msg 361 224 linear 8 75 100;
+#X msg 361 201 linear 32 50 2175;
+#X msg 360 374 exponential 8 50 175;
+#X text 186 20 fdn~ a feedback delay network;
+#X text 316 468 creation arguments: <max nb delaylines> <total delay
+memory in ms>;
+#X text 3 396 print delay lengths;
+#X text 2 448 reset state;
+#X text 316 512 nb delay lines is always a multiple of 4;
+#X text 358 96 specify delay line lengths manually;
+#X text 359 152 specify a linear/exponential delay length range;
+#X text 361 170 <type> <nb lines> <min length> <max length>;
+#X text 359 430 inlets: low/high frequency reverb time (60dB time)
+;
+#X connect 0 0 2 0;
+#X connect 0 1 2 1;
+#X connect 1 0 0 2;
+#X connect 3 0 10 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 1;
+#X connect 6 0 16 2;
+#X connect 7 0 8 0;
+#X connect 8 0 16 0;
+#X connect 9 0 10 2;
+#X connect 10 0 8 1;
+#X connect 10 0 16 0;
+#X connect 11 0 16 0;
+#X connect 12 0 10 1;
+#X connect 13 0 16 0;
+#X connect 14 0 16 0;
+#X connect 15 0 16 0;
+#X connect 16 0 0 0;
+#X connect 16 1 0 1;
+#X connect 17 0 16 0;
+#X connect 18 0 16 0;
+#X connect 19 0 16 0;
+#X connect 20 0 16 0;
+#X connect 21 0 16 0;
+#X connect 22 0 16 0;
diff --git a/doc/junction~.pd b/doc/junction~.pd
new file mode 100644
index 0000000..591e4bc
--- /dev/null
+++ b/doc/junction~.pd
@@ -0,0 +1,56 @@
+#N canvas 420 323 450 300 10;
+#X obj 181 138 junction~ 4;
+#X obj 253 167 delwrite~ del1 1000;
+#X obj 123 51 vd~ del1;
+#X obj 183 51 vd~ del2;
+#X obj 244 51 vd~ del3;
+#X obj 304 51 vd~ del4;
+#X obj 123 30 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 10
+-262144 -1 -1 115 256;
+#X obj 183 30 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 10
+-262144 -1 -1 87 256;
+#X obj 245 31 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 10
+-262144 -1 -1 270 256;
+#X obj 305 31 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 10
+-262144 -1 -1 144 256;
+#X obj 63 262 dac~;
+#X obj 13 121 ead~;
+#X obj 30 97 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 10
+-262144 -1 -1 37 256;
+#X obj 90 97 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 10
+-262144 -1 -1 77 256;
+#X obj 4 97 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 229 189 delwrite~ del2 1000;
+#X obj 205 210 delwrite~ del3 1000;
+#X obj 181 232 delwrite~ del4 1000;
+#X msg 313 111 random \$1;
+#X obj 314 85 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 10
+-262144 -1 -1 74 256;
+#X text 61 5 junction~: a circular lossless signal junction;
+#X obj 58 238 vols~;
+#X obj 105 221 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 32
+10 -262144 -1 -1 77 256;
+#X connect 0 0 17 0;
+#X connect 0 0 21 0;
+#X connect 0 1 16 0;
+#X connect 0 1 21 1;
+#X connect 0 2 15 0;
+#X connect 0 3 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 1;
+#X connect 4 0 0 2;
+#X connect 5 0 0 3;
+#X connect 6 0 2 0;
+#X connect 7 0 3 0;
+#X connect 8 0 4 0;
+#X connect 9 0 5 0;
+#X connect 11 0 0 0;
+#X connect 12 0 11 1;
+#X connect 13 0 11 2;
+#X connect 14 0 11 0;
+#X connect 18 0 0 0;
+#X connect 19 0 18 0;
+#X connect 21 0 10 0;
+#X connect 21 1 10 1;
+#X connect 22 0 21 2;
diff --git a/doc/reference.txt b/doc/reference.txt
index 6485266..b167b72 100644
--- a/doc/reference.txt
+++ b/doc/reference.txt
@@ -36,6 +36,8 @@ dynwav~ dynamic wavetable: use a signal block as wavetable
ead~ exp. attack decay
eadsr~ exp. attack decay sustain release
ear~ exp. attack release
+fdn~ a feedback delay network
+junction~ a circulant lossless signal junction
lattice~ lattice filter
matrix~ multiply a signal block with an arbitrary matrix
permut~ random permute a signal block
diff --git a/include/extlib_util.h b/include/extlib_util.h
index 259d944..6e4d94b 100644
--- a/include/extlib_util.h
+++ b/include/extlib_util.h
@@ -29,3 +29,6 @@
/* convert milliseconds to 1-p, with p a real pole */
float milliseconds_2_one_minus_realpole(float time);
+
+/* check if floating point number is denormal */
+#define IS_DENORMAL(f) (((*(unsigned int *)&(f))&0x7f800000) == 0)
diff --git a/modules/Makefile b/modules/Makefile
index 4e1cabd..17a4893 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -2,7 +2,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
+ diag.o matrix.o permut.o lattice.o ratio.o ffpoly.o fwarp.o \
+ junction.o fdn.o
clean:
diff --git a/modules/abs.c b/modules/abs.c
index 4d8b8eb..0cb3d4d 100644
--- a/modules/abs.c
+++ b/modules/abs.c
@@ -1,21 +1,6 @@
-/*
- * abs.c - computes absolute value of a signal
- * 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.
- */
+
+// since this is present in a lot of libs, it is conditionally compiled
+#ifdef HAVE_ABS_TILDE
#include "m_pd.h"
#include <math.h>
@@ -62,3 +47,5 @@ void abs_tilde_setup(void)
class_addmethod(abs_class, (t_method)nullfn, &s_signal, A_NULL);
class_addmethod(abs_class, (t_method)abs_dsp, gensym("dsp"), A_NULL);
}
+
+#endif
diff --git a/modules/bdiag.c b/modules/bdiag.c
index 37a0349..be2b8c4 100644
--- a/modules/bdiag.c
+++ b/modules/bdiag.c
@@ -22,9 +22,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
-#include "m_pd.h"
-#include <math.h>
+#include "extlib_util.h"
#include <stdio.h>
#include <stdlib.h>
@@ -170,6 +168,9 @@ static t_int *bdiag_perform(t_int *w)
s1new = (a * s1) - (b * s2) + u1; /* update state */
s2new = (a * s2) + (b * s1) + u2;
+ s1new = IS_DENORMAL(s1new) ? 0 : s1new; /* clear denormals */
+ s2new = IS_DENORMAL(s2new) ? 0 : s2new;
+
*state++ = s1new; /* store state */
*state++ = s2new;
diff --git a/modules/diag.c b/modules/diag.c
index 5f7fe36..1e6bd96 100644
--- a/modules/diag.c
+++ b/modules/diag.c
@@ -22,8 +22,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "m_pd.h"
-#include <math.h>
+#include "extlib_util.h"
#include <stdio.h>
#include <stdlib.h>
@@ -113,17 +112,16 @@ static t_int *diag_perform(t_int *w)
t_float *eigen = ctl->c_eigen;
t_float *state = ctl->c_state;
t_int n = (t_int)(w[2]);
-
- t_float x;
+ t_float newstate;
int i;
for (i=0; i<n; i++)
{
- x = *in;
- *state += x;
- *state *= *eigen;
- *out = *state;
+ newstate = (*state + *in) * (*eigen);
+ newstate = IS_DENORMAL(newstate) ? 0 : newstate;
+ *state = newstate;
+ *out = newstate;
in++;
out++;
diff --git a/modules/dist.c b/modules/dist.c
index 578e2ef..20fb221 100644
--- a/modules/dist.c
+++ b/modules/dist.c
@@ -31,7 +31,7 @@
#define PULSE 8
#define NEWTON1 9
#define UPPERCLIP 10
-
+#define COMPARATOR 11
@@ -213,6 +213,18 @@ static t_int *dist_perform(t_int *w)
}
break;
+ case COMPARATOR:
+ for (i = 0; i < n; i++)
+ {
+ x = *in++ * gain;
+
+ x = (x > 0.0f) ? 1.0f : -1.0f;
+
+ *out++ = x;
+
+ }
+ break;
+
default:
for (i = 0; i < n; i++) *out++ = *in++;
diff --git a/modules/ead.c b/modules/ead.c
index 8b93faa..4d301b8 100644
--- a/modules/ead.c
+++ b/modules/ead.c
@@ -96,7 +96,7 @@ static t_int *ead_perform(t_int *w)
state -= decay*state;
}
- ctl->c_state = state;
+ ctl->c_state = IS_DENORMAL(state) ? 0 : state;
return (w+4); /* pd quirk: pointer for sequencer */
}
diff --git a/modules/eadsr.c b/modules/eadsr.c
index 0e0b9db..bba96cd 100644
--- a/modules/eadsr.c
+++ b/modules/eadsr.c
@@ -115,7 +115,7 @@ static t_int *eadsr_perform(t_int *w)
state -= decay*(state-sustain);
}
- ctl->c_state = state;
+ ctl->c_state = IS_DENORMAL(state) ? 0 : state;
return (w+4);
}
diff --git a/modules/ear.c b/modules/ear.c
index efe9b3f..d842065 100644
--- a/modules/ear.c
+++ b/modules/ear.c
@@ -81,7 +81,7 @@ static t_int *ear_perform(t_int *w)
state -= release*state;
}
- ctl->c_state = state;
+ ctl->c_state = IS_DENORMAL(state) ? 0 : state;
return (w+4);
}
diff --git a/modules/fdn.c b/modules/fdn.c
new file mode 100644
index 0000000..7842508
--- /dev/null
+++ b/modules/fdn.c
@@ -0,0 +1,497 @@
+/*
+ * fdn.c - a feedback delay network (reverb tail)
+ * using a housholder reflection feedback matrix (In - 2/n 11T)
+ * 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.
+ */
+
+/* TODO: CLEAN UP THIS MESS
+
+add delay time generation code
+add prime calculation routine (for prime delay line lengths)
+add more diffuse feedback matrix (hadamard)
+check filtering code
+
+*/
+
+#include "extlib_util.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+#define FDN_MIN_DECAY_TIME .01f
+
+/*
+
+#define NBPRIMES
+int prime[NBPRIMES];
+
+static int isprime(int n)
+{
+ int i=1;
+ int d,m,p;
+ while(1){
+ p = prime[i++];
+ m = n % p;
+ if (m == 0) return 0; // it is a prime
+ d = n / p;
+ if (d < p) return 1; // it is not a prime
+ }
+}
+
+static int initprimes(void)
+{
+ int i, curprime;
+ prime[0] = 1;
+ prime[1] = 2;
+ curprime = 3;
+
+ for(i=2; i<NBPRIMES; i++){
+ while (!isprime(curprime)) curprime++;
+ prime[i] = curprime;
+ //printf("%d, ", curprime);
+ curprime++;
+ }
+ printf("\n");
+ return 0;
+}
+*/
+
+
+//static int find_nearest_prime(int n){ return n;}
+
+typedef struct fdnctl
+{
+ t_int c_order; /* veelvoud van 4 */
+ t_int c_maxorder;
+ t_float c_leak;
+ t_float c_input;
+ t_float c_output;
+ t_float *c_buf;
+ t_float *c_gain_in;
+ t_float *c_gain_state;
+ t_float c_timehigh;
+ t_float c_timelow;
+ t_int *c_tap; /* cirular feed: N+1 pointers: 1 read, (N-1)r/w, 1 write */
+ t_float *c_length; /* delay lengths in ms */
+ t_int c_bufsize;
+ t_float c_fsample;
+ t_float *c_vector[2];
+ t_float *c_vectorbuffer;
+ t_int c_curvector;
+} t_fdnctl;
+
+typedef struct fdn
+{
+ t_object x_obj;
+ t_float x_f;
+ t_fdnctl x_ctl;
+} t_fdn;
+
+
+static void fdn_order(t_fdn *x, t_int order){
+ if (order > x->x_ctl.c_maxorder) {
+ post("fdn: this should not happen (panic!) order %d is larger than maxorder %d:",
+ order, x->x_ctl.c_maxorder );
+ exit(1);
+ }
+ x->x_ctl.c_order = order;
+ x->x_ctl.c_leak = -2./ order;
+ x->x_ctl.c_input = 1./ sqrt(order); //????????????????
+
+}
+
+static void fdn_print(t_fdn *x)
+{
+ int i;
+ fprintf(stderr, "fdn: delay coefficients (ms)\n");
+ for (i=0;i<x->x_ctl.c_order;i++) {
+ fprintf(stderr, "%f ", x->x_ctl.c_length[i]);
+ }
+ fprintf(stderr, "\n");
+
+}
+
+
+static void fdn_reset(t_fdn *x)
+{
+ int i;
+ if (x->x_ctl.c_buf) memset(x->x_ctl.c_buf, 0, x->x_ctl.c_bufsize * sizeof(float));
+ if (x->x_ctl.c_vectorbuffer) memset(x->x_ctl.c_vectorbuffer, 0, x->x_ctl.c_maxorder * 2 * sizeof(float));
+}
+
+
+
+
+static t_int *fdn_perform(t_int *w)
+{
+
+
+ t_float *in = (float *)(w[3]);
+ t_float *outr = (float *)(w[4]);
+ t_float *outl = (float *)(w[5]);
+ t_fdnctl *ctl = (t_fdnctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_float input = ctl->c_input;
+ t_float output = ctl->c_output;
+ t_float *gain_in = ctl->c_gain_in;
+ t_float *gain_state = ctl->c_gain_state;
+ t_int order = ctl->c_order;
+ t_int *tap = ctl->c_tap;
+ t_float *buf = ctl->c_buf;
+ t_int mask = ctl->c_bufsize - 1;
+
+ t_int i,j;
+ t_float x,y,v,left,right,z;
+ t_float filt_in, filt_last;
+
+ t_float *cvec, *lvec;
+
+ t_float save;
+
+
+ for(i=0;i<n;i++){
+
+ x = *in++;
+ y = 0;
+ left = 0;
+ right = 0;
+
+ /* get temporary vector buffers */
+ cvec = ctl->c_vector[ctl->c_curvector];
+ lvec = ctl->c_vector[ctl->c_curvector ^ 1];
+ ctl->c_curvector ^= 1;
+
+
+ /* read input vector + get sum and left/right output*/
+ for(j=0;j<order;)
+ {
+ z = buf[tap[j]];
+ cvec[j] = z;
+ y += z;
+ left += z;
+ right += z;
+ j++;
+
+ z = buf[tap[j]];
+ cvec[j] = z;
+ y += z;
+ left -= z;
+ right += z;
+ j++;
+
+ z = buf[tap[j]];
+ cvec[j] = z;
+ y += z;
+ left += z;
+ right -= z;
+ j++;
+
+ z = buf[tap[j]];
+ cvec[j] = z;
+ y += z;
+ left -= z;
+ right -= z;
+ j++;
+ }
+
+
+ /* write output */
+ *outl++ = left;
+ *outr++ = right;
+
+ /* y == leak to all inputs */
+ y *= ctl->c_leak;
+
+
+
+ /* perform feedback */
+ /* todo: decouple feedback & permutation */
+ save = cvec[0];
+ for (j=0; j<order-1; j++){
+ cvec[j] = cvec[j+1] + y + x;
+ }
+ cvec[order-1] = save + y + x;
+
+
+
+ /* apply gain + store result vector in delay lines + increment taps*/
+ tap[0] = (tap[0]+1)&mask;
+ for(j=0;j<order;j++) {
+ save = gain_in[j] * cvec[j] + gain_state[j] * lvec[j];
+ save = IS_DENORMAL(save) ? 0 : save;
+ cvec[j] = save;
+ buf[tap[j+1]] = save;
+ tap[j+1] = (tap[j+1] + 1) & mask;
+ }
+ }
+
+
+ return (w+6);
+}
+
+static void fdn_dsp(t_fdn *x, t_signal **sp)
+{
+
+ x->x_ctl.c_fsample = sp[0]->s_sr;
+ dsp_add(fdn_perform,
+ 5,
+ &x->x_ctl,
+ sp[0]->s_n,
+ sp[0]->s_vec,
+ sp[1]->s_vec,
+ sp[2]->s_vec);
+
+
+}
+static void fdn_free(t_fdn *x)
+{
+ if ( x->x_ctl.c_tap) free( x->x_ctl.c_tap);
+ if ( x->x_ctl.c_length) free( x->x_ctl.c_length);
+ if ( x->x_ctl.c_gain_in) free( x->x_ctl.c_gain_in);
+ if ( x->x_ctl.c_gain_state) free( x->x_ctl.c_gain_state);
+ if ( x->x_ctl.c_buf) free ( x->x_ctl.c_buf);
+ if ( x->x_ctl.c_vectorbuffer) free ( x->x_ctl.c_vectorbuffer );
+}
+
+
+/*
+
+each delay line is filtered with a first order iir filter:
+(gl: dc gain, gh: ny gain)
+
+H(z) = 2 gl gh / (gl + gh - z^-1 (gl - gh))
+
+this results in the difference equation
+
+yk = (2 gl gh ) / (gl + gh) x + (gl - gh) / (gl + gh) yk-1
+
+*/
+
+
+static void fdn_time(t_fdn *x, t_float timelow, t_float timehigh){
+ t_float elow, ehigh;
+ t_int i;
+ t_float gainlow, gainhigh, gainscale;
+
+ if (timelow < FDN_MIN_DECAY_TIME) timelow = FDN_MIN_DECAY_TIME;
+ if (timehigh < FDN_MIN_DECAY_TIME) timehigh = FDN_MIN_DECAY_TIME;
+
+ elow = -.003 / (timelow);
+ ehigh = -.003 / (timehigh);
+
+ /* setup gains */
+ for(i=0;i<x->x_ctl.c_order;i++){
+ gainlow = pow(10, elow * (x->x_ctl.c_length[i]));
+ gainhigh = pow(10, ehigh * (x->x_ctl.c_length[i]));
+ gainscale = 1.0f / (gainlow + gainhigh);
+ x->x_ctl.c_gain_in[i] = 2.0f * gainlow * gainhigh * gainscale;
+ x->x_ctl.c_gain_state[i] = (gainlow - gainhigh) * gainscale;
+ }
+ x->x_ctl.c_timehigh = timehigh;
+ x->x_ctl.c_timelow = timelow;
+}
+
+static void fdn_updatedamping(t_fdn *x)
+{
+ fdn_time(x, x->x_ctl.c_timelow, x->x_ctl.c_timehigh);
+}
+
+static void fdn_timelow(t_fdn *x, t_float f){
+ x->x_ctl.c_timelow = f;
+ fdn_updatedamping(x);
+}
+static void fdn_timehigh(t_fdn *x, t_float f){
+ x->x_ctl.c_timehigh = f;
+ fdn_updatedamping(x);
+}
+
+
+static void fdn_setupdelayline(t_fdn *x){
+ int sum, t, n;
+ int mask = x->x_ctl.c_bufsize - 1;
+ int start = x->x_ctl.c_tap[0];
+ int *tap = x->x_ctl.c_tap;
+ float *length = x->x_ctl.c_length;
+ float scale = sys_getsr() * .001f;
+
+ sum = 0;
+ tap[0] = (start & mask);
+ for (t=1; t<= x->x_ctl.c_order; t++){
+ sum += (int)(length[t-1] * scale);
+ tap[t]=(start+sum)&mask;
+ }
+
+ if (sum > mask){
+ post("fdn: warning: not enough delay memory, behaviour is undefined (this could lead to instability...)");
+ }
+
+
+}
+
+static void fdn_list (t_fdn *x, t_symbol *s, int argc, t_atom *argv){
+ int i;
+ float l;
+ int sum=0;
+
+ int order = argc & 0xfffffffc;
+
+ if (order < 4) return;
+ if (order > x->x_ctl.c_maxorder) return;
+
+
+ fdn_order(x, order);
+ for(i=0; i<order; i++)
+ if (argv[i].a_type == A_FLOAT) x->x_ctl.c_length[i] = argv[i].a_w.w_float;
+
+ fdn_setupdelayline(x);
+ fdn_updatedamping(x);
+}
+
+static void fdn_linear(t_fdn *x, t_float forder, t_float min, t_float max)
+{
+ t_int order = ((int)forder) & 0xfffffffc;
+ t_float length, inc;
+ t_int i;
+
+ if (order < 4) return;
+ if (order > x->x_ctl.c_maxorder) return;
+ if (min <= 0) return;
+ if (max <= 0) return;
+
+ inc = (max - min) / (float)(order - 1);
+ length = min;
+
+ for (i=0; i<order; i++){
+ x->x_ctl.c_length[i] = length;
+ length += inc;
+ }
+
+ fdn_order(x, order);
+ fdn_setupdelayline(x);
+ fdn_updatedamping(x);
+}
+
+
+
+static void fdn_exponential(t_fdn *x, t_float forder, t_float min, t_float max)
+{
+ t_int order = ((int)forder) & 0xfffffffc;
+ t_float length, inc;
+ t_int i;
+
+ if (order < 4) return;
+ if (order > x->x_ctl.c_maxorder) return;
+ if (min <= 0) return;
+ if (max <= 0) return;
+
+ inc = pow (max / min, 1.0f / ((float)(order - 1)));
+ length = min;
+
+ for (i=0; i<order; i++){
+ x->x_ctl.c_length[i] = length;
+ length *= inc;
+ }
+
+ fdn_order(x, order);
+ fdn_setupdelayline(x);
+ fdn_updatedamping(x);
+}
+
+
+
+
+
+t_class *fdn_class;
+
+static void *fdn_new(t_floatarg maxiorder, t_floatarg maxibufsize)
+{
+ t_int order = maxiorder;
+ t_int bufround;
+ t_fdn *x = (t_fdn *)pd_new(fdn_class);
+ t_float scale = sys_getsr() * .001f;
+ t_int bufsize = (t_int)(scale * maxibufsize);
+
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("timelow"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("timehigh"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+
+ /* init data */
+ if (order < 4) order = 8;
+ if (bufsize < 64) bufsize = 65536;
+
+ bufround = 1;
+ while (bufround < bufsize) bufround *= 2;
+ bufsize = bufround;
+
+
+ post("fdn: maximum nb of delay lines %d, total buffer size %d samples (%f seconds)",
+ order, bufsize, ((float)bufsize) / sys_getsr());
+
+
+ x->x_ctl.c_maxorder = order;
+ x->x_ctl.c_buf = (float *)malloc(sizeof(float) * bufsize);
+ x->x_ctl.c_bufsize = bufsize;
+ x->x_ctl.c_fsample = sys_getsr();
+ x->x_ctl.c_tap = (t_int *)malloc((order + 1) * sizeof(t_int));
+ x->x_ctl.c_length = (t_float *)malloc(order * sizeof(t_int));
+ x->x_ctl.c_gain_in = (t_float *)malloc(order * sizeof(t_float));
+ x->x_ctl.c_gain_state = (t_float *)malloc(order * sizeof(t_float));
+ x->x_ctl.c_vectorbuffer = (t_float *)malloc(order * 2 * sizeof(float));
+ memset(x->x_ctl.c_vectorbuffer, 0, order * 2 * sizeof(float));
+ x->x_ctl.c_curvector = 0;
+ x->x_ctl.c_vector[0] = &x->x_ctl.c_vectorbuffer[0];
+ x->x_ctl.c_vector[1] = &x->x_ctl.c_vectorbuffer[order];
+
+ /* preset */
+ fdn_order(x,8);
+ x->x_ctl.c_length[0]= 29.0f;
+ x->x_ctl.c_length[1]= 31.0f;
+ x->x_ctl.c_length[2]= 37.0f;
+ x->x_ctl.c_length[3]= 67.0f;
+ x->x_ctl.c_length[4]= 82.0f;
+ x->x_ctl.c_length[5]= 110.0f;
+ x->x_ctl.c_length[6]= 172.0f;
+ x->x_ctl.c_length[7]= 211.0f;
+ fdn_setupdelayline(x);
+ fdn_time(x, 4, 1);
+
+ /* reset delay memory to zero */
+ fdn_reset(x);
+
+
+ return (void *)x;
+}
+
+
+void fdn_tilde_setup(void)
+{
+ //post("fdn~ v0.1");
+ fdn_class = class_new(gensym("fdn~"), (t_newmethod)fdn_new,
+ (t_method)fdn_free, sizeof(t_fdn), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(fdn_class, t_fdn, x_f);
+ class_addmethod(fdn_class, (t_method)fdn_print, gensym("print"), 0);
+ class_addmethod(fdn_class, (t_method)fdn_reset, gensym("reset"), 0);
+ class_addmethod(fdn_class, (t_method)fdn_timehigh, gensym("timehigh"), A_DEFFLOAT, 0);
+ class_addmethod(fdn_class, (t_method)fdn_timelow, gensym("timelow"), A_DEFFLOAT, 0);
+ class_addmethod(fdn_class, (t_method)fdn_list, gensym("lines"), A_GIMME, 0);
+ class_addmethod(fdn_class, (t_method)fdn_dsp, gensym("dsp"), 0);
+ class_addmethod(fdn_class, (t_method)fdn_linear, gensym("linear"), A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(fdn_class, (t_method)fdn_exponential, gensym("exponential"), A_FLOAT, A_FLOAT, A_FLOAT, 0);
+
+}
+
diff --git a/modules/junction.c b/modules/junction.c
new file mode 100644
index 0000000..71476da
--- /dev/null
+++ b/modules/junction.c
@@ -0,0 +1,207 @@
+/*
+ * junction.c - computes a lossless circulant junction
+ * 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>
+
+
+typedef struct junctionctl
+{
+ t_int c_channels;
+ t_float **c_in;
+ t_float **c_out;
+ t_float *c_buffer;
+ t_float *c_coef;
+ t_float c_norm;
+} t_junctionctl;
+
+typedef struct junction
+{
+ t_object x_obj;
+ t_float x_f;
+ t_junctionctl x_ctl;
+} t_junction;
+
+void junction_bang(t_junction *x)
+{
+ int i, n = x->x_ctl.c_channels;
+ t_float *coef = x->x_ctl.c_coef;
+ t_float r;
+
+ for (i=1; i<n/2; i++)
+ {
+ r = rand();
+ r *= ((2 * M_PI)/RAND_MAX);
+ coef[i]= cos(r);
+ coef[n-i] = sin(r);
+ }
+
+ coef[0] = (rand() & 1) ? 1 : -1;
+ coef[n/2] = (rand() & 1) ? 1 : -1;
+
+ /* mayer_realfft(n, coef); */
+
+
+}
+
+void junction_random(t_junction *x, t_floatarg f)
+{
+ srand((int)f);
+ junction_bang(x);
+}
+
+static t_int *junction_perform(t_int *w)
+{
+
+
+
+ t_junctionctl *ctl = (t_junctionctl *)(w[1]);
+ t_int n = (t_int)(w[2]);
+ t_int i,j;
+ t_float x,y;
+
+ t_int c = ctl->c_channels;
+ t_float **in = ctl->c_in;
+ t_float **out = ctl->c_out;
+ t_float *buf = ctl->c_buffer;
+ t_float *coef = ctl->c_coef;
+
+ t_float norm = ctl->c_norm;
+
+
+ for (i=0;i<n;i++)
+ {
+
+ /* read input */
+ for (j=0; j<c; j++)
+ {
+ buf[j] = in[j][i];
+ }
+
+ /* transform */
+ mayer_realfft(c, buf);
+ for (j=1; j<c/2; j++)
+ {
+ float x,y,a,b;
+ x = buf[j];
+ y = buf[c-j];
+ a = coef[j];
+ b = coef[c-j];
+ buf[j] = a * x - b * y;
+ buf[c-j] = a * y + b * x;
+ }
+ buf[0] *= coef[0];
+ buf[c/2] *= coef[c/2];
+
+
+ mayer_realifft(c, buf);
+
+
+ /* write output */
+ for (j=0; j<c; j++)
+ {
+ out[j][i] = buf[j] * norm;
+ }
+ }
+
+
+ return (w+3);
+}
+
+
+
+static void junction_dsp(t_junction *x, t_signal **sp)
+{
+ int i, c = x->x_ctl.c_channels;
+ float norm;
+
+ for (i=0;i<c;i++)
+ {
+ x->x_ctl.c_in[i] = sp[i]->s_vec;
+ x->x_ctl.c_out[i] = sp[i+c]->s_vec;
+ }
+
+ norm = c;
+ norm = 1. / (norm);
+ x->x_ctl.c_norm = norm;
+
+
+ dsp_add(junction_perform, 2, &x->x_ctl, sp[0]->s_n);
+
+ /* dsp_add(junction_perform, 4, &x->x_ctl, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);*/
+
+}
+
+
+void junction_free(t_junction *x)
+{
+
+ if (x->x_ctl.c_in) free (x->x_ctl.c_in);
+ if (x->x_ctl.c_out) free (x->x_ctl.c_out);
+ if (x->x_ctl.c_buffer) free (x->x_ctl.c_buffer);
+ if (x->x_ctl.c_coef) free (x->x_ctl.c_coef);
+
+}
+
+t_class *junction_class;
+
+void *junction_new(t_floatarg channels)
+{
+
+ int l = ilog2(channels);
+ int i,n;
+
+ t_junction *x = (t_junction *)pd_new(junction_class);
+
+
+ if (l<2) l = 2;
+ if (l>4) l = 4;
+
+ n=1;
+ while (l--) n *= 2;
+
+ for (i=1;i<n;i++) inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal"));
+ for (i=0;i<n;i++) outlet_new(&x->x_obj, gensym("signal"));
+
+ x->x_ctl.c_in = (float **)malloc(n*sizeof(float *));
+ x->x_ctl.c_out = (float **)malloc(n*sizeof(float *));
+ x->x_ctl.c_buffer = (float *)malloc(n*sizeof(float));
+ x->x_ctl.c_coef = (float *)malloc(n*sizeof(float));
+ x->x_ctl.c_channels = n;
+
+ junction_bang(x);
+
+ return (void *)x;
+}
+
+void junction_tilde_setup(void)
+{
+ //post("junction~ v0.1");
+ junction_class = class_new(gensym("junction~"), (t_newmethod)junction_new,
+ (t_method)junction_free, sizeof(t_junction), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(junction_class, t_junction, x_f);
+ class_addmethod(junction_class, (t_method)junction_bang, gensym("bang"), 0);
+ class_addmethod(junction_class, (t_method)junction_random, gensym("random"), A_FLOAT, 0);
+ class_addmethod(junction_class, (t_method)junction_dsp, gensym("dsp"), 0);
+
+}
+
diff --git a/system/setup.c b/system/setup.c
index b425f84..7274349 100644
--- a/system/setup.c
+++ b/system/setup.c
@@ -25,6 +25,8 @@ void lattice_tilde_setup(void);
void ratio_setup(void);
void ffpoly_setup(void);
void fwarp_setup(void);
+void junction_tilde_setup(void);
+void fdn_tilde_setup(void);
void creb_setup(void)
{
@@ -40,7 +42,6 @@ void creb_setup(void)
qmult_tilde_setup();
qnorm_tilde_setup();
cheby_tilde_setup();
- abs_tilde_setup();
ramp_tilde_setup();
dwt_tilde_setup();
bfft_tilde_setup();
@@ -51,6 +52,8 @@ void creb_setup(void)
matrix_tilde_setup();
permut_tilde_setup();
lattice_tilde_setup();
+ junction_tilde_setup();
+ fdn_tilde_setup();
/* setup other objects */
ratio_setup();
@@ -61,4 +64,9 @@ void creb_setup(void)
biquadseries_tilde_setup();
filterortho_tilde_setup();
+ /* optional modules */
+#ifdef HAVE_ABS_TILDE
+ abs_tilde_setup();
+#endif
+
}