diff options
Diffstat (limited to 'adaptive/src')
-rwxr-xr-x | adaptive/src/adaptive.c | 158 | ||||
-rwxr-xr-x | adaptive/src/adaptive.h | 34 | ||||
-rwxr-xr-x | adaptive/src/lms2~.c | 332 | ||||
-rwxr-xr-x | adaptive/src/lms~.c | 295 | ||||
-rwxr-xr-x | adaptive/src/makefile | 48 | ||||
-rwxr-xr-x | adaptive/src/makefile_mingw | 46 | ||||
-rwxr-xr-x | adaptive/src/makefile_msvc | 39 | ||||
-rwxr-xr-x | adaptive/src/nlms2~.c | 359 | ||||
-rwxr-xr-x | adaptive/src/nlms3~.c | 423 | ||||
-rwxr-xr-x | adaptive/src/nlms~.c | 324 |
10 files changed, 2058 insertions, 0 deletions
diff --git a/adaptive/src/adaptive.c b/adaptive/src/adaptive.c new file mode 100755 index 0000000..223bb0a --- /dev/null +++ b/adaptive/src/adaptive.c @@ -0,0 +1,158 @@ +/******************************************************
+ *
+ * Adaptive Systems for PD
+ *
+ * copyleft (c) Gerda Strobl, Georg Holzmann
+ * 2005
+ *
+ * for complaints, suggestions: grh@mur.at
+ *
+ ******************************************************
+ *
+ * license: GNU General Public License v.2
+ *
+ ******************************************************/
+
+#include "adaptive.h"
+
+typedef struct _adaptive
+{
+ t_object x_obj;
+} t_adaptive;
+
+t_class *adaptive_class;
+
+static void adaptive_help(void)
+{
+ post("\n-----------------------------------------------");
+ post("adaptive systems for PD");
+ post("copyleft (c) Gerda Strobl, Georg Holzmann, 2005");
+ post("");
+ post("for more info look at the help patches!");
+ post("-----------------------------------------------\n");
+}
+
+void *adaptive_new(void)
+{
+ t_adaptive *x = (t_adaptive *)pd_new(adaptive_class);
+ return (void *)x;
+}
+
+//-----------------------------------------------------
+// declaration of the setup functions:
+void lms_tilde_setup();
+void lms2_tilde_setup();
+void nlms_tilde_setup();
+void nlms2_tilde_setup();
+void nlms3_tilde_setup();
+//-end-of-declaration----------------------------------
+
+void adaptive_setup(void)
+{
+ //---------------------------------------------------
+ // call all the setup functions:
+ lms_tilde_setup();
+ lms2_tilde_setup();
+ nlms_tilde_setup();
+ nlms2_tilde_setup();
+ nlms3_tilde_setup();
+ //-end-----------------------------------------------
+
+ post("\nadaptive: 2005 by Gerda Strobl and Georg Holzmann");
+
+ adaptive_class = class_new(gensym("adaptive"), adaptive_new, 0, sizeof(t_adaptive), 0, 0);
+ class_addmethod(adaptive_class, (t_method)adaptive_help, gensym("help"), 0);
+}
+
+
+/* ---------------------- helpers ----------------------- */
+
+void adaptation_write(const char *filename, t_int N, t_float mu, t_float *c)
+{
+ FILE *f=0;
+ int i;
+
+ // open file
+ f = fopen(filename, "w");
+ if(!f)
+ {
+ post("adaptive, save: error open file");
+ return;
+ }
+
+ // write little header, number of coefficients and mu
+ fprintf(f, "adaptivePD\n");
+ fprintf(f, "size: %d\n", N);
+ fprintf(f, "mu: %.30f\n", mu);
+
+ // write coefficients
+ for(i=0; i<N; i++)
+ fprintf(f, "%.30f\n", c[i]);
+
+ // close file
+ if (f) fclose(f);
+ post("adaptive, save: coefficients written to file");
+}
+
+void adaptation_read(const char *filename, t_int *N, t_float *mu,
+ t_float *c, t_float *buf)
+{
+ FILE *f=0;
+ int i, n=0;
+
+ // open file
+ f = fopen(filename, "r");
+ if(!f)
+ {
+ post("adaptive, open: error open file");
+ return;
+ }
+
+ // read header and nr of coefficients
+ if ( fscanf(f,"adaptivePD\n") != 0)
+ {
+ post("adaptive, open: error in reading file");
+ return;
+ }
+ if ( fscanf(f,"size: %d\n",&n) != 1)
+ {
+ post("adaptive, open: error in reading file");
+ return;
+ };
+
+ // change size of the filter if needed
+ if(n != *N)
+ {
+ if(c) freebytes(c, sizeof(t_float) * (*N));
+ if(buf) freebytes(buf, sizeof(t_sample) * (*N-1));
+
+ *N = (n<=0) ? 1 : n;
+
+ post("WARNING (adaptive): Nr. of coefficients is changed to %d!",*N);
+
+ // allocate mem and init coefficients
+ c = (t_float *)getbytes(sizeof(t_float) * (*N));
+
+ // allocate mem for temp buffer
+ buf = (t_sample *)getbytes(sizeof(t_sample) * (*N-1));
+ for(i=0; i<(*N-1); i++)
+ buf[i] = 0;
+ }
+
+ // read mu
+ if ( fscanf(f,"mu: %f\n",mu) != 1)
+ {
+ post("adaptive, open: error in reading file");
+ return;
+ };
+
+ // get coefficients:
+ for(i=0; i<(*N); i++)
+ if( fscanf(f, "%f\n", c+i) != 1)
+ {
+ post("adaptive, open: error in reading file");
+ return;
+ }
+ //post("c_inside: %d",c);
+ post("adaptive, read: coefficients readed from file");
+}
diff --git a/adaptive/src/adaptive.h b/adaptive/src/adaptive.h new file mode 100755 index 0000000..209a51a --- /dev/null +++ b/adaptive/src/adaptive.h @@ -0,0 +1,34 @@ +/******************************************************
+ *
+ * Adaptive Systems for PD
+ *
+ * copyleft (c) Gerda Strobl, Georg Holzmann
+ * 2005
+ *
+ * for complaints, suggestions: grh@mur.at
+ *
+ ******************************************************
+ *
+ * license: GNU General Public License v.2
+ *
+ ******************************************************/
+
+#ifndef __ADAPTIVE_H__
+#define __ADAPTIVE_H__
+
+#include "m_pd.h"
+#include <stdio.h>
+
+
+
+/* ---------------------- helpers ----------------------- */
+
+// save all data to file
+void adaptation_write(const char *filename, t_int N, t_float mu, t_float *c);
+
+// read data from file
+void adaptation_read(const char *filename, t_int *N, t_float *mu,
+ t_float *c, t_float *buf);
+
+
+#endif //__ADAPTIVE_H__
diff --git a/adaptive/src/lms2~.c b/adaptive/src/lms2~.c new file mode 100755 index 0000000..c3c3d3c --- /dev/null +++ b/adaptive/src/lms2~.c @@ -0,0 +1,332 @@ +/****************************************************** + * + * Adaptive Systems for PD + * + * copyleft (c) Gerda Strobl, Georg Holzmann + * 2005 + * + * for complaints, suggestions: grh@mur.at + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + +#include "adaptive.h" + + +/* ------------------------ lms2~ ------------------------- */ + +static t_class *lms2_tilde_class; + +typedef struct _lms2 +{ + t_object x_obj; + t_float f; + t_atom *coef; + t_sample *buf; + t_sample *y_tmp; + t_sample *e_tmp; + t_int bufsize; + t_outlet *c_out; + int adapt; // enable/disable adaptation + + t_int N; //number of coefficients of the adaptive system + t_float *c; // coefficients of the system + t_float mu; // step-size parameter (learning rate) + + t_canvas *x_canvas; +} t_lms2_tilde; + +static void lms2_tilde_a(t_lms2_tilde *x, t_floatarg f) +{ + x->adapt = (f==0) ? 0 : 1; +} + +static void lms2_tilde_geta(t_lms2_tilde *x) +{ + if(x->adapt==0) + post("lms2~: adaptation is currently OFF"); + else + post("lms2~: adaptation is currently ON"); +} + +static void lms2_tilde_mu(t_lms2_tilde *x, t_floatarg f) +{ + x->mu = f; +} + +static void lms2_tilde_getmu(t_lms2_tilde *x) +{ + post("mu (step-size parameter): %f", x->mu); +} + +static void lms2_tilde_getN(t_lms2_tilde *x) +{ + post("N (number of coefficients): %d", x->N); +} + +static void lms2_tilde_clear(t_lms2_tilde *x) +{ + int i; + + // clear coefficients + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffer + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void lms2_tilde_init(t_lms2_tilde *x) +{ + int i; + + // set the first coefficient to 1, all others to 0 + // so this is a delay free transmission + x->c[0] = 1; + for(i=1; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffers + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void lms2_tilde_print(t_lms2_tilde *x) +{ + int i; + + // print coefficients + post("\nNr. of coefficients: %d",x->N); + post("coefficients:"); + for(i=0; i<x->N; i++) + post("\t%d: %f",i,x->c[i]); +} + +static void lms2_tilde_write(t_lms2_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // save to file + adaptation_write(filename, x->N, x->mu, x->c); +} + +static void lms2_tilde_read(t_lms2_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + int n = x->N; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // read file + adaptation_read(filename, &x->N, &x->mu, x->c, x->buf); + + // if length changes: + if(x->N != n) + { + if(x->coef) freebytes(x->coef, sizeof(t_atom) * x->N); + x->coef = (t_atom *)getbytes(sizeof(t_atom) * x->N); + } +} + +static t_int *lms2_tilde_perform(t_int *w) +{ + t_sample *x_ = (t_sample *)(w[1]); + t_sample *d_ = (t_sample *)(w[2]); + t_sample *y_ = (t_sample *)(w[3]); + t_sample *e_ = (t_sample *)(w[4]); + int n = (int)(w[5]); + t_lms2_tilde *x = (t_lms2_tilde *)(w[6]); + int i, j, tmp; + + + for(i=0; i<n; i++) + { + // calc output (filter) + + x->y_tmp[i]=0; + + // y_[i] += x->c[j] * x_[i-j]; + // so lets split in two halfs, so that + // negative indezes get samples from the + // last audioblock (x->buf) ... + + tmp = (i+1 - x->N)*(-1); + tmp = tmp<0 ? 0 : tmp; + + for(j=0; j<x->N-tmp; j++) + x->y_tmp[i] += x->c[j] * x_[i-j]; + + for(j=x->N-tmp; j<x->N; j++) + x->y_tmp[i] += x->c[j] * x->buf[(i-j)*(-1)-1]; + + if(x->adapt) + { + // error computation + x->e_tmp[i] = d_[i] - x->y_tmp[i]; + + // coefficient adaptation + // (split in the same way as above) + + for(j=0; j<x->N-tmp; j++) + x->c[j] = x->c[j] + x->mu * x_[i-j] * x->e_tmp[i]; + + for(j=x->N-tmp; j<x->N; j++) + x->c[j] = x->c[j] + x->mu * x->buf[(i-j)*(-1)-1] * x->e_tmp[i]; + } + else x->e_tmp[i] = 0; + + //post("%d: in %f, d: %f, out: %f, e: %f, c1:%f, c2:%f", i, x_[i], d_[i], x->y_tmp[i], x->e_tmp[i], x->c[0], x->c[1]); + } + + // outlet coefficients + for(i=0; i<x->N; i++) + SETFLOAT(&x->coef[i],x->c[i]); + + outlet_list(x->c_out, &s_list, x->N, x->coef); + + // store last samples for next audiobuffer + for(i=0; i<x->N-1; i++) + x->buf[i] = x_[n-1-i]; + + // now write tmps to outlets + while(n--) + { + y_[n] = x->y_tmp[n]; + e_[n] = x->e_tmp[n]; + } + + return (w+7); +} + +static void lms2_tilde_dsp(t_lms2_tilde *x, t_signal **sp) +{ + // allocate new temp buffer if buffersize changes + if(x->bufsize != sp[0]->s_n) + { + if(sp[0]->s_n < x->N) + post("lms2~ WARNING: buffersize must be bigger than N, you will get wrong results !!!"); + + if(x->y_tmp) freebytes(x->y_tmp, sizeof(t_sample) * x->bufsize); + x->y_tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + if(x->e_tmp) freebytes(x->e_tmp, sizeof(t_sample) * x->bufsize); + x->e_tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + x->bufsize = sp[0]->s_n; + } + + dsp_add(lms2_tilde_perform, 6, sp[0]->s_vec, sp[1]->s_vec, + sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n, x); +} + +static void lms2_tilde_helper(void) +{ + post("\nlms2~: Adaptive transversal filter using LMS (for algorithm analysis)"); + post("INPUT:"); + post("\tinlet1: input signal x[n]"); + post("\tinlet2: desired output signal d[n]"); + post("\tinit_arg1: number of coefficients of the adaptive system"); + post("\tinit_arg2, mu: step-size parameter (learning rate)"); + post("OUTPUT:"); + post("\toutlet1: output signal y[n]"); + post("\toutlet2: error signal e[n]"); + post("\toutlet3: coefficients c[n] (only per block)\n"); +} + +static void *lms2_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_lms2_tilde *x = (t_lms2_tilde *)pd_new(lms2_tilde_class); + int i; + + // default values: + x->N = 8; + x->mu = 0.05; + x->adapt = 0; + x->y_tmp = NULL; + x->e_tmp = NULL; + x->bufsize = 0; + + switch(argc) + { + case 2: + x->mu = atom_getfloat(argv+1); + case 1: + x->N = atom_getint(argv); + x->N = (x->N<=0) ? 1 : x->N; + } + + // allocate mem and init coefficients + x->c = (t_float *)getbytes(sizeof(t_float) * x->N); + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // allocate mem for temp buffer + x->buf = (t_float *)getbytes(sizeof(t_float) * x->N-1); + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + + // for output atoms (coefficients): + x->coef = (t_atom *)getbytes(sizeof(t_atom) * x->N); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->c_out = outlet_new(&x->x_obj, 0); + + x->x_canvas = canvas_getcurrent(); + + + return (x); +} + +static void lms2_tilde_free(t_lms2_tilde *x) +{ + if(x->c) freebytes(x->c, sizeof(t_float) * x->N); + if(x->buf) freebytes(x->buf, sizeof(t_sample) * x->N-1); + if(x->y_tmp) freebytes(x->y_tmp, sizeof(t_sample) * x->bufsize); + if(x->e_tmp) freebytes(x->e_tmp, sizeof(t_sample) * x->bufsize); + if(x->coef) freebytes(x->coef, sizeof(t_atom) * x->N); +} + +void lms2_tilde_setup(void) +{ + lms2_tilde_class = class_new(gensym("lms2~"), (t_newmethod)lms2_tilde_new, + (t_method)lms2_tilde_free, sizeof(t_lms2_tilde), + CLASS_DEFAULT, A_GIMME, 0); + + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_a, + gensym("adaptation"), A_DEFFLOAT, 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_geta, + gensym("getadaptation"), 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_mu, + gensym("mu"), A_DEFFLOAT, 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_getmu, + gensym("getmu"), 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_getN, + gensym("getN"), 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_init, + gensym("init_unity"), 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_clear, + gensym("clear"), 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_print, + gensym("print"), 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_write, + gensym("write"), A_DEFSYMBOL, 0); + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_read, + gensym("read"), A_DEFSYMBOL, 0); + + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(lms2_tilde_class, t_lms2_tilde, f); + + class_addmethod(lms2_tilde_class, (t_method)lms2_tilde_helper, gensym("help"), 0); +} diff --git a/adaptive/src/lms~.c b/adaptive/src/lms~.c new file mode 100755 index 0000000..d39ccb7 --- /dev/null +++ b/adaptive/src/lms~.c @@ -0,0 +1,295 @@ +/****************************************************** + * + * Adaptive Systems for PD + * + * copyleft (c) Gerda Strobl, Georg Holzmann + * 2005 + * + * for complaints, suggestions: grh@mur.at + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + +#include "adaptive.h" + + +/* ------------------------ lms~ ------------------------- */ + +static t_class *lms_tilde_class; + +typedef struct _lms +{ + t_object x_obj; + t_float f; + t_sample *buf; + t_sample *tmp; + t_int bufsize; + int adapt; // enable/disable adaptation + + t_int N; //number of coefficients of the adaptive system + t_float *c; // coefficients of the system + t_float mu; // step-size parameter (learning rate) + + t_canvas *x_canvas; +} t_lms_tilde; + +static void lms_tilde_a(t_lms_tilde *x, t_floatarg f) +{ + x->adapt = (f==0) ? 0 : 1; +} + +static void lms_tilde_geta(t_lms_tilde *x) +{ + if(x->adapt==0) + post("lms~: adaptation is currently OFF"); + else + post("lms~: adaptation is currently ON"); +} + +static void lms_tilde_mu(t_lms_tilde *x, t_floatarg f) +{ + x->mu = f; +} + +static void lms_tilde_getmu(t_lms_tilde *x) +{ + post("mu (step-size parameter): %f", x->mu); +} + +static void lms_tilde_getN(t_lms_tilde *x) +{ + post("N (number of coefficients): %d", x->N); +} + +static void lms_tilde_clear(t_lms_tilde *x) +{ + int i; + + // clear coefficients + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffer + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void lms_tilde_init(t_lms_tilde *x) +{ + int i; + + // set the first coefficient to 1, all others to 0 + // so this is a delay free transmission + x->c[0] = 1; + for(i=1; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffers + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void lms_tilde_print(t_lms_tilde *x) +{ + int i; + + // print coefficients + post("\nNr. of coefficients: %d",x->N); + post("coefficients:"); + for(i=0; i<x->N; i++) + post("\t%d: %f",i,x->c[i]); +} + +static void lms_tilde_write(t_lms_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // save to file + adaptation_write(filename, x->N, x->mu, x->c); +} + +static void lms_tilde_read(t_lms_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // read file + adaptation_read(filename, &x->N, &x->mu, x->c, x->buf); +} + +static t_int *lms_tilde_perform(t_int *w) +{ + t_lms_tilde *x = (t_lms_tilde *)(w[1]); + t_sample *x_ = (t_sample *)(w[2]); + t_sample *d_ = (t_sample *)(w[3]); + t_sample *y_ = (t_sample *)(w[4]); + int n = (int)(w[5]); + int i, j, tmp; + t_sample e=0; + + + for(i=0; i<n; i++) + { + // calc output (filter) + + x->tmp[i]=0; + + // y_[i] += x->c[j] * x_[i-j]; + // so lets split in two halfs, so that + // negative indezes get samples from the + // last audioblock (x->buf) ... + tmp = (i+1 - x->N)*(-1); + tmp = tmp<0 ? 0 : tmp; + + for(j=0; j<x->N-tmp; j++) + x->tmp[i] += x->c[j] * x_[i-j]; + + for(j=x->N-tmp; j<x->N; j++) + x->tmp[i] += x->c[j] * x->buf[(i-j)*(-1)-1]; + + if(x->adapt) + { + // error computation + e = d_[i] - x->tmp[i]; + + // coefficient adaptation + // (split in the same way as above) + + for(j=0; j<x->N-tmp; j++) + x->c[j] = x->c[j] + x->mu * x_[i-j] * e; + + for(j=x->N-tmp; j<x->N; j++) + x->c[j] = x->c[j] + x->mu * x->buf[(i-j)*(-1)-1] * e; + } + + //post("%d: in %f, d: %f, out: %f, error: %f, c1:%f, c2:%f", i, x_[i], d_[i], x->tmp[i], e, x->c[0], x->c[1]); + } + + // store last samples for next audiobuffer + for(i=0; i<x->N-1; i++) + x->buf[i] = x_[n-1-i]; + + // now write tmp to outlet + while(n--) + y_[n] = x->tmp[n]; + + return (w+6); +} + +static void lms_tilde_dsp(t_lms_tilde *x, t_signal **sp) +{ + // allocate new temp buffer if buffersize changes + if(x->bufsize != sp[0]->s_n) + { + if(sp[0]->s_n < x->N) + post("lms~ WARNING: buffersize must be bigger than N, you will get wrong results !!!"); + + if(x->tmp) freebytes(x->tmp, sizeof(t_sample) * x->bufsize); + x->tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + x->bufsize = sp[0]->s_n; + } + + dsp_add(lms_tilde_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, + sp[2]->s_vec, sp[0]->s_n); +} + +static void lms_tilde_helper(void) +{ + post("\nlms~: Adaptive transversal filter using LMS"); + post("INPUT:"); + post("\tinlet1: input signal x[n]"); + post("\tinlet2: desired output signal d[n]"); + post("\tinit_arg1: number of coefficients of the adaptive system"); + post("\tinit_arg2, mu: step-size parameter (learning rate)"); + post("OUTPUT:"); + post("\toutlet1: output signal\n"); +} + +static void *lms_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_lms_tilde *x = (t_lms_tilde *)pd_new(lms_tilde_class); + int i; + + // default values: + x->N = 8; + x->mu = 0.05; + x->adapt = 0; + x->tmp = NULL; + x->bufsize = 0; + + switch(argc) + { + case 2: + x->mu = atom_getfloat(argv+1); + case 1: + x->N = atom_getint(argv); + x->N = (x->N<=0) ? 1 : x->N; + } + + // allocate mem and init coefficients + x->c = (t_float *)getbytes(sizeof(t_float) * x->N); + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // allocate mem for temp buffer + x->buf = (t_sample *)getbytes(sizeof(t_sample) * x->N-1); + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_canvas = canvas_getcurrent(); + + return (x); +} + +static void lms_tilde_free(t_lms_tilde *x) +{ + if(x->c) freebytes(x->c, sizeof(t_float) * x->N); + if(x->buf) freebytes(x->buf, sizeof(t_sample) * x->N-1); + if(x->tmp) freebytes(x->tmp, sizeof(t_sample) * x->bufsize); +} + +void lms_tilde_setup(void) +{ + lms_tilde_class = class_new(gensym("lms~"), (t_newmethod)lms_tilde_new, + (t_method)lms_tilde_free, sizeof(t_lms_tilde), + CLASS_DEFAULT, A_GIMME, 0); + + class_addmethod(lms_tilde_class, (t_method)lms_tilde_a, + gensym("adaptation"), A_DEFFLOAT, 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_geta, + gensym("getadaptation"), 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_mu, + gensym("mu"), A_DEFFLOAT, 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_getmu, + gensym("getmu"), 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_getN, + gensym("getN"), 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_init, + gensym("init_unity"), 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_clear, + gensym("clear"), 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_print, + gensym("print"), 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_write, + gensym("write"), A_DEFSYMBOL, 0); + class_addmethod(lms_tilde_class, (t_method)lms_tilde_read, + gensym("read"), A_DEFSYMBOL, 0); + + class_addmethod(lms_tilde_class, (t_method)lms_tilde_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(lms_tilde_class, t_lms_tilde, f); + + class_addmethod(lms_tilde_class, (t_method)lms_tilde_helper, gensym("help"), 0); +} diff --git a/adaptive/src/makefile b/adaptive/src/makefile new file mode 100755 index 0000000..9a3f09b --- /dev/null +++ b/adaptive/src/makefile @@ -0,0 +1,48 @@ +current: all
+
+.SUFFIXES: .pd_linux
+
+# make sure that the "m_pd.h" is somehow available either by putting it into this
+# directory, by adding it's path to the INCLUDE-path or by putting it into an
+# already included path, e.g. "/usr/include/"
+INCLUDE = -I. -I/usr/include/
+
+PDPATH = /usr/lib/pd
+
+LDFLAGS = -export-dynamic -shared
+
+#select either the DBG and OPT compiler flags below:
+
+CFLAGS = -DPD -DUNIX -W -Wno-unused \
+ -Wno-parentheses -Wno-switch -O6 -funroll-loops -fomit-frame-pointer
+
+SYSTEM = $(shell uname -m)
+
+# the sources:
+
+SRC = adaptive.c lms~.c lms2~.c nlms~.c nlms2~.c nlms3~.c
+
+TARGET = adaptive.pd_linux
+
+
+OBJ = $(SRC:.c=.o)
+
+
+# ------------------ targets ------------------------------------
+
+
+clean:
+ rm -f *.o *.pd_linux
+
+all: $(OBJ)
+ @echo :: $(OBJ)
+ ld $(LDFLAGS) -o $(TARGET) $(OBJ)
+ strip --strip-unneeded $(TARGET)
+
+$(OBJ) : %.o : %.c
+ touch $*.c
+ cc $(CFLAGS) $(INCLUDE) -c -o $*.o $*.c
+
+install:
+ cp $(TARGET) $(PDPATH)/externs
+ cp ../doc/help-*.pd $(PDPATH)/doc/5.reference
diff --git a/adaptive/src/makefile_mingw b/adaptive/src/makefile_mingw new file mode 100755 index 0000000..4f9d617 --- /dev/null +++ b/adaptive/src/makefile_mingw @@ -0,0 +1,46 @@ +current: all
+
+.SUFFIXES: .dll
+
+PDPATH = "c:/pd"
+
+INCLUDE = -I. -I$(PDPATH)/src
+
+LDFLAGS = --export-dynamic -shared
+
+#select either the DBG and OPT compiler flags below:
+
+CFLAGS = -DPD -DNT -W -Wno-unused -mms-bitfields\
+ -Wno-parentheses -Wno-switch -O6 -funroll-loops -fomit-frame-pointer
+
+SYSTEM = $(shell uname -m)
+
+# the sources:
+
+SRC = adaptive.c lms~.c lms2~.c nlms~.c nlms2~.c nlms3~.c
+
+TARGET = adaptive.dll
+
+
+OBJ = $(SRC:.c=.o)
+
+
+# ------------------ targets ------------------------------------
+
+
+clean:
+ rm -f *.a *.def *.o *.dll
+
+all: $(OBJ)
+ @echo :: $(OBJ)
+ g++ $(LDFLAGS) -o $(TARGET) $(OBJ) $(PDPATH)/bin/pd.dll -libc
+ strip --strip-unneeded $(TARGET)
+ chmod 755 $(TARGET)
+
+$(OBJ) : %.o : %.c
+ touch $*.c
+ gcc $(CFLAGS) $(INCLUDE) -c -o $*.o $*.c
+
+install:
+ cp $(TARGET) $(PDPATH)/externs
+ cp ../doc/help-*.pd $(PDPATH)/doc/5.reference
diff --git a/adaptive/src/makefile_msvc b/adaptive/src/makefile_msvc new file mode 100755 index 0000000..dc104c3 --- /dev/null +++ b/adaptive/src/makefile_msvc @@ -0,0 +1,39 @@ +
+current: all
+
+TARGET = adaptive.dll
+
+VIS_CPP_PATH = "C:\Programme\Microsoft Visual Studio\Vc98"
+
+PD_INST_PATH = "C:\pd"
+
+SRC = adaptive.c lms~.c lms2~.c nlms~.c nlms2~.c nlms3~.c
+
+PD_WIN_INCLUDE_PATH = /I. /I$(PD_INST_PATH)\src /I$(VIS_CPP_PATH)\include
+
+PD_WIN_C_FLAGS = /W3 /WX /DNT /DPD /nologo
+
+PD_WIN_L_FLAGS = /nologo
+
+PD_WIN_LIB = $(VIS_CPP_PATH)\lib\libc.lib \
+ $(VIS_CPP_PATH)\lib\oldnames.lib \
+ $(VIS_CPP_PATH)\lib\kernel32.lib \
+ $(PD_INST_PATH)\bin\pd.lib
+
+
+OBJ = $(SRC:.c=.obj)
+
+.c.obj:
+ cl $(PD_WIN_C_FLAGS) $(PD_WIN_INCLUDE_PATH) /c $*.c
+
+all: $(OBJ)
+ link $(PD_WIN_L_FLAGS) /dll /export:adaptive_setup \
+ /out:$(TARGET) $(OBJ) $(PD_WIN_LIB)
+ del *.obj *.lib *.exp
+
+clean:
+ del *.obj *.dll *.lib *.exp
+
+install:
+ copy *.dll $(PD_INST_PATH)\externs
+ copy ..\doc\*.pd $(PD_INST_PATH)\doc\5.reference
diff --git a/adaptive/src/nlms2~.c b/adaptive/src/nlms2~.c new file mode 100755 index 0000000..c967641 --- /dev/null +++ b/adaptive/src/nlms2~.c @@ -0,0 +1,359 @@ +/****************************************************** + * + * Adaptive Systems for PD + * + * copyleft (c) Gerda Strobl, Georg Holzmann + * 2005 + * + * for complaints, suggestions: grh@mur.at + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + +#include "adaptive.h" + + +/* ------------------------ nlms2~ ------------------------- */ + +static t_class *nlms2_tilde_class; + +typedef struct _nlms2 +{ + t_object x_obj; + t_float f; + t_atom *coef; + t_sample *buf; + t_sample *y_tmp; + t_sample *e_tmp; + t_int bufsize; + t_outlet *c_out; + int adapt; // enable/disable adaptation + + t_int N; //number of coefficients of the adaptive system + t_float *c; // coefficients of the system + t_float mu; // step-size parameter (learning rate) + t_float alpha; // small constant to avoid division by zero + + t_canvas *x_canvas; +} t_nlms2_tilde; + +static void nlms2_tilde_a(t_nlms2_tilde *x, t_floatarg f) +{ + x->adapt = (f==0) ? 0 : 1; +} + +static void nlms2_tilde_geta(t_nlms2_tilde *x) +{ + if(x->adapt==0) + post("nlms2~: adaptation is currently OFF"); + else + post("nlms2~: adaptation is currently ON"); +} + +static void nlms2_tilde_mu(t_nlms2_tilde *x, t_floatarg f) +{ + x->mu = f; +} + +static void nlms2_tilde_getmu(t_nlms2_tilde *x) +{ + post("mu (step-size parameter): %f", x->mu); +} + +static void nlms2_tilde_alpha(t_nlms2_tilde *x, t_floatarg f) +{ + x->alpha = f; +} + +static void nlms2_tilde_getalpha(t_nlms2_tilde *x) +{ + post("alpha: %f", x->alpha); +} + +static void nlms2_tilde_getN(t_nlms2_tilde *x) +{ + post("N (number of coefficients): %d", x->N); +} + +static void nlms2_tilde_clear(t_nlms2_tilde *x) +{ + int i; + + // clear coefficients + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffer + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void nlms2_tilde_init(t_nlms2_tilde *x) +{ + int i; + + // set the first coefficient to 1, all others to 0 + // so this is a delay free transmission + x->c[0] = 1; + for(i=1; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffers + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void nlms2_tilde_print(t_nlms2_tilde *x) +{ + int i; + + // print coefficients + post("\nNr. of coefficients: %d",x->N); + post("coefficients:"); + for(i=0; i<x->N; i++) + post("\t%d: %f",i,x->c[i]); +} + +static void nlms2_tilde_write(t_nlms2_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // save to file + adaptation_write(filename, x->N, x->mu, x->c); +} + +static void nlms2_tilde_read(t_nlms2_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + int n = x->N; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // read file + adaptation_read(filename, &x->N, &x->mu, x->c, x->buf); + + // if length changes: + if(x->N != n) + { + if(x->coef) freebytes(x->coef, sizeof(t_atom) * x->N); + x->coef = (t_atom *)getbytes(sizeof(t_atom) * x->N); + } +} + +static t_int *nlms2_tilde_perform(t_int *w) +{ + t_sample *x_ = (t_sample *)(w[1]); + t_sample *d_ = (t_sample *)(w[2]); + t_sample *y_ = (t_sample *)(w[3]); + t_sample *e_ = (t_sample *)(w[4]); + int n = (int)(w[5]); + t_nlms2_tilde *x = (t_nlms2_tilde *)(w[6]); + int i, j, tmp; + t_sample x_2; + + + for(i=0; i<n; i++) + { + // calc output (filter) + + x->y_tmp[i]=0; + + // y_[i] += x->c[j] * x_[i-j]; + // so lets split in two halfs, so that + // negative indezes get samples from the + // last audioblock (x->buf) ... + tmp = (i+1 - x->N)*(-1); + tmp = tmp<0 ? 0 : tmp; + + for(j=0; j<x->N-tmp; j++) + x->y_tmp[i] += x->c[j] * x_[i-j]; + + for(j=x->N-tmp; j<x->N; j++) + x->y_tmp[i] += x->c[j] * x->buf[(i-j)*(-1)-1]; + + if(x->adapt) + { + x_2=0; + + // error computation + x->e_tmp[i] = d_[i] - x->y_tmp[i]; + + // Normalized LMS Adaptmsation Algorithm + // (split in the same way as above) + // + // c[n] = c[n-1] + mu/(alpha + x'[n]*x[n])*e[n]*x[n] + + // calc x'[n]*x[n] + + for(j=0; j<x->N-tmp; j++) + x_2 += x_[i-j] * x_[i-j]; + for(j=x->N-tmp; j<x->N; j++) + x_2 += x->buf[(i-j)*(-1)-1] * x->buf[(i-j)*(-1)-1]; + + + for(j=0; j<x->N-tmp; j++) + x->c[j] = x->c[j] + x->mu/(x->alpha+x_2) * x_[i-j] * x->e_tmp[i]; + + for(j=x->N-tmp; j<x->N; j++) + x->c[j] = x->c[j] + x->mu/(x->alpha+x_2) * x->buf[(i-j)*(-1)-1] * x->e_tmp[i]; + } + else x->e_tmp[i] = 0; + + //post("%d: in %f, d: %f, out: %f, e: %f, c1:%f, c2:%f", i, x_[i], d_[i], x->y_tmp[i], x->e_tmp[i], x->c[0], x->c[1]); + } + + // outlet coefficients + for(i=0; i<x->N; i++) + SETFLOAT(&x->coef[i],x->c[i]); + + outlet_list(x->c_out, &s_list, x->N, x->coef); + + // store last samples for next audiobuffer + for(i=0; i<x->N-1; i++) + x->buf[i] = x_[n-1-i]; + + // now write to outlets + while(n--) + { + y_[n] = x->y_tmp[n]; + e_[n] = x->e_tmp[n]; + } + + return (w+7); +} + +static void nlms2_tilde_dsp(t_nlms2_tilde *x, t_signal **sp) +{ + // allocate new temp buffer if buffersize changes + if(x->bufsize != sp[0]->s_n) + { + if(sp[0]->s_n < x->N) + post("nlms2~ WARNING: buffersize must be bigger than N, you will get wrong results !!!"); + + if(x->y_tmp) freebytes(x->y_tmp, sizeof(t_sample) * x->bufsize); + x->y_tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + if(x->e_tmp) freebytes(x->e_tmp, sizeof(t_sample) * x->bufsize); + x->e_tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + x->bufsize = sp[0]->s_n; + } + + dsp_add(nlms2_tilde_perform, 6, sp[0]->s_vec, sp[1]->s_vec, + sp[2]->s_vec, sp[3]->s_vec, sp[0]->s_n, x); +} + +static void nlms2_tilde_helper(void) +{ + post("\nnlms2~: Adaptive transversal filter using normalized LMS"); + post("INPUT:"); + post("\tinlet1: input signal x[n]"); + post("\tinlet2: desired output signal d[n]"); + post("\tinit_arg1: number of coefficients of the adaptive system"); + post("\tinit_arg2, mu: step-size parameter (learning rate)"); + post("OUTPUT:"); + post("\toutlet1: output signal"); + post("\toutlet2: error signal e[n]"); + post("\toutlet3: coefficients c[n] (only per block)\n"); +} + +static void *nlms2_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_nlms2_tilde *x = (t_nlms2_tilde *)pd_new(nlms2_tilde_class); + int i; + + // default values: + x->N = 8; + x->mu = 0.05; + x->alpha = 0.0001; + x->adapt = 0; + x->y_tmp = NULL; + x->e_tmp = NULL; + x->bufsize = 0; + + switch(argc) + { + case 2: + x->mu = atom_getfloat(argv+1); + case 1: + x->N = atom_getint(argv); + x->N = (x->N<=0) ? 1 : x->N; + } + + // allocate mem and init coefficients + x->c = (t_float *)getbytes(sizeof(t_float) * x->N); + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // allocate mem for temp buffer + x->buf = (t_sample *)getbytes(sizeof(t_sample) * x->N-1); + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + + // for output atoms (coefficients): + x->coef = (t_atom *)getbytes(sizeof(t_atom) * x->N); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->c_out = outlet_new(&x->x_obj, 0); + + x->x_canvas = canvas_getcurrent(); + + return (x); +} + +static void nlms2_tilde_free(t_nlms2_tilde *x) +{ + if(x->c) freebytes(x->c, sizeof(t_float) * x->N); + if(x->buf) freebytes(x->buf, sizeof(t_sample) * x->N-1); + if(x->y_tmp) freebytes(x->y_tmp, sizeof(t_sample) * x->bufsize); + if(x->e_tmp) freebytes(x->e_tmp, sizeof(t_sample) * x->bufsize); + if(x->coef) freebytes(x->coef, sizeof(t_atom) * x->N); +} + +void nlms2_tilde_setup(void) +{ + nlms2_tilde_class = class_new(gensym("nlms2~"), (t_newmethod)nlms2_tilde_new, + (t_method)nlms2_tilde_free, sizeof(t_nlms2_tilde), + CLASS_DEFAULT, A_GIMME, 0); + + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_a, + gensym("adaptation"), A_DEFFLOAT, 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_geta, + gensym("getadaptation"), 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_mu, + gensym("mu"), A_DEFFLOAT, 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_getmu, + gensym("getmu"), 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_alpha, + gensym("alpha"), A_DEFFLOAT, 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_getalpha, + gensym("getalpha"), 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_getN, + gensym("getN"), 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_init, + gensym("init_unity"), 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_clear, + gensym("clear"), 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_print, + gensym("print"), 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_write, + gensym("write"), A_DEFSYMBOL, 0); + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_read, + gensym("read"), A_DEFSYMBOL, 0); + + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(nlms2_tilde_class, t_nlms2_tilde, f); + + class_addmethod(nlms2_tilde_class, (t_method)nlms2_tilde_helper, gensym("help"), 0); +} diff --git a/adaptive/src/nlms3~.c b/adaptive/src/nlms3~.c new file mode 100755 index 0000000..a1857a2 --- /dev/null +++ b/adaptive/src/nlms3~.c @@ -0,0 +1,423 @@ +/****************************************************** + * + * Adaptive Systems for PD + * + * copyleft (c) Gerda Strobl, Georg Holzmann + * 2005 + * + * for complaints, suggestions: grh@mur.at + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + +#include "adaptive.h" + + +/* ------------------------ nlms3~ ------------------------- */ + +static t_class *nlms3_tilde_class; + +typedef struct _nlms3 +{ + t_object x_obj; + t_float f; + t_atom *coef; + t_sample *buf; + t_sample *xbuf; + t_sample *in_tmp; + t_sample *y_tmp; + t_sample *e_tmp; + t_int bufsize; + t_outlet *c_out; + int adapt; // enable/disable adaptation + + t_int N; //number of coefficients of the adaptive system + t_float *c; // coefficients of the system + t_float mu; // step-size parameter (learning rate) + t_float alpha; // small constant to avoid division by zero + + t_canvas *x_canvas; +} t_nlms3_tilde; + +static void nlms3_tilde_a(t_nlms3_tilde *x, t_floatarg f) +{ + x->adapt = (f==0) ? 0 : 1; + + if(!x->adapt) + { + int i; + + // clear temp buffers + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + for(i=0; i<x->N-1; i++) + x->xbuf[i] = 0; + } +} + +static void nlms3_tilde_geta(t_nlms3_tilde *x) +{ + if(x->adapt==0) + post("nlms3~: adaptation is currently OFF"); + else + post("nlms3~: adaptation is currently ON"); +} + +static void nlms3_tilde_mu(t_nlms3_tilde *x, t_floatarg f) +{ + x->mu = f; +} + +static void nlms3_tilde_getmu(t_nlms3_tilde *x) +{ + post("mu (step-size parameter): %f", x->mu); +} + +static void nlms3_tilde_alpha(t_nlms3_tilde *x, t_floatarg f) +{ + x->alpha = f; +} + +static void nlms3_tilde_getalpha(t_nlms3_tilde *x) +{ + post("alpha: %f", x->alpha); +} + +static void nlms3_tilde_getN(t_nlms3_tilde *x) +{ + post("N (number of coefficients): %d", x->N); +} + +static void nlms3_tilde_clear(t_nlms3_tilde *x) +{ + int i; + + // clear coefficients + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffers + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + for(i=0; i<x->N-1; i++) + x->xbuf[i] = 0; +} + +static void nlms3_tilde_init(t_nlms3_tilde *x) +{ + int i; + + // set the first coefficient to 1, all others to 0 + // so this is a delay free transmission + x->c[0] = 1; + for(i=1; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffers + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + for(i=0; i<x->N-1; i++) + x->xbuf[i] = 0; +} + +static void nlms3_tilde_print(t_nlms3_tilde *x) +{ + int i; + + // print coefficients + post("\nNr. of coefficients: %d",x->N); + post("coefficients:"); + for(i=0; i<x->N; i++) + post("\t%d: %f",i,x->c[i]); +} + +static void nlms3_tilde_write(t_nlms3_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // save to file + adaptation_write(filename, x->N, x->mu, x->c); +} + +static void nlms3_tilde_read(t_nlms3_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + int n = x->N; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // read file + adaptation_read(filename, &x->N, &x->mu, x->c, x->buf); + + // if length changes: + if(x->N != n) + { + if(x->coef) freebytes(x->coef, sizeof(t_atom) * x->N); + x->coef = (t_atom *)getbytes(sizeof(t_atom) * x->N); + } +} + +static t_int *nlms3_tilde_perform(t_int *w) +{ + t_sample *in_ = (t_sample *)(w[1]); + t_sample *x_ = (t_sample *)(w[2]); + t_sample *d_ = (t_sample *)(w[3]); + t_sample *out_= (t_sample *)(w[4]); + t_sample *y_ = (t_sample *)(w[5]); + t_sample *e_ = (t_sample *)(w[6]); + int n = (int)(w[7]); + t_nlms3_tilde *x = (t_nlms3_tilde *)(w[8]); + int i, j, tmp; + t_sample x_2; + + + // calculate inlet2 (filter+adaptation) + if(x->adapt) + { + for(i=0; i<n; i++) + { + x->y_tmp[i]=0; + x_2=0; + + // y_[i] += x->c[j] * x_[i-j]; + // so lets split in two halfs, so that + // negative indezes get samples from the + // last audioblock (x->buf) ... + tmp = (i+1 - x->N)*(-1); + tmp = tmp<0 ? 0 : tmp; + + for(j=0; j<x->N-tmp; j++) + x->y_tmp[i] += x->c[j] * x_[i-j]; + + for(j=x->N-tmp; j<x->N; j++) + x->y_tmp[i] += x->c[j] * x->xbuf[(i-j)*(-1)-1]; + + // error computation + x->e_tmp[i] = d_[i] - x->y_tmp[i]; + + // Normalized LMS Adaptmsation Algorithm + // (split in the same way as above) + // + // c[n] = c[n-1] + mu/(alpha + x'[n]*x[n])*e[n]*x[n] + + // calc x'[n]*x[n] + + for(j=0; j<x->N-tmp; j++) + x_2 += x_[i-j] * x_[i-j]; + for(j=x->N-tmp; j<x->N; j++) + x_2 += x->xbuf[(i-j)*(-1)-1] * x->xbuf[(i-j)*(-1)-1]; + + for(j=0; j<x->N-tmp; j++) + x->c[j] = x->c[j] + x->mu/(x->alpha+x_2) * x_[i-j] * x->e_tmp[i]; + for(j=x->N-tmp; j<x->N; j++) + x->c[j] = x->c[j] + x->mu/(x->alpha+x_2) * x->xbuf[(i-j)*(-1)-1] * x->e_tmp[i]; + } + + // outlet coefficients + for(i=0; i<x->N; i++) + SETFLOAT(&x->coef[i],x->c[i]); + + outlet_list(x->c_out, &s_list, x->N, x->coef); + + // store last samples for next audiobuffer + for(i=0; i<x->N-1; i++) + x->xbuf[i] = x_[n-1-i]; + } + + + // calculate filter output (inlet 1) + for(i=0; i<n; i++) + { + x->in_tmp[i]=0; + + // y_[i] += x->c[j] * x_[i-j]; + // so lets split in two halfs, so that + // negative indezes get samples from the + // last audioblock (x->buf) ... + tmp = (i+1 - x->N)*(-1); + tmp = tmp<0 ? 0 : tmp; + + for(j=0; j<x->N-tmp; j++) + x->in_tmp[i] += x->c[j] * in_[i-j]; + + for(j=x->N-tmp; j<x->N; j++) + x->in_tmp[i] += x->c[j] * x->buf[(i-j)*(-1)-1]; + } + // store last samples for next audiobuffer + for(i=0; i<x->N-1; i++) + x->buf[i] = in_[n-1-i]; + + + // write to the outlets + if(x->adapt) + { + while(n--) + { + out_[n] = x->in_tmp[n]; + y_[n] = x->y_tmp[n]; + e_[n] = x->e_tmp[n]; + } + } + else + { + while(n--) + { + out_[n] = x->in_tmp[n]; + y_[n] = 0; + e_[n] = 0; + } + } + + + return (w+9); +} + +static void nlms3_tilde_dsp(t_nlms3_tilde *x, t_signal **sp) +{ + // allocate new temp buffer if buffersize changes + if(x->bufsize != sp[0]->s_n) + { + if(sp[0]->s_n < x->N) + post("nlms3~ WARNING: buffersize must be bigger than N, you will get wrong results !!!"); + + if(x->in_tmp) freebytes(x->in_tmp, sizeof(t_sample) * x->bufsize); + x->in_tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + if(x->y_tmp) freebytes(x->y_tmp, sizeof(t_sample) * x->bufsize); + x->y_tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + if(x->e_tmp) freebytes(x->e_tmp, sizeof(t_sample) * x->bufsize); + x->e_tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + x->bufsize = sp[0]->s_n; + } + + dsp_add(nlms3_tilde_perform, 8, 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[0]->s_n, x); +} + +static void nlms3_tilde_helper(void) +{ + post("\nnlms3~: Adaptive transversal filter using normalized LMS"); + post("INPUT:"); + post("\tinlet1: input signal without adaptation, only filter"); + post("\tinlet2: input signal for adaptation x[n]"); + post("\tinlet3: desired output signal d[n]"); + post("\tinit_arg1: number of coefficients of the adaptive system"); + post("\tinit_arg2, mu: step-size parameter (learning rate)"); + post("OUTPUT:"); + post("\toutlet1: output signal from inlet1"); + post("\toutlet2: output signal from inlet2"); + post("\toutlet3: error signal e[n]"); + post("\toutlet4: coefficients c[n] (only per block)\n"); +} + +static void *nlms3_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_nlms3_tilde *x = (t_nlms3_tilde *)pd_new(nlms3_tilde_class); + int i; + + // default values: + x->N = 8; + x->mu = 0.05; + x->alpha = 0.000001; + x->adapt = 0; + x->in_tmp = NULL; + x->y_tmp = NULL; + x->e_tmp = NULL; + x->bufsize = 0; + + switch(argc) + { + case 2: + x->mu = atom_getfloat(argv+1); + case 1: + x->N = atom_getint(argv); + x->N = (x->N<=0) ? 1 : x->N; + } + + // allocate mem and init coefficients + x->c = (t_float *)getbytes(sizeof(t_float) * x->N); + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // allocate mem for temp buffers + x->buf = (t_sample *)getbytes(sizeof(t_sample) * x->N-1); + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + x->xbuf = (t_sample *)getbytes(sizeof(t_sample) * x->N-1); + for(i=0; i<x->N-1; i++) + x->xbuf[i] = 0; + + // for output atoms (coefficients): + x->coef = (t_atom *)getbytes(sizeof(t_atom) * x->N); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + outlet_new(&x->x_obj, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->c_out = outlet_new(&x->x_obj, 0); + + x->x_canvas = canvas_getcurrent(); + + return (x); +} + +static void nlms3_tilde_free(t_nlms3_tilde *x) +{ + if(x->c) freebytes(x->c, sizeof(t_float) * x->N); + if(x->buf) freebytes(x->buf, sizeof(t_sample) * x->N-1); + if(x->xbuf) freebytes(x->xbuf, sizeof(t_sample) * x->N-1); + if(x->in_tmp) freebytes(x->y_tmp, sizeof(t_sample) * x->bufsize); + if(x->y_tmp) freebytes(x->y_tmp, sizeof(t_sample) * x->bufsize); + if(x->e_tmp) freebytes(x->e_tmp, sizeof(t_sample) * x->bufsize); + if(x->coef) freebytes(x->coef, sizeof(t_atom) * x->N); +} + +void nlms3_tilde_setup(void) +{ + nlms3_tilde_class = class_new(gensym("nlms3~"), (t_newmethod)nlms3_tilde_new, + (t_method)nlms3_tilde_free, sizeof(t_nlms3_tilde), + CLASS_DEFAULT, A_GIMME, 0); + + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_a, + gensym("adaptation"), A_DEFFLOAT, 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_geta, + gensym("getadaptation"), 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_mu, + gensym("mu"), A_DEFFLOAT, 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_getmu, + gensym("getmu"), 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_alpha, + gensym("alpha"), A_DEFFLOAT, 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_getalpha, + gensym("getalpha"), 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_getN, + gensym("getN"), 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_init, + gensym("init_unity"), 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_clear, + gensym("clear"), 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_print, + gensym("print"), 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_write, + gensym("write"), A_DEFSYMBOL, 0); + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_read, + gensym("read"), A_DEFSYMBOL, 0); + + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(nlms3_tilde_class, t_nlms3_tilde, f); + + class_addmethod(nlms3_tilde_class, (t_method)nlms3_tilde_helper, gensym("help"), 0); +} diff --git a/adaptive/src/nlms~.c b/adaptive/src/nlms~.c new file mode 100755 index 0000000..5ebc4f5 --- /dev/null +++ b/adaptive/src/nlms~.c @@ -0,0 +1,324 @@ +/****************************************************** + * + * Adaptive Systems for PD + * + * copyleft (c) Gerda Strobl, Georg Holzmann + * 2005 + * + * for complaints, suggestions: grh@mur.at + * + ****************************************************** + * + * license: GNU General Public License v.2 + * + ******************************************************/ + +#include "adaptive.h" + + +/* ------------------------ nlms~ ------------------------- */ + +static t_class *nlms_tilde_class; + +typedef struct _nlms +{ + t_object x_obj; + t_float f; + t_sample *buf; + t_sample *tmp; + t_int bufsize; + int adapt; // enable/disable adaptation + + t_int N; //number of coefficients of the adaptive system + t_float *c; // coefficients of the system + t_float mu; // step-size parameter (learning rate) + t_float alpha; // small constant to avoid division by zero + + t_canvas *x_canvas; +} t_nlms_tilde; + +static void nlms_tilde_a(t_nlms_tilde *x, t_floatarg f) +{ + x->adapt = (f==0) ? 0 : 1; +} + +static void nlms_tilde_geta(t_nlms_tilde *x) +{ + if(x->adapt==0) + post("nlms~: adaptation is currently OFF"); + else + post("nlms~: adaptation is currently ON"); +} + +static void nlms_tilde_mu(t_nlms_tilde *x, t_floatarg f) +{ + x->mu = f; +} + +static void nlms_tilde_getmu(t_nlms_tilde *x) +{ + post("mu (step-size parameter): %f", x->mu); +} + +static void nlms_tilde_alpha(t_nlms_tilde *x, t_floatarg f) +{ + x->alpha = f; +} + +static void nlms_tilde_getalpha(t_nlms_tilde *x) +{ + post("alpha: %f", x->alpha); +} + +static void nlms_tilde_getN(t_nlms_tilde *x) +{ + post("N (number of coefficients): %d", x->N); +} + +static void nlms_tilde_clear(t_nlms_tilde *x) +{ + int i; + + // clear coefficients + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffer + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void nlms_tilde_init(t_nlms_tilde *x) +{ + int i; + + // set the first coefficient to 1, all others to 0 + // so this is a delay free transmission + x->c[0] = 1; + for(i=1; i<x->N; i++) + x->c[i] = 0; + + // clear temp buffers + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; +} + +static void nlms_tilde_print(t_nlms_tilde *x) +{ + int i; + + // print coefficients + post("\nNr. of coefficients: %d",x->N); + post("coefficients:"); + for(i=0; i<x->N; i++) + post("\t%d: %f",i,x->c[i]); +} + +static void nlms_tilde_write(t_nlms_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // save to file + adaptation_write(filename, x->N, x->mu, x->c); +} + +static void nlms_tilde_read(t_nlms_tilde *x, t_symbol *s) +{ + // make correct path + char filnam[MAXPDSTRING]; + char filename[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, s->s_name, filnam, MAXPDSTRING); + sys_bashfilename(filnam, filename); + + // read file + adaptation_read(filename, &x->N, &x->mu, x->c, x->buf); +} + +static t_int *nlms_tilde_perform(t_int *w) +{ + t_nlms_tilde *x = (t_nlms_tilde *)(w[1]); + t_sample *x_ = (t_sample *)(w[2]); + t_sample *d_ = (t_sample *)(w[3]); + t_sample *y_ = (t_sample *)(w[4]); + int n = (int)(w[5]); + int i, j, tmp; + t_sample e=0, x_2; + + + for(i=0; i<n; i++) + { + // calc output (filter) + + x->tmp[i]=0; + + // y_[i] += x->c[j] * x_[i-j]; + // so lets split in two halfs, so that + // negative indezes get samples from the + // last audioblock (x->buf) ... + tmp = (i+1 - x->N)*(-1); + tmp = tmp<0 ? 0 : tmp; + + for(j=0; j<x->N-tmp; j++) + x->tmp[i] += x->c[j] * x_[i-j]; + + for(j=x->N-tmp; j<x->N; j++) + x->tmp[i] += x->c[j] * x->buf[(i-j)*(-1)-1]; + + if(x->adapt) + { + x_2=0; + + // error computation + e =d_[i] - x->tmp[i]; + + // Normalized LMS Adaptmsation Algorithm + // (split in the same way as above) + // + // c[n] = c[n-1] + mu/(alpha + x'[n]*x[n])*e[n]*x[n] + + // calc x'[n]*x[n] + // TODO: Performance Optimization: save results from the past + // so that this for loop should be obsolet ... + for(j=0; j<x->N-tmp; j++) + x_2 += x_[i-j] * x_[i-j]; + for(j=x->N-tmp; j<x->N; j++) + x_2 += x->buf[(i-j)*(-1)-1] * x->buf[(i-j)*(-1)-1]; + + + for(j=0; j<x->N-tmp; j++) + x->c[j] = x->c[j] + x->mu/(x->alpha+x_2) * x_[i-j] * e; + + for(j=x->N-tmp; j<x->N; j++) + x->c[j] = x->c[j] + x->mu/(x->alpha+x_2) * x->buf[(i-j)*(-1)-1] * e; + } + + //post("%d: in %f, d: %f, out: %f, error: %f, c1:%f, c2:%f", i, x_[i], d_[i], x->tmp[i], e, x->c[0], x->c[1]); + } + + // store last samples for next audiobuffer + for(i=0; i<x->N-1; i++) + x->buf[i] = x_[n-1-i]; + + // now write tmp to outlet + while(n--) + y_[n] = x->tmp[n]; + + return (w+6); +} + +static void nlms_tilde_dsp(t_nlms_tilde *x, t_signal **sp) +{ + // allocate new temp buffer if buffersize changes + if(x->bufsize != sp[0]->s_n) + { + if(sp[0]->s_n < x->N) + post("nlms~ WARNING: buffersize must be bigger than N, you will get wrong results !!!"); + + if(x->tmp) freebytes(x->tmp, sizeof(t_sample) * x->bufsize); + x->tmp = (t_sample *)getbytes(sizeof(t_sample) * sp[0]->s_n); + + x->bufsize = sp[0]->s_n; + } + + dsp_add(nlms_tilde_perform, 5, x, sp[0]->s_vec, sp[1]->s_vec, + sp[2]->s_vec, sp[0]->s_n); +} + +static void nlms_tilde_helper(void) +{ + post("\nnlms~: Adaptive transversal filter using normalized LMS"); + post("INPUT:"); + post("\tinlet1: input signal x[n]"); + post("\tinlet2: desired output signal d[n]"); + post("\tinit_arg1: number of coefficients of the adaptive system"); + post("\tinit_arg2, mu: step-size parameter (learning rate)"); + post("OUTPUT:"); + post("\toutlet1: output signal\n"); +} + +static void *nlms_tilde_new(t_symbol *s, int argc, t_atom *argv) +{ + t_nlms_tilde *x = (t_nlms_tilde *)pd_new(nlms_tilde_class); + int i; + + // default values: + x->N = 8; + x->mu = 0.05; + x->alpha = 0.0001; + x->adapt = 0; + x->tmp = NULL; + x->bufsize = 0; + + switch(argc) + { + case 2: + x->mu = atom_getfloat(argv+1); + case 1: + x->N = atom_getint(argv); + x->N = (x->N<=0) ? 1 : x->N; + } + + // allocate mem and init coefficients + x->c = (t_float *)getbytes(sizeof(t_float) * x->N); + for(i=0; i<x->N; i++) + x->c[i] = 0; + + // allocate mem for temp buffer + x->buf = (t_sample *)getbytes(sizeof(t_sample) * x->N-1); + for(i=0; i<x->N-1; i++) + x->buf[i] = 0; + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_canvas = canvas_getcurrent(); + + return (x); +} + +static void nlms_tilde_free(t_nlms_tilde *x) +{ + if(x->c) freebytes(x->c, sizeof(t_float) * x->N); + if(x->buf) freebytes(x->buf, sizeof(t_sample) * x->N-1); + if(x->tmp) freebytes(x->tmp, sizeof(t_sample) * x->bufsize); +} + +void nlms_tilde_setup(void) +{ + nlms_tilde_class = class_new(gensym("nlms~"), (t_newmethod)nlms_tilde_new, + (t_method)nlms_tilde_free, sizeof(t_nlms_tilde), + CLASS_DEFAULT, A_GIMME, 0); + + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_a, + gensym("adaptation"), A_DEFFLOAT, 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_geta, + gensym("getadaptation"), 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_mu, + gensym("mu"), A_DEFFLOAT, 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_getmu, + gensym("getmu"), 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_alpha, + gensym("alpha"), A_DEFFLOAT, 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_getalpha, + gensym("getalpha"), 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_getN, + gensym("getN"), 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_init, + gensym("init_unity"), 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_clear, + gensym("clear"), 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_print, + gensym("print"), 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_write, + gensym("write"), A_DEFSYMBOL, 0); + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_read, + gensym("read"), A_DEFSYMBOL, 0); + + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(nlms_tilde_class, t_nlms_tilde, f); + + class_addmethod(nlms_tilde_class, (t_method)nlms_tilde_helper, gensym("help"), 0); +} |