Update of /cvsroot/pure-data/externals/grh/adaptive/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28792/src
Added Files: adaptive.c adaptive.h lms2~.c lms~.c makefile makefile_mingw makefile_msvc nlms2~.c nlms3~.c nlms~.c Log Message: initial commit of adaptive
--- NEW FILE: lms~.c --- /****************************************************** * * 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); }
--- NEW FILE: nlms~.c --- /****************************************************** * * 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); }
--- NEW FILE: makefile_mingw --- 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
--- NEW FILE: adaptive.c --- /****************************************************** * * 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"); }
--- NEW FILE: nlms3~.c --- /****************************************************** * * 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); }
--- NEW FILE: adaptive.h --- /****************************************************** * * 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__
--- NEW FILE: nlms2~.c --- /****************************************************** * * 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); }
--- NEW FILE: makefile --- 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
--- NEW FILE: lms2~.c --- /****************************************************** * * 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); }
--- NEW FILE: makefile_msvc ---
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