aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Morelli <morellid@users.sourceforge.net>2005-10-18 23:10:53 +0000
committerDavide Morelli <morellid@users.sourceforge.net>2005-10-18 23:10:53 +0000
commiteb9ef05774af20edb43118182834c18a4ac70707 (patch)
treec7ae7be5449dc270e37f3f62ada9840d4efdf0cd
initial checkinsvn2git-root
svn path=/trunk/externals/frankenstein/; revision=3734
-rwxr-xr-xGArhythm.c539
-rwxr-xr-xMakefile40
-rwxr-xr-xREADME.txt77
-rwxr-xr-xSHOWME.pd30
-rwxr-xr-xbay.orc418
-rwxr-xr-xchord_melo.c1137
-rwxr-xr-xchord_melo_test3.pd630
-rwxr-xr-xchords_memory.c1137
-rwxr-xr-xdoc/LINKS.txt26
-rwxr-xr-xdoc/README.txt27
-rwxr-xr-xdoc/chords_graph.docbin0 -> 75264 bytes
-rwxr-xr-xdoc/chords_graph.sxwbin0 -> 16853 bytes
-rwxr-xr-xdoc/genomes-notes.txt125
-rwxr-xr-xdoc/maxlibnotes.txt16
-rwxr-xr-xdoc/model.docbin0 -> 17920 bytes
-rwxr-xr-xdoc/model.sxwbin0 -> 6944 bytes
-rwxr-xr-xharmonizer.c629
-rwxr-xr-xmakefile.darwin37
-rwxr-xr-xmanager.pd14
-rwxr-xr-xpatches/SHOWME.pd28
-rwxr-xr-xpatches/bay.orc418
-rwxr-xr-xpatches/test-harmonizer2.pd185
-rwxr-xr-xpatches/test.graphbin0 -> 57604 bytes
-rwxr-xr-xritmo1.c115
-rwxr-xr-xsglib.h1947
-rwxr-xr-xtest-chords_graph.pd46
-rwxr-xr-xtest-harmonizer.pd172
-rwxr-xr-xtest-harmonizer2.pd197
-rwxr-xr-xtest.graphbin0 -> 58564 bytes
29 files changed, 7990 insertions, 0 deletions
diff --git a/GArhythm.c b/GArhythm.c
new file mode 100755
index 0000000..a41b311
--- /dev/null
+++ b/GArhythm.c
@@ -0,0 +1,539 @@
+/*
+
+*/
+#include <stdlib.h>
+#include "m_pd.h"
+
+#define BUFFER_LENGHT 16 // lunghezza dei buffers (quanti elementi nel pattern)
+#define MAX_POPULATION 100
+#define CHOIR 20
+#define NUM_STRUM 4 // quanti strumenti uso , max 8
+
+#define DEF_PROB_CROSSOVER 0.9f
+#define DEF_PROB_MUTATION 0.025f
+#define REINSERT_SRC 1 // quanti reinserisco ad ogni ciclo usando il ritmo src
+#define REINSERT_LAST 0 // quanti reinserisco ad ogni ciclo usando il ritmo src
+
+#define DEBUG 0 // messaggi di debug
+
+static t_class *GArhythm_class;
+
+
+typedef struct _GArhythm
+{
+ t_object x_obj; // myself
+ t_symbol *x_arrayname_src_strum1; // where i read the current pattern
+ t_symbol *x_arrayname_src_strum2; // where i read the current pattern
+ t_symbol *x_arrayname_src_strum3; // where i read the current pattern
+ t_symbol *x_arrayname_src_strum4; // where i read the current pattern
+ t_symbol *x_arrayname_dest_strum1; // where i put the computed pattern
+ t_symbol *x_arrayname_dest_strum2; // where i put the computed pattern
+ t_symbol *x_arrayname_dest_strum3; // where i put the computed pattern
+ t_symbol *x_arrayname_dest_strum4; // where i put the computed pattern
+ //t_float *buf_strum1; // buffer strum1o
+ //t_float *buf_strum2; // buffer alto
+ // tutti gli indici vanno da 0 a 1;
+ float indice_variazione; // quanto cambio dalla battuta precedente
+ float indice_riempimento; // quanto voglio fitto il pattern risultante
+ float indice_aderenza; // quanto simile al ritmo sorgente devo essere
+ // la popolazione array di cromosomi
+ char population[MAX_POPULATION][BUFFER_LENGHT];
+ float prob_crossover;
+ float prob_mutation;
+ char last[BUFFER_LENGHT];
+
+} t_GArhythm;
+
+void GArhythm_init_pop(t_GArhythm *x)
+{
+ int i, j, tmp, k;
+ double rnd;
+ for (i=0; i<MAX_POPULATION; i++)
+ {
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ tmp = 0;
+ for (k=0; k<NUM_STRUM; k++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd > 0.5)
+ {
+ tmp = tmp + (1<<k); // da 0 a MAX_POPULATION
+ }
+ }
+ x->population[i][j]=tmp;
+ }
+ if (DEBUG)
+ post("inizializzo population[%i] = %i%i%i%i",
+ i,
+ x->population[i][0],
+ x->population[i][1],
+ x->population[i][2],
+ x->population[i][3]
+ );
+ }
+}
+
+void GArhythm_init_buf(t_float *buf)
+{
+ int i;
+ for (i=0; i<sizeof(buf); i++)
+ {
+ buf[i] = 0;
+ }
+}
+
+void GArhythm_allocate_buffers(t_GArhythm *x)
+{
+// x->buf_strum1 = (t_float *)getbytes(BUFFER_LENGHT * sizeof(t_float));
+// x->buf_strum2 = (t_float *)getbytes(BUFFER_LENGHT * sizeof(t_float));
+// GArhythm_init_buf(x->buf_strum1);
+// GArhythm_init_buf(x->buf_strum2);
+
+}
+
+void GArhythm_free(t_GArhythm *x)
+{
+// freebytes(x->buf_strum1, sizeof(x->buf_strum1));
+// freebytes(x->buf_strum2, sizeof(x->buf_strum2));
+}
+
+// returns fitness: how similar are man and woman
+static double GArhythm_evaluate_fitness1(char *woman, char *man)
+{
+ int res=0;
+ int max = BUFFER_LENGHT*2;
+ int i;
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ if (woman[i] == man[i])
+ res++;
+ }
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ if ((woman[i]!= 0) && (man[i] != 0))
+ res++;
+ if ((woman[i]== 0) && (man[i] == 0))
+ res++;
+ }
+ return res/max;
+}
+
+// riempimento
+static double GArhythm_evaluate_fitness2(char *woman, char *man)
+{
+ int i, j, max;
+ double ris=0;
+ max = BUFFER_LENGHT * NUM_STRUM;
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ for (j=0; j<NUM_STRUM; j++)
+ {
+ if (man[i] & (0x01<<j))
+ ris++;
+ }
+ }
+ return ris/max;
+
+}
+
+// similarities TODO
+static double GArhythm_evaluate_fitness3(char *woman, char *man)
+{
+ int i;
+ short int global1[BUFFER_LENGHT];
+ short int global2[BUFFER_LENGHT];
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ if (woman[i] != 0x00)
+ global1[i]=1;
+ else
+ global1[i]=0;
+ if (man[i] != 0x00)
+ global2[i]=1;
+ else
+ global2[i]=0;
+
+ }
+ // TODO
+ return 0;
+}
+
+
+static void GArhythm_create_child(t_GArhythm *x, char *woman, char *man, char *child)
+{
+ double rnd;
+ int split, i, j, tmp;
+ // crossover
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < x->prob_crossover)
+ {
+ split =(int) ( rnd * BUFFER_LENGHT); // da 0 a MAX_POPULATION
+ for (i=0; i< split; i++)
+ {
+ child[i] = woman[i];
+ }
+ for (i=split; i<BUFFER_LENGHT; i++)
+ {
+ child[i] = man[i];
+ }
+ // TODO: vertical split (some instr from mammy, some from daddy)
+ }else
+ {
+ for (i=0; i< BUFFER_LENGHT; i++)
+ {
+ child[i] = woman[i];
+ }
+ }
+ // mutation
+ for (i=0; i< BUFFER_LENGHT; i++)
+ {
+ // per ogni battito
+ for (j=0; j<NUM_STRUM; j++)
+ {
+ // per ogni strumento
+ tmp = child[i] & (0x01<<j); // tmp > 0 se è presente il battito là
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < x->prob_mutation)
+ {
+ if (DEBUG)
+ post("mutazione al battito %i allo strumento %i", i, j);
+ if (tmp)
+ {
+ child[i] = child[i] & (~(0x01<<j)); // tolgo il bit
+ } else
+ {
+ child[i] = child[i] | (0x01<<j); // aggiungo il bit
+ }
+ }
+ }
+ }
+ if (DEBUG)
+ post("generato figlio %i %i %i %i tra %i %i %i %i e %i %i %i %i, split=%i",
+ child[0], child[1], child[2], child[3],
+ woman[0], woman[1], woman[2], woman[3],
+ man[0], man[1], man[2], man[3],
+ split);
+
+}
+
+static void GArhythm_bang(t_GArhythm *x) {
+
+ int i, j, vecsize, ntot, tmp, me;
+ float prob, variatore;
+ t_garray *arysrc_strum1;
+ t_garray *arysrc_strum2;
+ t_garray *arysrc_strum3;
+ t_garray *arysrc_strum4;
+ t_garray *arydest_strum1;
+ t_garray *arydest_strum2;
+ t_garray *arydest_strum3;
+ t_garray *arydest_strum4;
+ t_float *vecsrc_strum1;
+ t_float *vecsrc_strum2;
+ t_float *vecsrc_strum3;
+ t_float *vecsrc_strum4;
+ t_float *vecdest_strum1;
+ t_float *vecdest_strum2;
+ t_float *vecdest_strum3;
+ t_float *vecdest_strum4;
+ double rnd;
+ int winner;
+ double winner_fitness;
+
+ char figli[MAX_POPULATION][BUFFER_LENGHT];
+
+ // load tables
+
+ if (!(arysrc_strum1 = (t_garray *)pd_findbyclass(x->x_arrayname_src_strum1, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_strum1->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_strum1, &vecsize, &vecsrc_strum1))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_strum1->s_name);
+ }
+ else if (!(arysrc_strum2 = (t_garray *)pd_findbyclass(x->x_arrayname_src_strum2, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_strum2->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_strum2, &vecsize, &vecsrc_strum2))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_strum2->s_name);
+ }
+ else if (!(arysrc_strum3 = (t_garray *)pd_findbyclass(x->x_arrayname_src_strum3, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_strum3->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_strum3, &vecsize, &vecsrc_strum3))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_strum3->s_name);
+ }
+ else if (!(arysrc_strum4 = (t_garray *)pd_findbyclass(x->x_arrayname_src_strum4, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_strum4->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_strum4, &vecsize, &vecsrc_strum4))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_strum4->s_name);
+ }
+ else if (!(arydest_strum1 = (t_garray *)pd_findbyclass(x->x_arrayname_dest_strum1, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_strum1->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_strum1, &vecsize, &vecdest_strum1))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_strum1->s_name);
+ }
+ else if (!(arydest_strum2 = (t_garray *)pd_findbyclass(x->x_arrayname_dest_strum2, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_strum2->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_strum2, &vecsize, &vecdest_strum2))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_strum2->s_name);
+ }
+ else if (!(arydest_strum3 = (t_garray *)pd_findbyclass(x->x_arrayname_dest_strum3, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_strum3->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_strum3, &vecsize, &vecdest_strum3))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_strum3->s_name);
+ }
+ else if (!(arydest_strum4 = (t_garray *)pd_findbyclass(x->x_arrayname_dest_strum4, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_strum4->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_strum4, &vecsize, &vecdest_strum4))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_strum4->s_name);
+ }
+ else // I got arrays and data
+ {
+ // vecdest_strum2 e _strum1 contengono i valori in float degli array
+ if (DEBUG)
+ post("--------- starting process");
+
+ // uccido a caso REINSERT_SRC elementi e inserisco il ritmo src al loro posto
+ for (i=0; i<REINSERT_SRC; i++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ me = (int) (rnd * MAX_POPULATION);
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ char c = 0x00;
+ if (vecsrc_strum1[j])
+ c = c | 0x01;
+ if (vecsrc_strum2[j])
+ c = c | (0x01 << 1);
+ if (vecsrc_strum3[j])
+ c = c | (0x01 << 2);
+ if (vecsrc_strum4[j])
+ c = c | (0x01 << 3);
+ x->population[me][j]=c;
+ }
+ }
+ // uccido a caso REINSERT_LAST elementi e inserisco il last al loro posto
+ for (i=0; i<REINSERT_LAST; i++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ me = (int) (rnd * MAX_POPULATION);
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ x->population[me][j]=x->last[j];
+ }
+ }
+
+ // metà sono donne, prese a caso
+ for (i=0; i<(MAX_POPULATION/2); i++)
+ {
+ int winner=CHOIR;
+ int winner_value=0;
+ int men[CHOIR];
+ char figlio[BUFFER_LENGHT];
+ double fitness1[CHOIR];
+ double fitness2[CHOIR];
+ double fitness3[CHOIR];
+ double fitnessTOT[CHOIR];
+ rnd = rand()/((double)RAND_MAX + 1);
+ me =(int) ( rnd * MAX_POPULATION); // da 0 a MAX_POPULATION
+ // me è la donna che valuta gli uomini
+
+ if (DEBUG)
+ post("woman %i = %i %i %i %i", me, x->population[me][0], x->population[me][1], x->population[me][2], x->population[me][3]);
+
+ for (j=0; j<CHOIR; j++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ tmp =(int) ( rnd * MAX_POPULATION); // da 0 a MAX_POPULATION
+ // tmp è questo uomo
+ men[j] = tmp;
+ fitness1[j]=GArhythm_evaluate_fitness1(x->population[me], x->population[tmp]);
+ fitness2[j]=GArhythm_evaluate_fitness2(x->population[me], x->population[tmp]);
+ fitness3[j]=GArhythm_evaluate_fitness3(x->population[me], x->population[tmp]);
+ fitnessTOT[j]=fitness1[j] * (x->indice_aderenza)
+ + fitness2[j] * (x->indice_riempimento)
+ + (1 - fitness2[j]) * (1-(x->indice_riempimento))
+ + fitness3[j] * (x->indice_variazione);
+ if (winner_value <= fitnessTOT[j])
+ {
+ winner = tmp;
+ winner_value = fitnessTOT[j];
+ }
+ }
+ // winner è il maschio migliore nel coro
+ if (DEBUG)
+ post("ho scelto il maschio %i", winner);
+ // genero un figlio
+ GArhythm_create_child(x, x->population[me], x->population[winner], figlio);
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ figli[i][j] = figlio[j];
+ }
+ }
+
+ // uccido a caso metà popolazione e ci metto i nuovi nati
+ for (i=0; i<(MAX_POPULATION/2); i++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ me =(int) ( rnd * MAX_POPULATION); // da 0 a MAX_POPULATION
+ // me è chi deve morire
+
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ x->population[me][j] = figli[i][j];
+ }
+ }
+
+ // prendo il più adatto rispetto all'ultimo ritmo suonato
+ winner = 0;
+ winner_fitness = 0;
+ for(i=0; i<BUFFER_LENGHT; i++)
+ {
+ double tmp1, tmp2, tmp3, tmpTOT;
+ tmp1 = GArhythm_evaluate_fitness1(x->last, x->population[i]);
+ tmp2 = GArhythm_evaluate_fitness2(x->last, x->population[i]);
+ tmp3 = GArhythm_evaluate_fitness3(x->last, x->population[i]);
+ tmpTOT = tmp1 * (x->indice_aderenza)
+ + tmp2 * (x->indice_riempimento)
+ + (1-tmp2) * (1-(x->indice_riempimento))
+ + tmp3 * (x->indice_variazione);
+ if (tmpTOT >= winner_fitness)
+ {
+ winner_fitness = tmpTOT;
+ winner = i;
+ }
+ }
+
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ // copio il vincitor ein x->last
+ x->last[i] = x->population[winner][i];
+ // scrivo i buffer in uscita
+ vecdest_strum1[i]=((x->population[winner][i] & (0x01<<0)) ? 1 : 0);
+ vecdest_strum2[i]=((x->population[winner][i] & (0x01<<1)) ? 1 : 0);
+ vecdest_strum3[i]=((x->population[winner][i] & (0x01<<2)) ? 1 : 0);
+ vecdest_strum4[i]=((x->population[winner][i] & (0x01<<3)) ? 1 : 0);
+ }
+
+ // redraw the arrays
+ //garray_redraw(arysrc);
+ garray_redraw(arydest_strum1);
+ garray_redraw(arydest_strum2);
+ garray_redraw(arydest_strum3);
+ garray_redraw(arydest_strum4);
+
+
+ }
+}
+/*
+static void GArhythm_src(t_GArhythm *x, t_symbol *s) {
+ x->x_arrayname_src = s;
+}
+*/
+
+static void GArhythm_variazione_set(t_GArhythm *x, t_floatarg f)
+{
+ x->indice_variazione = f;
+ }
+
+static void GArhythm_aderenza_set(t_GArhythm *x, t_floatarg f)
+{
+ x->indice_aderenza = f;
+}
+
+static void GArhythm_riempimento_set(t_GArhythm *x, t_floatarg f)
+{
+ x->indice_riempimento = f;
+}
+
+static void GArhythm_crossover_set(t_GArhythm *x, t_floatarg f)
+{
+ x->prob_crossover = f;
+}
+
+static void GArhythm_mutation_set(t_GArhythm *x, t_floatarg f)
+{
+ x->prob_mutation = f;
+}
+
+static void *GArhythm_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_GArhythm *x = (t_GArhythm *)pd_new(GArhythm_class);
+ GArhythm_allocate_buffers(x);
+ GArhythm_init_pop(x);
+ // inizializzo gli indici
+ x->indice_variazione=0;
+ x->indice_riempimento=0;
+ x->indice_aderenza=0;
+ x->prob_crossover = DEF_PROB_CROSSOVER;
+ x->prob_mutation = DEF_PROB_MUTATION;
+
+
+ if (argc>0)
+ {
+ x->x_arrayname_src_strum1 = atom_getsymbolarg(0, argc, argv);
+ }
+ if (argc>1)
+ {
+ x->x_arrayname_src_strum2 = atom_getsymbolarg(1, argc, argv);
+ }
+ if (argc>2)
+ {
+ x->x_arrayname_src_strum3 = atom_getsymbolarg(2, argc, argv);
+ }
+ if (argc>3)
+ {
+ x->x_arrayname_src_strum4 = atom_getsymbolarg(3, argc, argv);
+ }
+ if (argc>4)
+ {
+ x->x_arrayname_dest_strum1 = atom_getsymbolarg(4, argc, argv);
+ }
+ if (argc>5)
+ {
+ x->x_arrayname_dest_strum2 = atom_getsymbolarg(5, argc, argv);
+ }
+ if (argc>6)
+ {
+ x->x_arrayname_dest_strum3 = atom_getsymbolarg(6, argc, argv);
+ }
+ if (argc>7)
+ {
+ x->x_arrayname_dest_strum4 = atom_getsymbolarg(7, argc, argv);
+ }
+
+ return (x);
+}
+
+void GArhythm_setup(void)
+{
+ GArhythm_class = class_new(gensym("GArhythm"), (t_newmethod)GArhythm_new,
+ (t_method)GArhythm_free, sizeof(t_GArhythm), CLASS_DEFAULT, A_GIMME, 0);
+ class_addbang(GArhythm_class, (t_method)GArhythm_bang);
+// class_addmethod(GArhythm_class, (t_method)GArhythm_src, gensym("src"),A_SYMBOL, 0);
+ class_addmethod(GArhythm_class, (t_method)GArhythm_variazione_set, gensym("variazione"), A_DEFFLOAT, 0);
+ class_addmethod(GArhythm_class, (t_method)GArhythm_riempimento_set, gensym("riempimento"), A_DEFFLOAT, 0);
+ class_addmethod(GArhythm_class, (t_method)GArhythm_aderenza_set, gensym("aderenza"), A_DEFFLOAT, 0);
+}
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..b294eaf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,40 @@
+# customize here !
+#VC="C:\Programmi\Microsoft Visual Studio .NET\Vc7"
+VC="C:\Programmi\Microsoft Visual Studio .NET\Vc7"
+PDPATH="H:\PureData\pd-0.38-3.msw\pd"
+#PDPATH="C:\Documents and Settings\Davide\Documenti\personali\pd-0.38-3.msw\pd"
+
+
+current: pd_nt distclean
+
+pd_nt: chord_melo.dll chords_memory.dll harmonizer.dll GArhythm.dll ritmo1.dll
+
+.SUFFIXES: .dll
+
+PDNTCFLAGS = /W3 /WX /O2 /G6 /DNT /DPD /nologo
+
+PDNTINCLUDE = /I. /I$(PDPATH)\tcl\include /I$(PDPATH)\src /I$(VC)\include /Iinclude
+
+PDNTLDIR = $(VC)\Lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.lib \
+ $(PDPATH)\bin\pd.lib
+
+.c.dll:
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+ link /dll /export:$*_setup $*.obj $(PDNTLIB)
+
+
+
+clean:
+ -del link.stamp
+ -del *.obj
+ -del *.lib
+ -del *.exp
+ -del *.dll
+
+distclean:
+ -del *.obj
+ -del *.lib
+ -del *.exp
diff --git a/README.txt b/README.txt
new file mode 100755
index 0000000..8ee7599
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,77 @@
+frankenstein set of externals
+
+authors:
+dmorelli: www.davidemorelli.it
+pland: www.davidcasal.com
+with the help of vatic
+
+last update:
+14-10-2005
+
+------------------- what is this?
+
+this is an attempt to build an intelligent system for realtime
+improvisation, a system that follows a human player and proposes
+rhythm, melody, chords sequences, formal structure.
+it learns the style in realtime.
+it uses various AI techniques: GA, searchs, ANN (maybe)
+
+description of files:
+
+chord_melo.c
+a GA melody generator. it takes a melody as input and evolves it over time.
+uses co-evolutionary techniques (Todd)
+
+chords_memory.c
+it is a directional graph which implements a memory of the played
+chords sequences, you can train it...
+and once trained you can ask questions like:
+in C major, from a D minor 7h where did I go most if the times?
+or
+in C major, from a D minor 7h build a chord sequence to bring me
+in D major in 4 steps using the chords sequences I used most
+
+harmonizer.c
+a GA external that build choir voicing for 5 voices:
+you pass it the midi value of each voice, starting chord, next chord
+and it outputs a list with the midi values of each voice.
+avoids hidden 8ves and 5ths.
+
+
+folders:
+
+doc/
+implementation documents, notes, logs, ideas, etc..
+patches/
+example patches, help patches, some used in performances, etc..
+aima/
+python patches not yes used but interesting for agents
+ruby/
+gridflow patches not yet used
+old/
+old not used code
+test/
+testing code, not to be used
+backup/
+previous versions
+
+
+TODO:
+
+gluer/solderer
+an external that takes the input of two or more chord_melody,
+a chord sequence and glues the melody statemets together
+to build a long complete melody.
+
+form_manager
+an external that manages the form and structure of the piece:
+decide which melody statement to use, the chord sequence to ask for, etc..
+
+various objects to detect played notes
+
+diatonic_melody.c
+same as chord_melody but without chord reference, only scale used
+(for post-tonal music non based on chords)
+
+chromatic_melo.c
+same as diatonic_melo but without any reference (for atonal music)
diff --git a/SHOWME.pd b/SHOWME.pd
new file mode 100755
index 0000000..f870d28
--- /dev/null
+++ b/SHOWME.pd
@@ -0,0 +1,30 @@
+#N canvas 63 95 785 518 12;
+#X obj 513 100 tabwrite src;
+#X obj 644 87 tabwrite dest;
+#N canvas 0 0 450 300 graph25 0;
+#X array src 16 float 1;
+#A 0 53 52 55 53 52 50 48 47 48 55 57 59 60 55 52 48;
+#X array dest 16 float 1;
+#A 0 53 50 52 38 64 46 43 41 48 64 67 67 36 55 53 57;
+#X coords 0 127 15 0 400 250 1;
+#X restore 75 32 graph;
+#X obj 572 38 tgl 15 0 empty empty START 0 -6 0 8 -258699 -1 -1 1 1
+;
+#X floatatom 550 138 5 0 0 0 - - -;
+#X floatatom 596 138 5 0 0 0 - - -;
+#X floatatom 648 137 5 0 0 0 - - -;
+#X obj 591 279 tgl 15 0 toggleSRC empty src 0 -6 0 8 -262144 -1 -1
+0 1;
+#X obj 627 279 tgl 15 0 toggleOUT empty out 0 -6 0 8 -262144 -1 -1
+1 1;
+#X obj 572 56 chord_melo_test3;
+#X floatatom 613 213 5 0 0 0 current_melo - -;
+#X connect 3 0 9 0;
+#X connect 9 0 4 0;
+#X connect 9 0 0 0;
+#X connect 9 1 1 0;
+#X connect 9 1 5 0;
+#X connect 9 2 10 0;
+#X connect 9 3 0 1;
+#X connect 9 3 1 1;
+#X connect 9 3 6 0;
diff --git a/bay.orc b/bay.orc
new file mode 100755
index 0000000..e754d31
--- /dev/null
+++ b/bay.orc
@@ -0,0 +1,418 @@
+; ================================================================
+; Header
+; ================================================================
+sr=44100
+kr=882
+ksmps=50
+nchnls=2
+
+; ================================================================
+; Globals
+; ================================================================
+zakinit 10,10
+
+; Global variable for the reverb unit
+ga1 init 0
+
+; ================================================================
+; Tables
+; ================================================================
+; Waveform for the string-pad
+iwave ftgen 1, 0, 4096, 10, 1, .5, .33, .25, .0, .1, .1, .1
+
+; Senoid required by chorus
+isine ftgen 2, 0, 4096, 10, 1
+
+
+; ================================================================
+; Instruments
+; ================================================================
+
+
+instr 1 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz1"
+kpos invalue "pos1"
+kamp invalue "amp1"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+
+instr 2 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz2"
+kpos invalue "pos2"
+kamp invalue "amp2"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+instr 3 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+ ; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz3"
+kpos invalue "pos3"
+kamp invalue "amp3"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+instr 4 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz4"
+kpos invalue "pos4"
+kamp invalue "amp4"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+
+
+
+
+; strumento senza invalue
+
+instr 9 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+ ihz = p4
+ idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+ ipos = p6
+ iamp = ampdb(idb)
+
+; modified by dmorelli
+
+;kpos invalue "pos1"
+;kamp invalue "amp1"
+;kctrl = kamp*70
+;kctrl = ampdb(kctrl)
+ ; Slow attack and release
+ kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, ihz, 1 ; audio oscillator
+ acel1 oscil kctrl, ihz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, ihz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ ippan = ipos*1.570796325 ; half of PI (radians of 90o angle)
+ ipleft = cos(ippan) ; half sign "down"
+ ipright = sin(ippan) ; half sign "up"
+ asig1 = asig*ipleft;
+ asig2 = asig*ipright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+; ================================================================
+; EFFECTS
+; ================================================================
+
+
+; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+; Chorus effect, borrowed from http://www.jlpublishing.com/Csound.htm
+; I made some of its parameters accesible trhough score
+instr 10 ;Chorus
+ ; Read input from zak
+ a1 zar 1
+ a2 zar 2
+ idlyml=p4 ;delay in milliseconds
+ k1 oscili idlyml/p5, 1, 2
+ ar1l vdelay3 a1, idlyml/5+k1, 900 ;delayed sound 1
+ ar1r vdelay3 a2, idlyml/5+k1, 900 ;delayed sound 1
+ k2 oscili idlyml/p5, .995, 2
+ ar2l vdelay3 a1, idlyml/5+k2, 700 ;delayed sound 2
+ ar2r vdelay3 a2, idlyml/5+k2, 700 ;delayed sound 2
+ k3 oscili idlyml/p5, 1.05, 2
+ ar3l vdelay3 a1, idlyml/5+k3, 700 ;delayed sound 3
+ ar3r vdelay3 a2, idlyml/5+k3, 700 ;delayed sound 3
+ k4 oscili idlyml/p5, 1, 2
+ ar4l vdelay3 a1, idlyml/5+k4, 900 ;delayed sound 4
+ ar4r vdelay3 a2, idlyml/5+k4, 900 ;delayed sound 4
+ aoutl = (a1+ar1l+ar2l+ar3l+ar4l)*.5
+ aoutr = (a2+ar1r+ar2r+ar3r+ar4r)*.5
+
+ ; To the output mixer
+ zawm aoutl, 5
+ zawm aoutr, 6
+ ; and also to the reverb unit
+ ga1 = ga1 + (aoutl+aoutr)*.5
+endin
+
+; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+; Reverb
+; 8 delay line FDN reverb, with feedback matrix based upon
+; physical modeling scattering junction of 8 lossless waveguides
+; of equal characteristic impedance. Based on Julius O. Smith III,
+; "A New Approach to Digital Reverberation using Closed Waveguide
+; Networks," Proceedings of the International Computer Music
+; Conference 1985, p. 47-53 (also available as a seperate
+; publication from CCRMA), as well as some more recent papers by
+; Smith and others.
+;
+; Coded by Sean Costello, October 1999
+instr 25 ;Reverb
+ ; Note: ga1 is the global input to the reverb.
+ afilt1 init 0
+ afilt2 init 0
+ afilt3 init 0
+ afilt4 init 0
+ afilt5 init 0
+ afilt6 init 0
+ afilt7 init 0
+ afilt8 init 0
+ idel1 = (2473.000/sr)
+ idel2 = (2767.000/sr)
+ idel3 = (3217.000/sr)
+ idel4 = (3557.000/sr)
+ idel5 = (3907.000/sr)
+ idel6 = (4127.000/sr)
+ idel7 = (2143.000/sr)
+ idel8 = (1933.000/sr)
+
+
+ igain = p4 ; gain of reverb. Adjust empirically
+ ; for desired reverb time. .6 gives
+ ; a good small "live" room sound, .8
+ ; a small hall, .9 a large hall,
+ ; .99 an enormous stone cavern.
+
+ ipitchmod = p5 ; amount of random pitch modulation
+ ; for the delay lines. 1 is the "normal"
+ ; amount, but this may be too high for
+ ; held pitches such as piano tones.
+ ; Adjust to taste.
+
+ itone = p6 ; Cutoff frequency of lowpass filters
+ ; in feedback loops of delay lines,
+ ; in Hz. Lower cutoff frequencies results
+ ; in a sound with more high-frequency
+ ; damping.
+
+ ; k1-k8 are used to add random pitch modulation to the
+ ; delay lines. Helps eliminate metallic overtones
+ ; in the reverb sound.
+ k1 randi .001, 3.1, .06
+ k2 randi .0011, 3.5, .9
+ k3 randi .0017, 1.11, .7
+ k4 randi .0006, 3.973, .3
+ k5 randi .001, 2.341, .63
+ k6 randi .0011, 1.897, .7
+ k7 randi .0017, 0.891, .9
+ k8 randi .0006, 3.221, .44
+ ; apj is used to calculate "resultant junction pressure" for
+ ; the scattering junction of 8 lossless waveguides
+ ; of equal characteristic impedance. If you wish to
+ ; add more delay lines, simply add them to the following
+ ; equation, and replace the .25 by 2/N, where N is the
+ ; number of delay lines.
+ apj = .25 * (afilt1 + afilt2 + afilt3 + afilt4 + afilt5 + afilt6 + afilt7 + afilt8)
+
+
+ adum1 delayr 1
+ adel1 deltapi idel1 + k1 * ipitchmod
+ delayw ga1 + apj - afilt1
+
+ adum2 delayr 1
+ adel2 deltapi idel2 + k2 * ipitchmod
+ delayw ga1 + apj - afilt2
+
+ adum3 delayr 1
+ adel3 deltapi idel3 + k3 * ipitchmod
+ delayw ga1 + apj - afilt3
+
+ adum4 delayr 1
+ adel4 deltapi idel4 + k4 * ipitchmod
+ delayw ga1 + apj - afilt4
+
+ adum5 delayr 1
+ adel5 deltapi idel5 + k5 * ipitchmod
+ delayw ga1 + apj - afilt5
+
+ adum6 delayr 1
+ adel6 deltapi idel6 + k6 * ipitchmod
+ delayw ga1 + apj - afilt6
+
+ adum7 delayr 1
+ adel7 deltapi idel7 + k7 * ipitchmod
+ delayw ga1 + apj - afilt7
+
+ adum8 delayr 1
+ adel8 deltapi idel8 + k8 * ipitchmod
+ delayw ga1 + apj - afilt8
+
+ ; 1st order lowpass filters in feedback
+ ; loops of delay lines.
+ afilt1 tone adel1 * igain, itone
+ afilt2 tone adel2 * igain, itone
+ afilt3 tone adel3 * igain, itone
+ afilt4 tone adel4 * igain, itone
+ afilt5 tone adel5 * igain, itone
+ afilt6 tone adel6 * igain, itone
+ afilt7 tone adel7 * igain, itone
+ afilt8 tone adel8 * igain, itone
+
+ ; The outputs of the delay lines are summed
+ ; and sent to the stereo outputs. This could
+ ; easily be modified for a 4 or 8-channel
+ ; sound system.
+ aout1 = (afilt1 + afilt3 + afilt5 + afilt7)
+ aout2 = (afilt2 + afilt4 + afilt6 + afilt8)
+ ;outs aout1, aout2
+ ; To the output mixer
+ zawm aout1, 5
+ zawm aout2, 6
+ ga1 = 0
+endin
+
+
+; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+; Output mixer
+; It applies a bass enhancement, compression and fadeout
+; to the whole piece,
+instr 30 ;Mixer
+ ; Read input from zak
+ a1 zar 5
+ a2 zar 6
+ ; Bass enhancement
+ al1 butterlp a1, 100
+ al2 butterlp a2, 100
+ a1 = al1*1.5 +a1
+ a2 = al2*1.5 +a2
+
+ ; Global amplitude shape
+ ; It applies a gain of p4 to the whole piece, and creates a
+ ; fadeout the last p5 seconds
+ kenv linseg p4, p3-p5, p4, p5, 0
+ a1=a1*kenv
+ a2=a2*kenv
+
+ ; Compression
+ a1 dam a1, 5000, 0.5, 1, 0.2, 0.1
+ a2 dam a2, 5000, 0.5, 1, 0.2, 0.1
+
+ outs a1, a2
+ zacl 0, 10
+endin
+
diff --git a/chord_melo.c b/chord_melo.c
new file mode 100755
index 0000000..975b653
--- /dev/null
+++ b/chord_melo.c
@@ -0,0 +1,1137 @@
+/*
+BUGS:
+- I had to comment out arrays re-display because it crashed my pd
+- sometimes dest_played gets filled with junk
+
+TODO:
+- now rests can't be used! change chord_melo_seq_max_min
+*/
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "m_pd.h"
+
+#define BUFFER_LENGHT 16 // lunghezza dei buffers (quanti elementi nel pattern)
+#define MAX_POPULATION 500
+#define CHOIR 20
+#define NOTES 128 // how many notes can I use ? MIDI ! #define MAX_OCTAVES 3
+
+#define DEF_PROB_CROSSOVER 0.9f
+#define DEF_PROB_MUTATION 0.03f
+#define REINSERT_SRC 2 // quanti reinserisco ad ogni ciclo usando il ritmo src
+#define REINSERT_LAST 0 // quanti reinserisco ad ogni ciclo usando l'ultimo ritmo scelto
+
+#define DEBUG 1 // messaggi di debug
+#define DEBUG_VERBOSE 0 // messaggi di debug
+
+static t_class *chord_melo_class;
+
+// 1 gene of the genome
+typedef struct _chord_melo_gene
+{
+ int chord_note; // 0-12
+ int passing_note; // from -4 to +4
+ int played; // 0 / 1
+} chord_melo_gene;
+
+// an interval between 2 genes
+typedef struct _chord_melo_interval
+{
+ int direction; // -1/0/1
+ int chord_note; // 0-12
+ int passing_note; // from -4 to +4
+} chord_melo_interval;
+
+typedef struct _chord_melo_critic
+{
+ double interval[12][9];
+} chord_melo_critic;
+
+// return the interval between 2 genes
+chord_melo_interval chord_melo_Getchord_melo_interval(chord_melo_gene *g1, chord_melo_gene *g2)
+{
+ int note1, note2;
+ chord_melo_interval res;
+ if (g1->chord_note < g2->chord_note)
+ {
+ // ascending
+ res.direction = 1;
+ } else if (g1->chord_note > g2->chord_note)
+ {
+ // descending
+ res.direction = -1;
+ } else if (g1->passing_note == g2->passing_note)
+ {
+ // unison
+ res.direction = 0;
+ } else
+ {
+ // passing note
+ if (g1->passing_note < g2->passing_note)
+ {
+ // ascending
+ res.direction = 1;
+ } else
+ {
+ // descending
+ res.direction = -1;
+ }
+ }
+ res.chord_note = g1->chord_note - g2->chord_note;
+ res.passing_note = g2->passing_note - g1->passing_note;
+ return res;
+}
+
+// fills an array of intervals with the transition in a genome
+void chord_melo_transitions(chord_melo_interval *res, chord_melo_gene *src)
+{
+ int i;
+ //chord_melo_gene *last;
+ //last = &src[0];
+ for (i=1;i<BUFFER_LENGHT;i++)
+ {
+ res[i-1] = chord_melo_Getchord_melo_interval(&src[i-1], &src[i]);
+ //last = &src[i];
+ }
+}
+
+// fills an array of integers to design the shape of a genome
+// -1 = descending, 0=unisone, 1=ascending
+void chord_melo_shape(int *res, chord_melo_gene *src)
+{
+ int i, tmp;
+ chord_melo_gene *last;
+ last = &src[0];
+ for (i=1;i<BUFFER_LENGHT;i++)
+ {
+ tmp = chord_melo_Getchord_melo_interval(last, &src[i]).chord_note;
+ if (tmp == 0)
+ {
+ tmp = chord_melo_Getchord_melo_interval(last, &src[i]).passing_note;
+ if (abs(tmp) > 1)
+ tmp = chord_melo_Getchord_melo_interval(last, &src[i]).direction;
+ }
+ //res[i-1] = chord_melo_Getchord_melo_interval(last, &src[i]).direction;
+ res[i-1] = tmp;
+ last = &src[i];
+ }
+ if (DEBUG_VERBOSE)
+ post("shape: %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
+ res[0], res[1],res[2],res[3],res[4],res[5],res[6],res[7],res[8],res[9],
+ res[10],res[11],res[12],res[13],res[14]);
+
+}
+
+// fills a 4 gene long array with a sequence
+// starting - max/min - max/min - ending
+void chord_melo_seq_max_min(chord_melo_gene *seq, chord_melo_gene *src)
+{
+ // return a 4 gene seq:
+ // seq[0] = starting
+ // seq[1] = min/max
+ // seq[2] = min/max
+ // seq[3] = end
+ int i;
+ int min_pos=0;
+ int max_pos=0;
+ int first_pos=0;
+ int last_pos=0;
+ chord_melo_interval interv;
+ chord_melo_gene curr_min = src[0];
+ chord_melo_gene curr_max = src[0];
+ for (i=1;i<BUFFER_LENGHT;i++)
+ {
+ // look for first
+ //TODO
+ // look for last
+ //TODO
+ // look for min
+ interv = chord_melo_Getchord_melo_interval(&curr_min, &src[i]);
+ if (interv.direction < 0)
+ {
+ min_pos = i;
+ curr_min = src[i];
+ }
+ // look for max
+ interv = chord_melo_Getchord_melo_interval(&curr_max, &src[i]);
+ if (interv.direction > 0)
+ {
+ max_pos = i;
+ curr_max = src[i];
+ }
+ }
+ seq[0] = src[0];
+ seq[3] = src[BUFFER_LENGHT-1];
+ if (min_pos<max_pos)
+ {
+ seq[1] = src[min_pos];
+ seq[2] = src[max_pos];
+ } else
+ {
+ seq[2] = src[min_pos];
+ seq[1] = src[max_pos];
+ }
+
+
+}
+
+// return the shape of the min/max sequence
+void chord_melo_higher_shape(int *res, chord_melo_gene *src)
+{
+ int i, tmp;
+ chord_melo_gene *last;
+ chord_melo_gene seq[4];
+ // i get the max min sequence
+ chord_melo_seq_max_min(seq, src);
+ last = &seq[0];
+ for (i=1;i<4;i++)
+ {
+ tmp = chord_melo_Getchord_melo_interval(last, &src[i]).chord_note;
+ if (tmp == 0)
+ {
+ tmp = chord_melo_Getchord_melo_interval(last, &src[i]).passing_note;
+ if (abs(tmp) > 1)
+ tmp = chord_melo_Getchord_melo_interval(last, &src[i]).direction;
+ }
+ //res[i-1] = chord_melo_Getchord_melo_interval(last, &src[i]).direction;
+ res[i-1] = tmp;
+
+ //res[i-1] = chord_melo_Getchord_melo_interval(last, &seq[i]).direction;
+ last = &seq[i];
+ }
+
+ if (DEBUG_VERBOSE)
+ post("higher shape: %i %i %i %i",
+ res[0], res[1],res[2],res[3]);
+}
+
+typedef struct _chord_melo
+{
+ t_object x_obj; // myself
+ t_symbol *x_arrayname_src_note; // where i read the current pattern
+ t_symbol *x_arrayname_src_octave; // where i read the current pattern
+ t_symbol *x_arrayname_src_passing; // where i read the current pattern
+ t_symbol *x_arrayname_src_played; // where i read the current pattern
+ t_symbol *x_arrayname_dest_note; // where i put the computed pattern
+ t_symbol *x_arrayname_dest_octave; // where i put the computed pattern
+ t_symbol *x_arrayname_dest_passing; // where i put the computed pattern
+ t_symbol *x_arrayname_dest_played;
+ // tutti gli indici vanno da 0 a 1;
+ float indice_fitness1;
+ float indice_fitness2;
+ float indice_fitness3;
+ // la popolazione array di cromosomi
+ chord_melo_gene population[MAX_POPULATION][BUFFER_LENGHT];
+ float prob_crossover;
+ float prob_mutation;
+ chord_melo_gene last[BUFFER_LENGHT];
+ chord_melo_gene last_src[BUFFER_LENGHT];
+ int init;
+ t_float *vecsrc_note;
+ t_float *vecsrc_octave;
+ t_float *vecsrc_passing;
+ t_float *vecsrc_played;
+ t_float *vecdest_note;
+ t_float *vecdest_octave;
+ t_float *vecdest_passing;
+ t_float *vecdest_played;
+ int tables_loaded;
+
+} t_chord_melo;
+
+
+// i use pointers to return more than 1 object at a time
+void chord_melo_gene2note(chord_melo_gene thisgene,
+ unsigned int *octave,
+ unsigned int *note,
+ int *alteration,
+ unsigned int *played)
+{
+ *octave = thisgene.chord_note / 3;
+ *note = thisgene.chord_note % 3;
+ *alteration = thisgene.passing_note;
+ *played = thisgene.played;
+}
+
+// passing note as a value between 0 and 2 (with octave)
+chord_melo_gene chord_melo_note2gene(unsigned int octave,
+ unsigned int note,
+ int alteration,
+ unsigned int played)
+{
+ chord_melo_gene ris;
+ ris.chord_note = note + 3*octave;
+ ris.passing_note = alteration;
+ ris.played = played;
+ return ris;
+}
+
+// passing note as a value 0-12 (without octave)
+chord_melo_gene chord_melo_note2geneB(unsigned int note,
+ int alteration,
+ unsigned int played)
+{
+ chord_melo_gene ris;
+ ris.chord_note = note;
+ ris.passing_note = alteration;
+ ris.played = played;
+ return ris;
+}
+
+// returns next passing note from src in the wanted direction, both chromatic or diatonic
+chord_melo_gene chord_melo_get_next_passing(chord_melo_gene *src, int direction, int chromatic)
+{
+ int new_note;
+ int new_octave;
+ int new_passing;
+ int origine_nota;
+ int origine_ottava;
+ int origine_passaggio;
+ chord_melo_gene res;
+ origine_nota = src->chord_note % 3;
+ origine_ottava = src->chord_note / 3;
+ origine_passaggio = src->passing_note;
+ if (chromatic)
+ {
+ if (direction < 0)
+ {
+ new_octave = origine_ottava;
+ new_note = origine_nota;
+ new_passing = origine_passaggio - 1;
+ } else
+ {
+ new_octave = origine_ottava;
+ new_note = origine_nota;
+ new_passing = origine_passaggio + 1;
+ }
+ } else
+ {
+ // diatonic
+ if (direction < 0)
+ {
+ new_octave = origine_ottava;
+ new_note = origine_nota;
+ new_passing = origine_passaggio - 2;
+ } else
+ {
+ new_octave = origine_ottava;
+ new_note = origine_nota;
+ new_passing = origine_passaggio + 2;
+ }
+ }
+ // check notes
+ if ((new_passing < -4 )&&(new_note==0))
+ {
+ new_passing += 5;
+ new_note = 2;
+ new_octave -= 1;
+ }
+ if ((new_passing < -3 )&&(new_note>0))
+ {
+ new_passing += 4;
+ new_note -= 1;
+ }
+ if ((new_passing > 4 )&&(new_note==2))
+ {
+ new_passing -= 5;
+ new_note = 0;
+ new_octave += 1;
+ }
+ if ((new_passing > 3 )&&(new_note<2))
+ {
+ new_passing -= 4;
+ new_note += 1;
+ }
+ if (new_octave < 0)
+ new_octave=0;
+
+ if (new_octave > 2)
+ new_octave=2;
+
+// if (new_octave > MAX_OCTAVES)
+// new_octave=MAX_OCTAVES;
+
+ res = chord_melo_note2gene(new_octave, new_note, new_passing, 1);
+ return res;
+}
+
+void chord_melo_fill_critic(chord_melo_critic *critic, chord_melo_gene *src)
+{
+ int i, j;
+ chord_melo_interval intervalli[BUFFER_LENGHT-1];
+ for (i=0; i<12; i++)
+ {
+ for (j=0; j<9; j++)
+ {
+ critic->interval[i][j]=0;
+ }
+ }
+ chord_melo_transitions(intervalli, src);
+ for (i=0; i<(BUFFER_LENGHT-1); i++)
+ {
+ if (critic->interval[intervalli[i].chord_note][intervalli[i].passing_note] < 0)
+ critic->interval[intervalli[i].chord_note][intervalli[i].passing_note] = 0;
+ critic->interval[intervalli[i].chord_note][intervalli[i].passing_note] =
+ critic->interval[intervalli[i].chord_note][intervalli[i].passing_note] +1;
+ }
+}
+
+double chord_melo_Todd_fitness1(chord_melo_critic *woman, chord_melo_gene *man)
+{
+
+ int i, j, res;
+ chord_melo_interval intervalli[BUFFER_LENGHT-1];
+ chord_melo_transitions(intervalli, man);
+ res = 0;
+ for (i=0; i<(BUFFER_LENGHT-1); i++)
+ {
+ res += woman->interval[intervalli[i].chord_note][intervalli[i].passing_note];
+ }
+
+ return res;
+}
+
+// fitness functions over higher shape
+double chord_melo_fitness1(chord_melo_gene *woman, chord_melo_gene *man)
+{
+ int i, res;
+ int hi_shape1[4];
+ int hi_shape2[4];
+ chord_melo_higher_shape(hi_shape1, woman);
+ chord_melo_higher_shape(hi_shape2, man);
+ res = 0;
+ for (i=0; i<4; i++)
+ {
+ if (hi_shape1[i] * hi_shape2[i]>=0)
+ {
+ // same direction
+ res += 12 - abs(hi_shape2[i] - hi_shape1[i]);
+ } else if (hi_shape1[i] * hi_shape2[i]==0)
+ {
+ // one voice moving, the other no
+ } else
+ {
+ // opposite direction
+ res -= 5;
+ }
+ }
+
+ return res;
+}
+
+// fitness functions over punctual shape
+double chord_melo_fitness2(chord_melo_gene *woman, chord_melo_gene *man)
+{
+ int i, res;
+ int shape1[BUFFER_LENGHT-1];
+ int shape2[BUFFER_LENGHT-1];
+ chord_melo_shape(shape1, woman);
+ chord_melo_shape(shape2, man);
+ res = 0;
+ for (i=0; i<4; i++)
+ {
+ if (shape1[i] * shape2[i]>=0)
+ {
+ // same direction
+ res += 12 - abs(shape2[i] - shape1[i]);
+ } else if (shape1[i] * shape2[i]==0)
+ {
+ // one voice moving, the other no
+ } else
+ {
+ // opposite direction
+ res -= 5;
+ }
+ }
+ return res;
+}
+
+
+void chord_melo_create_child(t_chord_melo *x, chord_melo_gene *woman, chord_melo_gene *man, chord_melo_gene *child)
+{
+ double rnd, rnd2;
+ int split, i, j, tmp, direction;
+ // crossover
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < x->prob_crossover)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+
+ // vertical split
+ //split =(int) ( rnd * BUFFER_LENGHT); // da 0 a MAX_POPULATION
+ split = rand() % BUFFER_LENGHT;
+ for (i=0; i< split; i++)
+ {
+ child[i] = woman[i];
+ }
+ for (i=split; i<BUFFER_LENGHT; i++)
+ {
+ child[i] = man[i];
+ }
+ }else
+ {
+ for (i=0; i< BUFFER_LENGHT; i++)
+ {
+ child[i] = woman[i];
+ }
+ }
+ // mutation
+
+ for (i=0; i< BUFFER_LENGHT; i++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < x->prob_mutation)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < 0.4)
+ {
+ int prec=6;
+ int tmp_oct;
+ int tmp_note;
+ int tmp_alt;
+ int tmp_played;
+ int interval;
+ // new chord note
+ int nuovanota = 0;
+ int nuovaplayed=0;
+ if (i>0)
+ {
+ chord_melo_gene2note(child[i-1], &tmp_oct, &tmp_note, &tmp_alt, &tmp_played);
+ prec = 3*tmp_oct + tmp_note;
+ rnd2 = rand()/((double)RAND_MAX + 1);
+ if (rnd2 < 0.3)
+ interval = 1;
+ else if (rnd2 < 0.6)
+ interval = 2;
+ else if (rnd2 < 0.8)
+ interval = 3;
+ else if (rnd2 < 0.9)
+ interval = 4;
+// else if (rnd2 < 0.95)
+// interval = 5;
+// else if (rnd2 < 0.99)
+// interval = 6;
+// else
+// interval = 7;
+ rnd2 = rand()/((double)RAND_MAX + 1);
+ if (rnd2 < 0.5)
+ interval *= -1;
+
+ nuovanota = prec + interval;
+
+ } else
+ {
+ rnd2 = rand()/((double)RAND_MAX + 1);
+ nuovanota = rnd2 * 12;
+ }
+ child[i] = chord_melo_note2gene(nuovanota / 3, nuovanota % 3, 0, 1);
+ } else if (rnd < 0.8)
+ {
+ // diatonic passing note
+ if (i>0)
+ {
+ if (child[i-1].passing_note == 0)
+ {
+ // only diatonic passing note if i come from a chord note!
+ rnd2 = rand()/((double)RAND_MAX + 1);
+ if (rnd2 < 0.5)
+ direction = -1;
+ else
+ direction = 1;
+ child[i] = chord_melo_get_next_passing(&child[i-1], direction, 0);
+ // resolve passing note
+ if (i<(BUFFER_LENGHT-1))
+ child[i+1] = chord_melo_get_next_passing(&child[i], direction, 0);
+ // shall I go on?
+ if ((i<(BUFFER_LENGHT-2)) &&
+ ((child[i-1].chord_note==2 && direction==1)||
+ (child[i-1].chord_note==0 && direction==-1)))
+ {
+ child[i+2] = chord_melo_get_next_passing(&child[i+1], direction, 0);
+ }
+
+ }
+ }
+ } else
+ {
+ // chromatic passing note
+ if (child[i-1].passing_note == 0)
+ {
+ // only diatonic passing note if i come from a chord note!
+ rnd2 = rand()/((double)RAND_MAX + 1);
+ if (rnd2 < 0.5)
+ direction = -1;
+ else
+ direction = 1;
+ child[i] = chord_melo_get_next_passing(&child[i-1], direction, 1);
+ // resolve passing note
+ if (i<(BUFFER_LENGHT-1))
+ child[i+1] = chord_melo_get_next_passing(&child[i], direction, 1);
+ // shall I go on?
+ if ((i<(BUFFER_LENGHT-2)) &&
+ ((child[i-1].chord_note==2 && direction==1)||
+ (child[i-1].chord_note==0 && direction==-1)))
+ {
+ child[i+2] = chord_melo_get_next_passing(&child[i+1], direction, 1);
+ }
+
+ }
+ }
+
+ }
+ }
+
+
+
+
+
+}
+
+
+
+// ----------------- normal external code ...
+
+
+void chord_melo_init_pop(t_chord_melo *x)
+{
+ int i, j, tmp, tmp2, k;
+ double rnd;
+ for (i=0; i<MAX_POPULATION; i++)
+ {
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //tmp = rnd * NOTES;
+ tmp = rand() % NOTES;
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //tmp2 = rnd * 12;
+ tmp2 = rand() % 12;
+ x->population[i][j] = chord_melo_note2gene(tmp2 / 3, tmp2 % 3, 0, 1);
+
+ }
+
+ }
+}
+
+
+void chord_melo_init_pop2(t_chord_melo *x)
+{
+ int i, j, tmp, tmp2, k;
+ double rnd;
+ for (i=0; i<MAX_POPULATION; i++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ //if (rnd > 0.5)
+ if (rnd > 1)
+ {
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //tmp = rnd * NOTES;
+ tmp = rand() % NOTES;
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //tmp2 = rnd * 12;
+ tmp2 = rand() % 12;
+ x->population[i][j] = chord_melo_note2gene(tmp2 / 3, tmp2 % 3, 0, 1);
+
+ }
+ } else
+ {
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ x->population[i][j] = x->last_src[j];
+ }
+
+ }
+
+ }
+
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ x->last[j] = x->last_src[j];
+ if (DEBUG)
+ post("init last[%] chord_note=%i passing_note=%i played=%i", j,
+ x->last[j].chord_note, x->last[j].passing_note, x->last[j].played);
+ // x->last[j] = x->population[0][j];
+ // x->last[i] = chord_melo_note2gene(1,1,0,1);
+ }
+
+ x->init=1;
+
+}
+
+
+void chord_melo_init_buf(t_float *buf)
+{
+ int i;
+ for (i=0; i<sizeof(buf); i++)
+ {
+ buf[i] = 0;
+ }
+}
+
+void chord_melo_allocate_buffers(t_chord_melo *x)
+{
+// x->buf_strum1 = (t_float *)getbytes(BUFFER_LENGHT * sizeof(t_float));
+// x->buf_strum2 = (t_float *)getbytes(BUFFER_LENGHT * sizeof(t_float));
+// chord_melo_init_buf(x->buf_strum1);
+// chord_melo_init_buf(x->buf_strum2);
+
+}
+
+void chord_melo_free(t_chord_melo *x)
+{
+// freebytes(x->buf_strum1, sizeof(x->buf_strum1));
+// freebytes(x->buf_strum2, sizeof(x->buf_strum2));
+}
+
+
+void chord_melo_get_tables(t_chord_melo *x) {
+
+ t_garray *arysrc_note;
+ t_garray *arysrc_octave;
+ t_garray *arysrc_passing;
+ t_garray *arysrc_played;
+ t_garray *arydest_note;
+ t_garray *arydest_octave;
+ t_garray *arydest_passing;
+ t_garray *arydest_played;
+
+ int vecsize;
+
+ // load tables
+
+ if (!(arysrc_note = (t_garray *)pd_findbyclass(x->x_arrayname_src_note, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_note->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_note, &vecsize, &(x->vecsrc_note)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_note->s_name);
+ }
+ else if (!(arysrc_octave = (t_garray *)pd_findbyclass(x->x_arrayname_src_octave, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_octave->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_octave, &vecsize, &(x->vecsrc_octave)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_octave->s_name);
+ }
+ else if (!(arysrc_passing = (t_garray *)pd_findbyclass(x->x_arrayname_src_passing, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_passing->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_passing, &vecsize, &(x->vecsrc_passing)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_passing->s_name);
+ }
+ else if (!(arysrc_played = (t_garray *)pd_findbyclass(x->x_arrayname_src_played, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src_played->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc_played, &vecsize, &(x->vecsrc_played)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src_played->s_name);
+ }
+ else if (!(arydest_note = (t_garray *)pd_findbyclass(x->x_arrayname_dest_note, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_note->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_note, &vecsize, &(x->vecdest_note)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_note->s_name);
+ }
+ else if (!(arydest_octave = (t_garray *)pd_findbyclass(x->x_arrayname_dest_octave, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_octave->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_octave, &vecsize, &(x->vecdest_octave)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_octave->s_name);
+ }
+ else if (!(arydest_passing = (t_garray *)pd_findbyclass(x->x_arrayname_dest_passing, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_passing->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_passing, &vecsize, &(x->vecdest_passing)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_note->s_name);
+ }
+ else if (!(arydest_played = (t_garray *)pd_findbyclass(x->x_arrayname_dest_played, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest_played->s_name);
+ }
+ else if (!garray_getfloatarray(arydest_played, &vecsize, &(x->vecdest_played)))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest_played->s_name);
+ }
+ else // I got arrays and data
+ {
+ // tutto ok
+ x->tables_loaded=1;
+ }
+}
+
+static void chord_melo_bang(t_chord_melo *x) {
+
+ int i, j, vecsize, ntot, tmp, me;
+ float prob, variatore;
+
+ double rnd;
+ int winner;
+ double winner_fitness;
+ double average_fitness;
+ chord_melo_gene src_genome[BUFFER_LENGHT];
+ chord_melo_gene figli[MAX_POPULATION][BUFFER_LENGHT];
+
+ //chord_melo_critic src_critic;
+ chord_melo_critic last_critic;
+
+ if (x->tables_loaded == 0)
+ {
+ chord_melo_get_tables(x);
+ }
+ else // I got arrays and data
+ {
+ if (DEBUG)
+ post("--------- starting process");
+
+ if (DEBUG)
+ post("building genome for the src melody:");
+
+ srand((unsigned int)time((time_t *)NULL));
+
+ // get src's genome
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ src_genome[i] = chord_melo_note2gene(x->vecsrc_octave[i],
+ x->vecsrc_note[i], x->vecsrc_passing[i], x->vecsrc_played[i]);
+ x->last_src[i] = src_genome[i];
+ //post("src melody: vecsrc_octave[i]=%f,vecsrc_note[i]=%f,vecsrc_passing[i]=%f",
+ // vecsrc_octave[i], vecsrc_note[i], vecsrc_passing[i]);
+
+ }
+ //return;
+
+ if (x->init==0)
+ return;
+
+ // uccido a caso REINSERT_SRC elementi e inserisco il ritmo src al loro posto
+ for (i=0; i<REINSERT_SRC; i++)
+ {
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //me = (int) (rnd * MAX_POPULATION);
+ me = rand() % MAX_POPULATION;
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ x->population[me][j]=src_genome[j];
+ }
+ }
+
+ //return;
+
+ // uccido a caso REINSERT_LAST elementi e inserisco il last al loro posto
+ for (i=0; i<REINSERT_LAST; i++)
+ {
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //me = (int) (rnd * MAX_POPULATION);
+ me = rand() % MAX_POPULATION;
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ x->population[me][j]=x->last[j];
+ }
+ }
+
+ // metà sono donne, prese a caso
+ for (i=0; i<(MAX_POPULATION/2); i++)
+ {
+ //chord_melo_critic this_chord_melo_critic;
+ int winner=0;
+ double winner_value=0;
+ int men[CHOIR];
+ chord_melo_gene figlio[BUFFER_LENGHT];
+ double fitness1[CHOIR];
+ double fitness2[CHOIR];
+ double fitness3[CHOIR];
+ double fitnessTOT[CHOIR];
+ double fitnessTodd1[CHOIR];
+ chord_melo_critic woman_critic;
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //me =(int) ( rnd * MAX_POPULATION); // da 0 a MAX_POPULATION
+ me = rand() % MAX_POPULATION;
+ // me è la donna che valuta gli uomini
+
+ if (DEBUG_VERBOSE)
+ post("woman %i = %i %i %i %i", me, x->population[me][0], x->population[me][1], x->population[me][2], x->population[me][3]);
+
+ chord_melo_fill_critic(&woman_critic, x->population[me]);
+
+ for (j=0; j<CHOIR; j++)
+ {
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //tmp =(int) ( rnd * MAX_POPULATION); // da 0 a MAX_POPULATION
+ tmp = rand() % MAX_POPULATION;
+ // tmp è questo uomo
+ men[j] = tmp;
+ if (DEBUG_VERBOSE)
+ post("i will evaluate man %i", tmp);
+ fitness1[j]=chord_melo_fitness1(x->population[me], x->population[tmp]);
+ fitness2[j]=chord_melo_fitness2(x->population[me], x->population[tmp]);
+ fitnessTodd1[j]=chord_melo_Todd_fitness1(&woman_critic, x->population[tmp]);
+ fitnessTOT[j]=fitness1[j] * (x->indice_fitness1)
+ + fitness2[j] * (x->indice_fitness2)
+ + fitnessTodd1[j] * (x->indice_fitness3);
+ if (DEBUG_VERBOSE)
+ post("man %i has fitness %i", tmp, fitnessTOT[j]);
+ if (winner_value <= fitnessTOT[j])
+ {
+ winner = tmp;
+ winner_value = fitnessTOT[j];
+ }
+ }
+ // winner è il maschio migliore nel coro
+ if (DEBUG_VERBOSE)
+ post("ho scelto il maschio %i con fitness %i", winner, winner_value);
+ // chord_melo_genero un figlio
+ chord_melo_create_child(x, x->population[me], x->population[winner], figlio);
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ figli[i][j] = figlio[j];
+ }
+ }
+
+ // uccido a caso metà popolazione e ci metto i nuovi nati
+ for (i=0; i<(MAX_POPULATION/2); i++)
+ {
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //me =(int) ( rnd * MAX_POPULATION); // da 0 a MAX_POPULATION
+ me = rand() % MAX_POPULATION;
+ // me è chi deve morire
+
+ for (j=0; j<BUFFER_LENGHT; j++)
+ {
+ x->population[me][j] = figli[i][j];
+ }
+ }
+
+ // prendo il più adatto rispetto all'ultimo ritmo suonato
+ winner = 0;
+ winner_fitness = 0;
+ average_fitness = 0;
+
+ //chord_melo_fill_critic(&src_critic, src_genome);
+ chord_melo_fill_critic(&last_critic, x->last);
+
+ for(i=0; i<MAX_POPULATION; i++)
+ {
+ double tmp1, tmp2, tmp3, tmpTOT, fitnessTodd1;
+ //tmp1 = chord_melo_fitness1(src_genome, x->population[i]);
+ //tmp2 = chord_melo_fitness2(src_genome, x->population[i]);
+ //fitnessTodd1=chord_melo_Todd_fitness1(&src_critic, x->population[i]);
+ tmp1 = chord_melo_fitness1(x->last, x->population[i]);
+ tmp2 = chord_melo_fitness2(x->last, x->population[i]);
+ fitnessTodd1=chord_melo_Todd_fitness1(&last_critic, x->population[i]);
+ tmpTOT = tmp1 * (x->indice_fitness1) +
+ tmp2 * (x->indice_fitness2) +
+ fitnessTodd1 * (x->indice_fitness3);
+
+ //post("%i fitness = %i", i, tmpTOT);
+
+ if (tmpTOT >= winner_fitness)
+ {
+ winner_fitness = tmpTOT;
+ winner = i;
+ }
+ average_fitness += tmpTOT;
+ }
+ average_fitness = average_fitness / MAX_POPULATION;
+
+ if (DEBUG)
+ post("winner is number %i with fitness=%d, average fitness = %d", winner, winner_fitness, average_fitness);
+
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ int note, played, octave, passing;
+ // copio il vincitore in x->last
+ x->last[i] = x->population[winner][i];
+ // scrivo i buffer in uscita
+ chord_melo_gene2note(x->population[winner][i],
+ &octave, &note, &passing, &played);
+ x->vecdest_note[i]=note;
+ x->vecdest_octave[i]=octave;
+ x->vecdest_passing[i]=passing;
+ x->vecdest_played[i]=(played > 0 ? 1 : 0);
+ if (DEBUG)
+ post("winner[%i] chord_note=%i, octave=%i, passing=%i, played=%i",
+ i, note, octave, passing, played);
+ }
+
+ //return;
+
+ // redraw the arrays
+/* garray_redraw(arydest_note);
+ garray_redraw(arydest_octave);
+ garray_redraw(arydest_passing);
+ garray_redraw(arydest_played);
+*/
+
+ }
+}
+
+void chord_melo_src_note(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_src_note = s;
+}
+
+void chord_melo_src_octave(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_src_octave = s;
+}
+
+void chord_melo_src_passing(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_src_passing = s;
+}
+
+void chord_melo_src_played(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_src_played = s;
+}
+
+void chord_melo_dest_note(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_dest_note = s;
+}
+
+void chord_melo_dest_octave(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_dest_octave = s;
+}
+
+void chord_melo_dest_passing(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_dest_passing = s;
+}
+
+void chord_melo_dest_played(t_chord_melo *x, t_symbol *s) {
+ x->x_arrayname_dest_played = s;
+}
+
+
+void chord_melo_fitness1_set(t_chord_melo *x, t_floatarg f)
+{
+ x->indice_fitness1 = f;
+ }
+
+void chord_melo_fitness2_set(t_chord_melo *x, t_floatarg f)
+{
+ x->indice_fitness2 = f;
+}
+
+void chord_melo_fitness3_set(t_chord_melo *x, t_floatarg f)
+{
+ x->indice_fitness3 = f;
+}
+
+void chord_melo_crossover_set(t_chord_melo *x, t_floatarg f)
+{
+ x->prob_crossover = f;
+}
+
+void chord_melo_mutation_set(t_chord_melo *x, t_floatarg f)
+{
+ x->prob_mutation = f;
+}
+
+/*
+void chord_melo_init(t_chord_melo *x, t_symbol *s) {
+ chord_melo_init_pop2(x);
+}
+*/
+
+void *chord_melo_new(t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ time_t a;
+ t_chord_melo *x = (t_chord_melo *)pd_new(chord_melo_class);
+ chord_melo_allocate_buffers(x);
+ chord_melo_init_pop(x);
+ // inizializzo gli indici
+ x->indice_fitness1=0;
+ x->indice_fitness2=0;
+ x->indice_fitness3=0;
+ x->prob_crossover = DEF_PROB_CROSSOVER;
+ x->prob_mutation = DEF_PROB_MUTATION;
+ x->init=0;
+ x->tables_loaded=0;
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ x->last[i] = chord_melo_note2gene(1,0,0,1);
+ }
+ srand(time(&a));
+
+ if (argc>0)
+ {
+ x->x_arrayname_src_note = atom_getsymbolarg(0, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_src_note=%s",x->x_arrayname_src_note->s_name);
+ }
+ if (argc>1)
+ {
+ x->x_arrayname_src_octave = atom_getsymbolarg(1, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_src_octave=%s",x->x_arrayname_src_octave->s_name);
+ }
+ if (argc>2)
+ {
+ x->x_arrayname_src_passing = atom_getsymbolarg(2, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_src_passing=%s",x->x_arrayname_src_passing->s_name);
+ }
+ if (argc>3)
+ {
+ x->x_arrayname_src_played = atom_getsymbolarg(3, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_src_played=%s",x->x_arrayname_src_played->s_name);
+ }
+ if (argc>4)
+ {
+ x->x_arrayname_dest_note = atom_getsymbolarg(4, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_dest_note=%s",x->x_arrayname_dest_note->s_name);
+ }
+ if (argc>5)
+ {
+ x->x_arrayname_dest_octave = atom_getsymbolarg(5, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_dest_octave=%s",x->x_arrayname_dest_octave->s_name);
+ }
+ if (argc>6)
+ {
+ x->x_arrayname_dest_passing = atom_getsymbolarg(6, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_dest_passing=%s",x->x_arrayname_dest_passing->s_name);
+ }
+ if (argc>7)
+ {
+ x->x_arrayname_dest_played = atom_getsymbolarg(7, argc, argv);
+ if (DEBUG)
+ post("x->x_arrayname_dest_played=%s",x->x_arrayname_dest_played->s_name);
+ }
+ return (x);
+}
+
+void chord_melo_setup(void)
+{
+ chord_melo_class = class_new(gensym("chord_melo"), (t_newmethod)chord_melo_new,
+ (t_method)chord_melo_free, sizeof(t_chord_melo), CLASS_DEFAULT, A_GIMME, 0);
+ class_addbang(chord_melo_class, (t_method)chord_melo_bang);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_src_note, gensym("src_note"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_src_octave, gensym("src_octave"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_src_passing, gensym("src_passing"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_src_played, gensym("src_played"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_dest_note, gensym("dest_note"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_dest_octave, gensym("dest_octave"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_dest_passing, gensym("dest_passing"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_dest_played, gensym("dest_played"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_fitness1_set, gensym("fitness1"), A_DEFFLOAT, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_fitness2_set, gensym("fitness2"), A_DEFFLOAT, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_fitness3_set, gensym("fitness3"), A_DEFFLOAT, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_init_pop2, gensym("init"),A_SYMBOL, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_mutation_set, gensym("mutation"), A_DEFFLOAT, 0);
+ class_addmethod(chord_melo_class, (t_method)chord_melo_crossover_set, gensym("crossover"), A_DEFFLOAT, 0);
+
+}
diff --git a/chord_melo_test3.pd b/chord_melo_test3.pd
new file mode 100755
index 0000000..4b5185a
--- /dev/null
+++ b/chord_melo_test3.pd
@@ -0,0 +1,630 @@
+#N canvas 204 24 1015 713 12;
+#X obj 620 131 metro;
+#N canvas 1 23 466 316 msecs 0;
+#X obj 58 19 inlet;
+#X obj 61 209 outlet;
+#X obj 57 147 /;
+#X obj 57 100 bang;
+#X obj 73 79 t f f;
+#X obj 57 174 / 4;
+#X msg 57 122 60000;
+#X connect 0 0 4 0;
+#X connect 2 0 5 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 4 1 2 1;
+#X connect 5 0 1 0;
+#X connect 6 0 2 0;
+#X restore 684 102 pd msecs;
+#X obj 683 28 loadbang;
+#X obj 620 108 tgl 15 0 empty empty empty 0 -6 0 8 -258699 -1 -1 0
+1;
+#N canvas 0 22 498 348 graph2 0;
+#X obj 122 9 inlet;
+#X obj 362 255 outlet;
+#X obj 171 33 int;
+#X obj 204 31 + 1;
+#X obj 185 57 % 4;
+#X obj 168 78 sel 0;
+#X obj 168 105 bng 15 250 50 0 empty empty beat 0 -6 0 8 -262144 -1
+-1;
+#X obj 263 86 sel 0;
+#X obj 264 108 bng 15 250 50 0 empty empty bar 0 -6 0 8 -262144 -1
+-1;
+#X obj 262 63 % 16;
+#X obj 69 278 hradio 10 1 0 16 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X obj 70 64 / 2;
+#X obj 71 87 int;
+#X obj 72 111 hradio 10 1 0 2 empty empty 1/8 0 -6 0 8 -262144 -1 -1
+0;
+#X obj 342 78 int;
+#X obj 73 220 hradio 10 1 0 4 empty empty 1/4 0 -6 0 8 -262144 -1 -1
+0;
+#X obj 341 55 / 4;
+#X obj 70 167 hradio 10 1 0 4 empty empty 1/16 0 -6 0 8 -262144 -1
+-1 0;
+#X connect 0 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 2 1;
+#X connect 3 0 4 0;
+#X connect 3 0 9 0;
+#X connect 4 0 5 0;
+#X connect 4 0 17 0;
+#X connect 4 0 11 0;
+#X connect 5 0 6 0;
+#X connect 7 0 8 0;
+#X connect 9 0 7 0;
+#X connect 9 0 10 0;
+#X connect 9 0 16 0;
+#X connect 9 0 1 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 14 0 15 0;
+#X connect 16 0 14 0;
+#X coords 0 1 100 -1 200 140 1;
+#X restore 379 92 graph;
+#X floatatom 706 127 5 0 0 0 - - -;
+#X obj 632 169 delay;
+#X obj 667 148 / 2;
+#X text 296 172 this delay is to center the quantization;
+#X obj 685 78 nbx 5 14 30 1000 0 0 empty empty empty 0 -6 0 10 -258699
+-1 -1 120 256;
+#X text 29 30 test1: detect rhythmic pattern and proposes a counterpoint
+;
+#N canvas 0 22 458 308 valori 0;
+#X obj 57 40 inlet;
+#X obj 136 42 inlet;
+#X obj 229 42 inlet;
+#X obj 58 215 outlet;
+#X msg 60 112 fitness1 \$1;
+#X msg 136 74 fitness2 \$1;
+#X msg 231 133 fitness3 \$1;
+#X connect 0 0 4 0;
+#X connect 1 0 5 0;
+#X connect 2 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 0;
+#X restore 713 532 pd valori;
+#X obj 713 378 vsl 15 128 0 1 0 0 empty empty 1st 0 -8 0 8 -262144
+-1 -1 12700 1;
+#X obj 760 380 vsl 15 128 0 1 0 0 empty empty 2nd 0 -8 0 8 -262144
+-1 -1 12700 1;
+#X obj 800 383 vsl 15 128 0 1 0 0 empty empty 3rd 0 -8 0 8 -262144
+-1 -1 12700 1;
+#X floatatom 700 515 5 0 0 0 - - -;
+#X floatatom 750 513 5 0 0 0 - - -;
+#X floatatom 800 522 5 0 0 0 - - -;
+#X obj 719 49 s sampleinit;
+#X obj 726 294 loadbang;
+#N canvas 105 213 716 372 initMelody 0;
+#X obj 79 28 loadbang;
+#X msg 18 132 \; src_played const 1 \;;
+#X msg 29 261 \; src_passing const 0 \;;
+#X msg 260 69 \; src_note 0 0 1 2 2 1 1 0 0 0 2 2 2 0 2 1 0 \;;
+#X msg 235 143 \; src_passing 0 0 0 0 -2 0 -2 0 -1 0 0 2 4 0 0 0 0
+\;;
+#X msg 247 107 \; src_octave 0 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 \;;
+#X connect 0 0 3 0;
+#X connect 0 0 1 0;
+#X connect 0 0 5 0;
+#X connect 0 0 4 0;
+#X restore 57 108 pd initMelody;
+#X obj 153 586 noteout;
+#X obj 153 562 makenote;
+#X msg 238 539 60;
+#X msg 270 539 100;
+#X obj 244 517 loadbang;
+#X msg 684 49 120;
+#X msg 712 328 1;
+#X obj 770 119 table src_octave;
+#X obj 769 96 table src_note;
+#X obj 770 141 table src_passing;
+#X obj 770 165 table src_played;
+#N canvas 14 41 980 629 play_melody 0;
+#X obj 58 50 t f f f f;
+#X obj 58 116 tabread dest_note;
+#X obj 225 79 tabread dest_octave;
+#X obj 186 153 tabread dest_passing;
+#X obj 2 290 tabread dest_played;
+#X obj 1 315 select 1;
+#X obj 259 -4 inlet;
+#X obj 659 8 inlet;
+#X floatatom 710 68 5 0 0 0 - - -;
+#X text 729 52 base midi note;
+#X obj 225 103 * 12;
+#X obj 57 144 select 0 1 2;
+#X msg 57 186 0;
+#X msg 103 184 4;
+#X msg 150 185 7;
+#X obj 159 266 +;
+#X obj 170 303 +;
+#X obj 180 344 + 36;
+#X text 245 344 default C;
+#X obj 275 535 outlet;
+#X floatatom 204 390 5 0 0 0 - - -;
+#X obj 95 451 int 0;
+#X obj 2 339 bang;
+#X obj 435 50 t f f f f;
+#X obj 372 332 select 1;
+#X obj 596 120 * 12;
+#X obj 428 161 select 0 1 2;
+#X msg 428 203 0;
+#X msg 474 201 4;
+#X msg 521 202 7;
+#X obj 530 283 +;
+#X obj 541 320 +;
+#X obj 551 361 + 36;
+#X text 616 361 default C;
+#X floatatom 575 407 5 0 0 0 - - -;
+#X obj 466 468 int 0;
+#X obj 373 356 bang;
+#X obj 373 307 tabread dest_played2;
+#X obj 429 133 tabread dest_note2;
+#X obj 596 96 tabread dest_octave2;
+#X obj 557 170 tabread dest_passing2;
+#X obj 883 242 inlet;
+#X obj 235 491 spigot;
+#X msg 221 455 1;
+#X msg 256 456 0;
+#X obj 318 492 spigot;
+#X msg 297 455 1;
+#X msg 332 456 0;
+#X obj 258 19 t f f;
+#X obj 247 430 select 0 1;
+#X floatatom 373 533 5 0 0 0 - - -;
+#X floatatom 195 539 5 0 0 0 - - -;
+#X connect 0 0 4 0;
+#X connect 0 1 1 0;
+#X connect 0 2 3 0;
+#X connect 0 3 2 0;
+#X connect 1 0 11 0;
+#X connect 2 0 10 0;
+#X connect 3 0 15 1;
+#X connect 4 0 5 0;
+#X connect 5 0 22 0;
+#X connect 6 0 48 0;
+#X connect 7 0 8 0;
+#X connect 7 0 17 1;
+#X connect 7 0 32 1;
+#X connect 10 0 16 1;
+#X connect 11 0 12 0;
+#X connect 11 1 13 0;
+#X connect 11 2 14 0;
+#X connect 12 0 15 0;
+#X connect 13 0 15 0;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 20 0;
+#X connect 17 0 21 1;
+#X connect 21 0 42 0;
+#X connect 22 0 21 0;
+#X connect 23 0 37 0;
+#X connect 23 1 38 0;
+#X connect 23 2 40 0;
+#X connect 23 3 39 0;
+#X connect 24 0 36 0;
+#X connect 25 0 31 1;
+#X connect 26 0 27 0;
+#X connect 26 1 28 0;
+#X connect 26 2 29 0;
+#X connect 27 0 30 0;
+#X connect 28 0 30 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 0;
+#X connect 31 0 32 0;
+#X connect 32 0 34 0;
+#X connect 32 0 35 1;
+#X connect 35 0 45 0;
+#X connect 36 0 35 0;
+#X connect 37 0 24 0;
+#X connect 38 0 26 0;
+#X connect 39 0 25 0;
+#X connect 40 0 30 1;
+#X connect 41 0 49 0;
+#X connect 42 0 19 0;
+#X connect 42 0 51 0;
+#X connect 43 0 42 1;
+#X connect 44 0 45 1;
+#X connect 45 0 19 0;
+#X connect 45 0 50 0;
+#X connect 46 0 45 1;
+#X connect 47 0 42 1;
+#X connect 48 0 0 0;
+#X connect 48 1 23 0;
+#X connect 49 0 43 0;
+#X connect 49 0 44 0;
+#X connect 49 1 46 0;
+#X connect 49 1 47 0;
+#X restore 153 432 pd play_melody;
+#X floatatom 264 313 5 0 0 0 base_midi_note - -;
+#N canvas 80 41 790 533 test_src_melody 0;
+#X obj 64 33 t f f f f;
+#X obj -17 299 select 1;
+#X obj 67 3 inlet;
+#X obj 418 160 inlet;
+#X floatatom 442 209 5 0 0 0 - - -;
+#X text 461 193 base midi note;
+#X obj 268 125 * 12;
+#X obj 57 144 select 0 1 2;
+#X msg 57 186 0;
+#X msg 103 184 4;
+#X msg 150 185 7;
+#X obj 159 266 +;
+#X obj 170 303 +;
+#X obj 180 344 + 36;
+#X text 245 344 default C;
+#X obj 120 482 outlet;
+#X floatatom 204 390 5 0 0 0 - - -;
+#X obj 116 450 int 0;
+#X obj -16 323 bang;
+#X obj -16 274 tabread src_played;
+#X obj 58 116 tabread src_note;
+#X obj 267 102 tabread src_octave;
+#X obj 186 153 tabread src_passing;
+#X connect 0 0 19 0;
+#X connect 0 1 20 0;
+#X connect 0 2 22 0;
+#X connect 0 3 21 0;
+#X connect 1 0 18 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 3 0 13 1;
+#X connect 6 0 12 1;
+#X connect 7 0 8 0;
+#X connect 7 1 9 0;
+#X connect 7 2 10 0;
+#X connect 8 0 11 0;
+#X connect 9 0 11 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 13 0 16 0;
+#X connect 13 0 17 1;
+#X connect 17 0 15 0;
+#X connect 18 0 17 0;
+#X connect 19 0 1 0;
+#X connect 20 0 7 0;
+#X connect 21 0 6 0;
+#X connect 22 0 11 1;
+#X restore 26 383 pd test_src_melody;
+#N canvas 0 22 462 312 chords 0;
+#X obj 146 45 select 0;
+#X obj 147 17 inlet;
+#X obj 150 255 outlet;
+#X msg 123 193 36;
+#X msg 177 193 41;
+#X msg 232 191 36;
+#X msg 286 191 43;
+#X obj 142 96 int 0;
+#X obj 144 69 bang;
+#X obj 202 99 + 1;
+#X obj 141 122 % 4;
+#X obj 137 147 select 0 1 2 3;
+#X connect 0 0 8 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 9 0;
+#X connect 7 0 10 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 1;
+#X connect 10 0 11 0;
+#X connect 11 0 3 0;
+#X connect 11 1 4 0;
+#X connect 11 2 5 0;
+#X connect 11 3 6 0;
+#X restore 265 290 pd chords;
+#X obj 102 619 outlet;
+#X obj 14 619 outlet;
+#X obj 569 246 outlet;
+#X obj 379 233 t a a a a;
+#X obj 607 56 inlet;
+#X obj 80 181 tgl 15 0 toggleSRC empty src 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 78 215 tgl 15 0 toggleOUT empty out 0 -6 0 8 -262144 -1 -1 0
+1;
+#N canvas 0 22 650 510 toggle 0;
+#X obj 170 119 r toggleSRC;
+#X obj 136 144 int 0;
+#X obj 136 168 select 1;
+#X obj 137 192 bang;
+#X obj 154 20 inlet;
+#X obj 197 270 outlet;
+#X obj 203 231 int 0;
+#X obj 86 104 bang;
+#X obj 201 60 t a a;
+#X connect 0 0 1 1;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 6 0;
+#X connect 4 0 8 0;
+#X connect 6 0 5 0;
+#X connect 7 0 1 0;
+#X connect 8 0 7 0;
+#X connect 8 1 6 1;
+#X restore 33 414 pd toggle;
+#N canvas 0 22 662 522 toggle 0;
+#X obj 136 144 int 0;
+#X obj 136 168 select 1;
+#X obj 137 192 bang;
+#X obj 154 20 inlet;
+#X obj 197 270 outlet;
+#X obj 203 231 int 0;
+#X obj 86 104 bang;
+#X obj 201 60 t a a;
+#X obj 170 119 r toggleOUT;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 3 0 7 0;
+#X connect 5 0 4 0;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 7 1 5 1;
+#X connect 8 0 0 1;
+#X restore 155 495 pd toggle;
+#N canvas 0 22 778 359 read-tables 0;
+#X obj 93 110 tabread dest_note;
+#X floatatom 96 147 5 0 0 0 - - -;
+#X floatatom 341 44 5 0 0 0 - - -;
+#X floatatom 244 147 5 0 0 0 - - -;
+#X floatatom 388 146 5 0 0 0 - - -;
+#X floatatom 532 143 5 0 0 0 - - -;
+#X obj 243 91 tabread dest_octave;
+#X obj 386 109 tabread dest_passing;
+#X obj 529 89 tabread dest_played;
+#X obj 514 175 print;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 2 0 6 0;
+#X connect 2 0 7 0;
+#X connect 2 0 8 0;
+#X connect 6 0 3 0;
+#X connect 7 0 4 0;
+#X connect 8 0 5 0;
+#X connect 8 0 9 0;
+#X restore 847 310 pd read-tables;
+#X msg 866 529 mutation \$1;
+#X msg 883 549 crossover \$1;
+#X obj 865 373 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 0 1;
+#X obj 899 371 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 0 1;
+#X floatatom 845 507 5 0 0 0 - - -;
+#X floatatom 900 505 5 0 0 0 - - -;
+#X msg 791 327 1;
+#N canvas 0 22 923 490 chord_melo1 0;
+#X obj 94 49 inlet;
+#X obj 349 58 inlet;
+#X obj 123 264 bang;
+#X obj 140 116 select 0;
+#X obj 185 256 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 191 187 int 0;
+#X obj 240 188 + 1;
+#X floatatom 191 211 5 0 0 0 generation - -;
+#X obj 191 164 bang;
+#X msg 23 270 init a;
+#X obj 22 227 select 1;
+#X obj 23 248 bang;
+#X obj 222 344 chord_melo src_note src_octave src_passing src_played
+dest_note dest_octave dest_passing dest_played;
+#X obj 415 139 table dest_note;
+#X obj 416 162 table dest_octave;
+#X obj 415 184 table dest_passing;
+#X obj 415 208 table dest_played;
+#X connect 0 0 3 0;
+#X connect 1 0 12 0;
+#X connect 2 0 12 0;
+#X connect 3 0 2 0;
+#X connect 3 0 8 0;
+#X connect 4 0 12 0;
+#X connect 5 0 6 0;
+#X connect 5 0 7 0;
+#X connect 5 0 10 0;
+#X connect 6 0 5 1;
+#X connect 8 0 5 0;
+#X connect 9 0 12 0;
+#X connect 10 0 11 0;
+#X connect 11 0 9 0;
+#X restore 667 589 pd chord_melo1;
+#N canvas 0 22 923 490 chord_melo2 0;
+#X obj 94 49 inlet;
+#X obj 349 58 inlet;
+#X obj 123 264 bang;
+#X obj 140 116 select 0;
+#X obj 185 256 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 191 187 int 0;
+#X obj 240 188 + 1;
+#X floatatom 191 211 5 0 0 0 generation - -;
+#X obj 191 164 bang;
+#X msg 23 270 init a;
+#X obj 22 227 select 1;
+#X obj 23 248 bang;
+#X obj 415 139 table dest_note2;
+#X obj 416 162 table dest_octave2;
+#X obj 415 184 table dest_passing2;
+#X obj 415 208 table dest_played2;
+#X obj 222 344 chord_melo src_note src_octave src_passing src_played
+dest_note2 dest_octave2 dest_passing2 dest_played2;
+#X connect 0 0 3 0;
+#X connect 1 0 16 0;
+#X connect 2 0 16 0;
+#X connect 3 0 2 0;
+#X connect 3 0 8 0;
+#X connect 4 0 16 0;
+#X connect 5 0 6 0;
+#X connect 5 0 7 0;
+#X connect 5 0 10 0;
+#X connect 6 0 5 1;
+#X connect 8 0 5 0;
+#X connect 9 0 16 0;
+#X connect 10 0 11 0;
+#X connect 11 0 9 0;
+#X restore 473 628 pd chord_melo2;
+#X obj 339 336 manager;
+#N canvas 0 22 698 589 sum 0;
+#X obj 116 64 inlet;
+#X obj 150 338 outlet;
+#X obj 278 36 inlet;
+#X obj 265 72 select 0;
+#X obj 264 124 int 0;
+#X obj 312 123 + 1;
+#X obj 266 96 bang;
+#X obj 86 202 spigot;
+#X obj 147 203 int;
+#X obj 104 236 + 0;
+#X obj 124 99 t f f;
+#X obj 211 126 bang;
+#X text 383 222 not working yet;
+#X text 337 254 it should join the two statements;
+#X text 326 277 join means make the first interval small;
+#X text 400 192 TODO;
+#X obj 204 295 spigot;
+#X obj 251 201 bang;
+#X msg 246 223 1;
+#X obj 257 247 -;
+#X obj 253 177 t a a;
+#X obj 254 147 % 2;
+#X connect 0 0 10 0;
+#X connect 2 0 3 0;
+#X connect 3 0 6 0;
+#X connect 3 0 11 0;
+#X connect 4 0 5 0;
+#X connect 4 0 21 0;
+#X connect 5 0 4 1;
+#X connect 6 0 4 0;
+#X connect 7 0 9 0;
+#X connect 8 0 9 1;
+#X connect 9 0 1 0;
+#X connect 10 0 8 1;
+#X connect 10 0 7 0;
+#X connect 10 1 16 0;
+#X connect 11 0 8 0;
+#X connect 16 0 1 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 19 0 16 1;
+#X connect 20 0 17 0;
+#X connect 20 1 19 1;
+#X connect 21 0 20 0;
+#X connect 21 0 7 1;
+#X restore 224 468 pd sum;
+#N canvas 0 22 458 308 valori 0;
+#X obj 57 40 inlet;
+#X obj 136 42 inlet;
+#X obj 229 42 inlet;
+#X obj 58 215 outlet;
+#X msg 60 112 fitness1 \$1;
+#X msg 136 74 fitness2 \$1;
+#X msg 231 133 fitness3 \$1;
+#X connect 0 0 4 0;
+#X connect 1 0 5 0;
+#X connect 2 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 0;
+#X restore 511 539 pd valori;
+#X obj 511 385 vsl 15 128 0 1 0 0 empty empty 1st 0 -8 0 8 -262144
+-1 -1 12700 1;
+#X obj 558 387 vsl 15 128 0 1 0 0 empty empty 2nd 0 -8 0 8 -262144
+-1 -1 12700 1;
+#X obj 598 390 vsl 15 128 0 1 0 0 empty empty 3rd 0 -8 0 8 -262144
+-1 -1 12700 1;
+#X floatatom 498 522 5 0 0 0 - - -;
+#X floatatom 548 520 5 0 0 0 - - -;
+#X floatatom 598 529 5 0 0 0 - - -;
+#X obj 524 301 loadbang;
+#X msg 510 335 1;
+#X msg 589 334 1;
+#X msg 423 568 mutation \$1;
+#X msg 440 588 crossover \$1;
+#X obj 422 412 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 0 1;
+#X obj 456 410 vsl 15 128 0 1 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 0 1;
+#X floatatom 402 546 5 0 0 0 - - -;
+#X floatatom 457 544 5 0 0 0 - - -;
+#X floatatom 344 439 5 0 0 0 - - -;
+#X obj 304 614 outlet;
+#X connect 0 0 6 0;
+#X connect 1 0 0 1;
+#X connect 1 0 5 0;
+#X connect 1 0 7 0;
+#X connect 2 0 26 0;
+#X connect 2 0 18 0;
+#X connect 3 0 0 0;
+#X connect 4 0 39 0;
+#X connect 6 0 4 0;
+#X connect 7 0 6 1;
+#X connect 9 0 1 0;
+#X connect 11 0 53 1;
+#X connect 12 0 11 0;
+#X connect 12 0 15 0;
+#X connect 13 0 11 1;
+#X connect 13 0 16 0;
+#X connect 14 0 11 2;
+#X connect 14 0 17 0;
+#X connect 19 0 27 0;
+#X connect 19 0 52 0;
+#X connect 22 0 21 0;
+#X connect 22 1 21 1;
+#X connect 23 0 22 1;
+#X connect 24 0 22 2;
+#X connect 25 0 24 0;
+#X connect 25 0 23 0;
+#X connect 26 0 9 0;
+#X connect 27 0 12 0;
+#X connect 27 0 13 0;
+#X connect 32 0 36 0;
+#X connect 32 0 44 0;
+#X connect 33 0 34 1;
+#X connect 33 0 32 1;
+#X connect 34 0 37 0;
+#X connect 34 0 43 0;
+#X connect 35 0 33 0;
+#X connect 39 1 32 0;
+#X connect 39 1 34 0;
+#X connect 39 2 35 0;
+#X connect 39 2 53 0;
+#X connect 39 2 54 0;
+#X connect 39 3 38 0;
+#X connect 39 3 55 0;
+#X connect 39 3 56 1;
+#X connect 40 0 3 0;
+#X connect 43 0 22 0;
+#X connect 44 0 22 0;
+#X connect 46 0 53 1;
+#X connect 47 0 53 1;
+#X connect 48 0 46 0;
+#X connect 48 0 50 0;
+#X connect 49 0 47 0;
+#X connect 49 0 51 0;
+#X connect 52 0 14 0;
+#X connect 55 0 32 2;
+#X connect 55 0 73 0;
+#X connect 55 0 74 0;
+#X connect 57 0 54 1;
+#X connect 58 0 57 0;
+#X connect 58 0 61 0;
+#X connect 59 0 57 1;
+#X connect 59 0 62 0;
+#X connect 60 0 57 2;
+#X connect 60 0 63 0;
+#X connect 64 0 65 0;
+#X connect 64 0 66 0;
+#X connect 65 0 58 0;
+#X connect 65 0 59 0;
+#X connect 66 0 60 0;
+#X connect 67 0 54 1;
+#X connect 68 0 54 1;
+#X connect 69 0 67 0;
+#X connect 69 0 71 0;
+#X connect 70 0 68 0;
+#X connect 70 0 72 0;
diff --git a/chords_memory.c b/chords_memory.c
new file mode 100755
index 0000000..9695940
--- /dev/null
+++ b/chords_memory.c
@@ -0,0 +1,1137 @@
+/*
+chords_memory:
+an external that using graph
+learns the played style
+and reproduces chords sequences
+see
+http://en.wikipedia.org/wiki/Graph_%28mathematics%29
+for an idea of what graphs are (but we'll use weights also)
+
+idea:
+
+------- NODES
+
+each node of the graph is a chord
+each node has a name like "Imin Imaj ... IImin IImaj .... etc"
+We'll cover each possible grade and form, each grade can be
+maj
+min
+dim
+aug
+maj7maj
+maj7min
+min7maj
+min7min
+dim7dim
+dim7min
+dim7maj
+aug7min
+aug7maj
+(tot 13 forms)
+we have 12 grades:
+I
+I#
+II
+II#
+III
+IV
+IV#
+V
+V#
+VI
+VI#
+VII
+
+for a total of 12x13=156 nodes
+
+------- ARCS
+
+each node is connected to any other node
+each node has a weight
+the weight is augmented each time the human plays this chord sequence
+so probably I V will have high weight
+and I VI#7 will be very light
+
+this will be a table of 156x156 int (24336 elements)
+
+what can i do with the graph?
+
+i can do questions like:
+
+simple questions like:
+starting from IIImin tell me a chord so i have a high weight (no novelty)
+starting from IIImin tell me a chord so I have hight novelty (low weight)
+(the graph simply must select the arc starting from IIImin with the desired weight)
+
+i can build walks giving starting chord:
+as before but more than 1 passage
+
+i can build walks giving target chord:
+- "build a walk from current chord to target chord with high novelty"
+- "build the shortest walk from current chord to target chord with novelty less than ..."
+- "build a 4 chords long walk from here to there with ... average novelty"
+all these questions are usefull if there is a "form manager" that decides
+the piece structure,for example it wants the 2nd theme to start in 4 measures
+and asks for a chord sequence with medium novelty ending on the dominant (V),
+when the piece is ending it can ask for a coming back to the first tone..
+
+once we have all the arcs building walks is simply a matter of apply search methods
+like http://en.wikipedia.org/wiki/A%2A_search_algorithm
+there are plenty of such algos, we must just copy them down.
+
+
+*/
+#include <stdlib.h>
+#include <math.h>
+// for random, we may want to use it when building walks
+#include <time.h>
+// for file io
+#include <stdio.h>
+// for string manipulation
+#include <string.h>
+#include <ctype.h>
+
+#include "m_pd.h"
+
+
+#define DEBUG 1 // messaggi di debug
+#define DEBUG_VERBOSE 0 // messaggi di debug
+
+// is this system Little Endian? (thanks to Mathieu Bouchard)
+// TODO: use this code in file writing/reading
+// instead of forcing little endian!
+//static inline int is_le() {int x=1; return ((char *)&x)[0];}
+
+// ------------------------------- declaration of used types
+
+static t_class *chords_memory_class;
+
+// how can a chord be?
+#define TYPES_NUM 10 // keep me updated
+typedef enum {
+ kMaj=0,
+ kMin=1,
+ kDim=2,
+ kAug=3,
+ kDom7=4,
+ kMaj7=5,
+ kMin7=6,
+ kMinMaj7=7,
+ kDim7=8,
+ kHalfDim7=9
+ } chord_type_t;
+
+// how many tones do we have in our octave?
+#define TONES_NUM 12 // keep me updated
+typedef enum {I=0,
+ Id=1,
+ II=2,
+ IId=3,
+ III=4,
+ IV=5,
+ IVd=6,
+ V=7,
+ Vd=8,
+ VI=9,
+ VId=10,
+ VII=11
+ } chord_tone_t;
+
+// how many nodes does this graph have?
+// for now TYPES_NUM*TONES_NUM
+// when we introduce modulation
+// we'll have more
+#define NODES_NUM TYPES_NUM*TONES_NUM
+
+// this defines a chord in a tonality
+typedef struct _chord
+{
+ chord_type_t mode;
+ chord_tone_t note;
+} chord_t;
+
+// enumeration of absolute notes
+// i'll need this when parsing strings like "C major"
+typedef enum {C=0,
+ Db=1,
+ D=2,
+ Eb=3,
+ E=4,
+ F=5,
+ Gb=6,
+ G=7,
+ Ab=8,
+ A=9,
+ Bb=10,
+ B=11
+ } abs_note_t;
+
+// enumeration of modes
+// i'll start with minor and major only
+// but we could add phrigian, doric, misolidian ,e tc...
+#define MODES_NUM 2
+typedef enum {
+ MAJOR=0,
+ MINOR=1 } modes_t;
+
+#define MODULATIONS_NUM MODES_NUM*TONES_NUM
+
+// data type for the steps of a walk
+typedef struct _step
+{
+ // 1 if i must modulate to tonality before computing chord
+ int modulate;
+ // this chord
+ chord_t chord;
+ // new tonality to be applied before chord
+ int tonality_note;
+ int tonality_mode;
+} step_t;
+
+// struct defining this external's memory space
+typedef struct _chords_memory
+{
+ t_object x_obj; // myself
+ t_outlet *x_outchordname; /* chord name, e.g. "Cmajor7" */
+ t_outlet *x_outtonalityname; /* chord name, e.g. "Cmajor7" */
+ t_outlet *x_outchordssequence; /* sequence of chords,a walk */
+ // the matrix : arcs of the graph
+ // each tonality mode has his matrix
+ // each matrix is in this form:
+ // from which chord to which chord
+ short int arcs[MODES_NUM][NODES_NUM][NODES_NUM];
+ // modulations matrix
+ // same as above
+ // but for modulations
+ short int modulations[MODES_NUM][NODES_NUM][MODULATIONS_NUM];
+ // I use this to normalize weights 0-1
+ short int maxweight[MODES_NUM];
+ // to convert from absolute tones (C, D, E, ..) to relative ones (I, II, III) and back
+ abs_note_t fundamental_note; // describes current tonality
+ modes_t fundamental_mode; // describes current tonality
+ // to save and load my status
+ t_symbol *filename;
+ // to normalize weights to 0-1
+ chord_t last_chord;
+ int last_chord_set;
+ // to use for walks
+ step_t *walk;
+ int steps;
+ int using_walk;
+ int current_step;
+
+} t_chords_memory;
+
+//static inline int mod(int a, int b) {int c=a%b; c+=b&-(c&&(a<0)^(b<0)); return c;}
+
+// bring this number in 0 12 range
+int clean_note(int src)
+{
+ while (src>12)
+ src-=12;
+ while (src<0)
+ src+=12;
+ return src;
+}
+// or use this one:
+#define MOD(x,y) (((x%y)+y)%y)
+
+
+// ------------------------------- init functions
+
+// initializes the graphs to 0 (everything is new)
+void chords_memory_init_graph(t_chords_memory *x)
+{
+ int i, j, m;
+ for (m=0; m<MODES_NUM; m++)
+ {
+ x->maxweight[m]=1;
+ for (i=0; i<NODES_NUM; i++)
+ {
+ for (j=0; j<NODES_NUM; j++)
+ {
+ // initially every chord sequence is a novelty
+ x->arcs[m][i][j]=0;
+ }
+ }
+ }
+ x->last_chord_set=0;
+}
+
+void chords_memory_init(t_chords_memory *x, t_floatarg f)
+{
+ chords_memory_init_graph(x);
+}
+
+
+// ------------- function for string manipulation (from string to chords)
+
+// tries to find out absolute tones names in this string
+abs_note_t from_string_to_abs_tone(const char *substr)
+{
+ if (strstr(substr, "C"))
+ return C;
+ if (strstr(substr, "Db"))
+ return Db;
+ if (strstr(substr, "D"))
+ return D;
+ if (strstr(substr, "Eb"))
+ return Eb;
+ if (strstr(substr, "E"))
+ return E;
+ if (strstr(substr, "F"))
+ return F;
+ if (strstr(substr, "Gb"))
+ return Gb;
+ if (strstr(substr, "G"))
+ return G;
+ if (strstr(substr, "Ab"))
+ return Ab;
+ if (strstr(substr, "A"))
+ return A;
+ if (strstr(substr, "Bb"))
+ return Bb;
+ if (strstr(substr, "B"))
+ return B;
+ return C;
+}
+
+chord_type_t from_string_to_type(const char *substr)
+{
+ if (strstr(substr, "minor/major 7th"))
+ return kMinMaj7;
+ if (strstr(substr, "major 7th"))
+ return kMaj7;
+ if (strstr(substr, "major"))
+ return kMaj;
+ if (strstr(substr, "minor 7th"))
+ return kMin7;
+ if (strstr(substr, "minor"))
+ return kMin;
+ if (strstr(substr, "half diminished 7th"))
+ return kHalfDim7;
+ if (strstr(substr, "diminished 7th"))
+ return kDim7;
+ if (strstr(substr, "diminished"))
+ return kDim;
+ if (strstr(substr, "augmented"))
+ return kAug;
+ if (strstr(substr, "dominant 7th"))
+ return kDom7;
+ // TODO: other chords
+ // beware when adding new chords
+ // put shorter names at end of this function!
+ return C;
+}
+
+// find the tonality mode in this string
+modes_t from_string_to_mode(const char *substr)
+{
+ if (strstr(substr, "major"))
+ return MAJOR;
+ if (strstr(substr, "minor"))
+ return MINOR;
+
+ // TODO: other modes (doric, misolidian , custom, etc..
+ return C;
+}
+
+// builds a string for this chord
+// the string is in maxlib's chord format
+void chords_memory_chord2string(t_chords_memory *x, char *string, chord_t chord)
+{
+ abs_note_t newnote;
+ memset( string, '\0', sizeof(string) );
+ newnote = clean_note(chord.note + x->fundamental_note);
+ switch (newnote)
+ {
+ case C: strcat(string, "C "); break;
+ case Db: strcat(string, "Db "); break;
+ case D: strcat(string, "D "); break;
+ case Eb: strcat(string, "Eb "); break;
+ case E: strcat(string, "E "); break;
+ case F: strcat(string, "F "); break;
+ case Gb: strcat(string, "Gb "); break;
+ case G: strcat(string, "G "); break;
+ case Ab: strcat(string, "Ab "); break;
+ case A: strcat(string, "A "); break;
+ case Bb: strcat(string, "Bb "); break;
+ case B: strcat(string, "B "); break;
+ }
+ switch (chord.mode)
+ {
+ case kMaj: strcat(string, "major"); break;
+ case kMin: strcat(string, "minor"); break;
+ case kDim: strcat(string, "diminished"); break;
+ case kAug: strcat(string, "augmented"); break;
+
+ case kMaj7: strcat(string, "major 7th"); break;
+ case kDom7: strcat(string, "dominant 7th"); break;
+ case kMin7: strcat(string, "minor 7th"); break;
+ case kHalfDim7: strcat(string, "half diminished 7th"); break;
+ case kDim7: strcat(string, "diminished 7th"); break;
+ case kMinMaj7: strcat(string, "minor/major 7th"); break;
+
+ }
+}
+
+// helper function that returns a substring of str
+// starting from start and ending in end
+char* substring_r(char* buffer, char* str, int start, int end)
+{
+ int i, x = 0;
+ for(i = start ; i <= end; i++)
+ buffer[x++] = str[i];
+ buffer[x] = '\0';
+ return buffer;
+}
+
+// TODO: function to translate a string to chord
+// used both from inlet and from textfile
+chord_t chords_memory_string2chord(t_chords_memory *x, char *string)
+{
+ chord_t chord;
+ int index1;
+ int interval;
+ abs_note_t absnote;
+ char substr[32]; // is 32 ok?
+ if (DEBUG)
+ post("chords_memory_string2chord: string='%s'",string);
+ // c strings ends with \0
+ // so I set the substring to \0
+ memset( substr, '\0', sizeof(substr) );
+ // I assume the input is from maxlib's [chord]
+ // i don't need the notes before ":"
+ index1 = strcspn( string, ":");
+ if (index1 == strlen(string))
+ {
+ // : not found
+ // then the input was not from maxlib's [chord]
+ // i hope they passed me the right string...
+ strncpy( substr, string, strlen(string));
+ } else
+ {
+ // I will work on the right substring split by ":"
+ substring_r(substr, string, index1+1, strlen(string)-1);
+ if (isspace(substr[0]))
+ {
+ // substring inizia con uno spazio, lo tolgo
+ index1 = strlen(substr)-1;
+ memmove(substr, substr+1, index1);
+ substr[index1] = '\0';
+ }
+ }
+ // now in substr i *should* have a string like this
+ // "C dominant 7th"
+ if (DEBUG)
+ post("chords_memory_string2chord: substr='%s'",substr);
+ // now I need to understand how many semitones there are
+ // between x->current_fundamental and this chord
+ absnote = from_string_to_abs_tone(substr);
+ interval = clean_note(absnote - x->fundamental_note);
+ chord.note = interval;
+ chord.mode=from_string_to_type(substr);
+ if (DEBUG)
+ post("chords_memory_string2chord: chord.note=%i chord.mode=%i",chord.note, chord.mode);
+ return chord;
+}
+
+// ------------------------------- search functions
+
+// internal function
+// find the better chord starting from chord1
+// using the desired weight which is a value between 0 and 1
+// so i have to normalize weights to 0-1 interval
+// i use maxweight to do that
+// TODO: add random, don't simply select the best but make a list with candidates
+// and select randomly
+chord_t chords_memory_find_better(t_chords_memory *x, chord_t chord1, float desired_weight)
+{
+ // chords are integers
+ // to know what this integer means do that:
+ // int tone = chord1 / TONES_NUM
+ // int type = chord1 % TYPES_NUM
+ // the use a switch(tone) and a switch(type)
+ // to know what kind of chord is this
+ int chord1int, chord2int, i, best_index;
+ float best_value;
+ float tmp;
+ double rnd;
+ chord_t chord2;
+ chord1int = chord1.note*TYPES_NUM + chord1.mode;
+
+ //rnd = rand()/((double)RAND_MAX + 1);
+ //best_index = rnd * NODES_NUM;
+ tmp = 0;
+ //best_value = fabs(((float) x->arcs[chord1int][best_index]) / ((float) x->maxweight) - desired_weight);
+ //if (DEBUG_VERBOSE)
+ // post("chords_memory_find_better: initial %i best value = %f",best_index, best_value);
+ best_index = x->fundamental_mode; // fallback is I
+ best_value = 2; // higher than everyone
+ for (i=0; i<NODES_NUM; i++)
+ {
+ // i don't want it if has never been used
+ // i wouldn't know where to go then
+ // and i'd end up wondering blind
+ if (x->arcs[x->fundamental_mode][chord1int][i]>0)
+ {
+ tmp = fabs(((float)x->arcs[x->fundamental_mode][chord1int][i]) / ((float)x->maxweight[x->fundamental_mode]) - desired_weight);
+ if (DEBUG_VERBOSE)
+ post("chords_memory_find_better: x->arcs[%i][%i][%i]=%i x->maxweight[%i]=%i desired_weight=%f tmp=%f",x->fundamental_mode,chord1int,i, x->arcs[x->fundamental_mode][chord1int][i], x->fundamental_mode, x->maxweight[x->fundamental_mode], desired_weight, tmp);
+
+ if (tmp < best_value)
+ {
+ if (DEBUG_VERBOSE)
+ {
+ post("chords_memory_find_better: new best with value = %f", tmp);
+ post("chords_memory_find_better: x->arcs[%i][chord1int][%i]=%i x->maxweight[%i]=%i desired_weight=%f",x->fundamental_mode,i, x->arcs[x->fundamental_mode][chord1int][i], x->fundamental_mode, x->maxweight[x->fundamental_mode], desired_weight);
+ }
+
+ best_value = tmp;
+ best_index = i;
+ }
+ if (tmp == best_value)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < 0.5)
+ {
+ best_value = tmp;
+ best_index = i;
+ if (DEBUG_VERBOSE)
+ {
+ post("chords_memory_find_better: new best with value = %f", tmp);
+ post("chords_memory_find_better: x->arcs[%i][chord1int][%i]=%i x->maxweight[%i]=%i desired_weight=%f",x->fundamental_mode,i, x->arcs[x->fundamental_mode][chord1int][i],x->fundamental_mode,x->maxweight[x->fundamental_mode], desired_weight);
+ }
+ }
+ }
+ }
+ }
+ // now in best_index I have the best chord
+ // i build the chord back from the integer
+ chord2.mode = best_index % TYPES_NUM;
+ chord2.note = best_index / TYPES_NUM;
+ if (DEBUG)
+ post("chords_memory_find_better: chord.note=%i chord.mode=%i",chord2.note, chord2.mode);
+ return chord2;
+}
+
+// data structures to be used by build_walk
+
+// to sort arrays
+#include "sglib.h"
+
+// the data set we will work on it a matrix of candidates steps
+// this define each possibile chord and/or modulation
+// that can be chosen at each step
+typedef struct _possible_step
+{
+ int chordInt;
+ int cost; // NB integers!
+ int modulation; // 1 if needs modulations before new chord
+ int tonalityInt;
+} possible_step_t;
+
+typedef struct _possible_step2
+{
+ int index;
+ int cost; // NB integers!
+} possible_step2_t;
+
+// a row of our data set
+// each row is a step in the walk
+typedef struct _step_row
+{
+ possible_step_t cell[NODES_NUM+MODULATIONS_NUM];
+ int curr_cell;
+} step_row_t;
+
+// this is the real searching function
+// implementing a modified version of the
+// depth limited search
+// the difference is that we don't accept solutions
+// in less than the wanted number of steps
+
+// sglib comparator for an array of possible_step_t
+#define POSSIBLE_STEP_COMPARATOR(e1, e2) (e1.cost - e2.cost)
+#define MY_ARRAY_ELEMENTS_EXCHANGER(type, a, i, j) {type tmp;tmp=a[i];a[i]=a[j];a[j]=tmp;}
+
+// recursive function
+// returns 0 if solutions was not found
+// 1 if a solution was found
+// the way i implement this changes the search function
+// actually is a greedy one:
+// i always select the lower cost
+// and take the first solution
+// this algo is:
+// COMPLETE: YES
+// OPTIMAL: NO
+// complexity (where s=steps, n=nodes:
+// best case: n*s
+// worst case: n^s
+// this will surely need threads!
+int chords_memory_build_walk_recursive(t_chords_memory *x,
+ int chord_from_int,
+ int tonality_from_int,
+ int chord_to_int,
+ int tonality_to_int,
+ int this_step,
+ int wanted_steps,
+ float desired_weight,
+ step_row_t *step_matrix)
+{
+
+ int i, cost_tmp, ret;
+ int this_tonality_note;
+ int this_tonality_mode;
+ float cost_float;
+ //test
+ possible_step2_t *ordered_list;
+ ordered_list = malloc(sizeof(possible_step2_t)*(NODES_NUM+MODULATIONS_NUM));
+
+ this_tonality_note = tonality_from_int / MODES_NUM;
+ this_tonality_mode = tonality_from_int % MODES_NUM;
+
+ if (DEBUG)
+ post("chords_memory_build_walk_recursive: recursive function called, this_step=%i,this_tonality_mode=%i",
+ this_step,this_tonality_mode);
+
+ // first of all, I write all costs in step_matrix[this_step];
+ // chords first
+ for (i=0; i<NODES_NUM; i++)
+ {
+ step_matrix[this_step].cell[i].chordInt = i;
+ step_matrix[this_step].cell[i].modulation = 0;
+ // evaluate this cost
+ if (x->arcs[this_tonality_mode][chord_from_int][i]>0)
+ {
+ cost_float = fabs(((float)x->arcs[this_tonality_mode][chord_from_int][i]) / ((float)x->maxweight[this_tonality_mode]) - desired_weight);
+ } else
+ {
+ cost_float = 2; // never used this chord, so very costly
+ }
+ cost_tmp = cost_float * 1000;
+ step_matrix[this_step].cell[i].cost = cost_tmp;
+
+ //test
+ ordered_list[i].index=i;
+ ordered_list[i].cost=cost_tmp;
+
+ if (DEBUG_VERBOSE)
+ post("%i: cost_float=%f cost_tmp=%i chordInt=%i",
+ i,cost_float,step_matrix[this_step].cell[i].cost, step_matrix[this_step].cell[i].chordInt);
+ }
+ // then modulations
+ for (i=NODES_NUM; i<MODULATIONS_NUM; i++)
+ {
+ step_matrix[this_step].cell[i].tonalityInt = i-NODES_NUM;
+ step_matrix[this_step].cell[i].modulation = 1;
+ // step_matrix[this_step].cell[i].chordInt = ?? TODO
+ //step_matrix[this_step].cell[i].cost = ?? TODO
+ step_matrix[this_step].cell[i].cost = 2;
+ // HOW DO I MANAGE MODULATIONS ?!?!?!
+
+ }
+ step_matrix[this_step].curr_cell=0;
+
+ if (DEBUG_VERBOSE)
+ post("sorting...");
+ // now order the costs using sglib
+ // as i am greedy i follow the cheaper path first
+// SGLIB_ARRAY_QUICK_SORT (possible_step_t, step_matrix[this_step].cell, NODES_NUM+MODULATIONS_NUM, POSSIBLE_STEP_COMPARATOR, MY_ARRAY_ELEMENTS_EXCHANGER)
+ SGLIB_ARRAY_QUICK_SORT (possible_step2_t, ordered_list, NODES_NUM+MODULATIONS_NUM, POSSIBLE_STEP_COMPARATOR, MY_ARRAY_ELEMENTS_EXCHANGER)
+
+ // this function is called recursively
+ //base case is then this_step==wanted_steps-1
+
+// for (step_matrix[this_step].curr_cell=0;
+// step_matrix[this_step].curr_cell<(NODES_NUM+MODULATIONS_NUM);
+// step_matrix[this_step].curr_cell++)
+ for (i=0; i<(NODES_NUM+MODULATIONS_NUM); i++)
+ {
+ step_matrix[this_step].curr_cell = ordered_list[i].index;
+ // i don't want solutions that use never heard chords...
+ if (ordered_list[i].cost < 2000)
+ {
+ if (DEBUG_VERBOSE)
+ {
+ post("step_matrix[%i].curr_cell=%i chodInt=%i cost=%i",
+ this_step,step_matrix[this_step].curr_cell,
+ step_matrix[this_step].cell[step_matrix[this_step].curr_cell].chordInt,
+ step_matrix[this_step].cell[step_matrix[this_step].curr_cell].cost
+ );
+ }
+ if (this_step==wanted_steps-1)
+ {
+ // base case
+ // look for the solution
+ if ((step_matrix[this_step].cell[step_matrix[this_step].curr_cell].chordInt == chord_to_int) &&
+ (step_matrix[this_step].cell[step_matrix[this_step].curr_cell].tonalityInt == tonality_to_int))
+ {
+ // i just found a solution!
+ if (DEBUG)
+ post("chords_memory_build_walk_recursive: solution found! chord_note=%i chord_to_int=%i",
+ chord_to_int/TYPES_NUM,chord_to_int);
+ free(ordered_list);
+ return 1; // as i am greedy (and lazy) i return immediatly
+ }
+ } else
+ {
+ // recurive case
+ ret = chords_memory_build_walk_recursive(x,
+ step_matrix[this_step].cell[step_matrix[this_step].curr_cell].chordInt,
+ step_matrix[this_step].cell[step_matrix[this_step].curr_cell].tonalityInt,
+ chord_to_int,
+ tonality_to_int,
+ this_step+1,
+ wanted_steps,
+ desired_weight,
+ step_matrix);
+ if (ret == 1)
+ {
+ // solution found below me!
+ if (DEBUG)
+ post("chords_memory_build_walk_recursive: solution found! chordInt=%i cost=%i",
+ step_matrix[this_step].cell[step_matrix[this_step].curr_cell].chordInt,
+ step_matrix[this_step].cell[step_matrix[this_step].curr_cell].cost);
+ free(ordered_list);
+ return 1;
+ }
+
+ }
+ }
+ }
+ free(ordered_list);
+ return 0;
+}
+
+// TODO: add ending tonality !!!!
+void chords_memory_build_walk(t_chords_memory *x, chord_t starting_chord, chord_t ending_chord, float desired_weight, int steps)
+{
+ int i,j,s,n, ret;
+ int chord_from_int, chord_to_int, tonality_from_int, tonality_to_int;
+ step_row_t *step_matrix;
+ // for output
+ t_atom *chords_sequence;
+ char stringTMP[25];
+ // alloc arrays
+ if (x->using_walk)
+ free(x->walk);
+ x->walk = malloc(sizeof(step_t)*steps);
+ step_matrix = malloc(sizeof(step_row_t)*steps);
+ chords_sequence = malloc(sizeof(t_atom)*steps);
+
+ // for each step:
+ // fill this step with costs
+ // order the list
+ // take the first
+ // use it to fill the next level until you get to the desired step
+ // if you don't find a solution then step back
+ // select the second alternative and again
+ chord_from_int = starting_chord.note * TYPES_NUM + starting_chord.mode ;
+ tonality_from_int = x->fundamental_note * MODES_NUM + x->fundamental_mode;
+ chord_to_int = ending_chord.note * TYPES_NUM + ending_chord.mode ;
+ tonality_to_int = tonality_from_int; // TODO !!!!!
+
+ if (DEBUG)
+ post("chords_memory_build_walk: calling recursive function");
+
+ ret = chords_memory_build_walk_recursive(x, chord_from_int, tonality_from_int, chord_to_int, tonality_to_int,
+ 0, steps, desired_weight, step_matrix);
+ if (ret==0)
+ {
+ // no solution found
+ // what do i do now?!?!
+ if (DEBUG)
+ post("no solution found");
+ return;
+ }
+ // copy the solution to the x->walk
+ // and set all needed vars
+ for (i=0; i<steps; i++)
+ {
+ int chordIntTMP = step_matrix[i].cell[step_matrix[i].curr_cell].chordInt;
+ int tonalityIntTMP = step_matrix[i].cell[step_matrix[i].curr_cell].tonalityInt;
+ int modulationTMP = step_matrix[i].cell[step_matrix[i].curr_cell].modulation;
+ // i copy this chord/modulation to the walk
+ x->walk[i].modulate = modulationTMP;
+ x->walk[i].chord.note = chordIntTMP / TYPES_NUM;
+ x->walk[i].chord.mode = chordIntTMP % TYPES_NUM;
+ x->walk[i].tonality_note = tonalityIntTMP / MODULATIONS_NUM;
+ x->walk[i].tonality_mode = tonalityIntTMP % MODULATIONS_NUM;
+ // build a list to send out to the
+ // right outlet
+ chords_memory_chord2string(x,stringTMP,x->walk[i].chord);
+ if (DEBUG)
+ post("chord: %s", stringTMP);
+
+ //outlet_symbol(x->x_outtonalityname, gensym(stringTMP));
+
+ SETSYMBOL(chords_sequence+1, gensym(stringTMP));
+ //SETSYMBOL(chords_sequence+1, stringTMP);
+ }
+
+ // send the solution list to outlet x_outchordssequence
+ outlet_list(x->x_outchordssequence,
+ gensym("list") ,
+ steps,
+ chords_sequence);
+
+ // TODO: set other vars for walk
+
+ // free arrays
+ free(step_matrix);
+ free(chords_sequence);
+ // don't free walk, will be freed by someone else
+}
+
+
+// ------------------------------- from now on there are functions directly called by pd
+
+// when you send a |next x( message...
+// function actually invoked when sending a "next x" message to the external
+void chords_memory_next(t_chords_memory *x, t_floatarg f)
+{
+ float desired_weight;
+ chord_t best;
+ char string[32];
+ desired_weight = f;
+ best = chords_memory_find_better(x, x->last_chord, desired_weight);
+ chords_memory_chord2string(x, string, best);
+ outlet_symbol(x->x_outchordname, gensym(string));
+}
+
+// when you send a search message
+void chords_memory_search(t_chords_memory *x, t_symbol *sl, int argc, t_atom *argv)
+{
+ int steps;
+ chord_t chord2;
+ float desired_weight;
+ // parse the list
+ // you need chord_dest, steps and desired_weight
+ // (later desired tonality also)
+
+ if (argc<4)
+ {
+ error("usage: search chord-note chord-type steps weight");
+ return;
+ }
+
+ chord2.note = atom_getint(argv);
+ chord2.mode= atom_getint(argv+1);
+ steps = atom_getint(argv+2);
+ desired_weight = atom_getfloat(argv+3);
+
+ chords_memory_build_walk(x, x->last_chord, chord2, desired_weight, steps);
+
+}
+
+
+// ------------------------------- functions to set and add chords/tonality
+
+// sets the current chord
+void chords_memory_set_chord(t_chords_memory *x, t_symbol *s) {
+ if (! x->last_chord_set)
+ {
+ x->last_chord_set=1;
+ }
+ x->last_chord = chords_memory_string2chord(x, s->s_name);
+ if (DEBUG)
+ post("chords_memory_set_chord: chord.note=%i chord.mode=%i",x->last_chord.note, x->last_chord.mode);
+}
+
+// add a chord sequence to the graph
+void chords_memory_add(t_chords_memory *x, chord_t chord1, chord_t chord2)
+{
+ // chords are integers
+ // to know what this integer means do that:
+ // int tone = chord1 / TONES_NUM
+ // int type = chord1 % TYPES_NUM
+ // the use a switch(tone) and a switch(type)
+ // to know what kind of chord is this
+
+ int chord1int, chord2int;
+ chord1int = chord1.note*TYPES_NUM + chord1.mode;
+ chord2int = chord2.note*TYPES_NUM + chord2.mode;
+ // now that i've translated chords in integers i can add
+ // 1 to its wheight (a bit less new)
+ x->arcs[x->fundamental_mode][chord1int][chord2int] = x->arcs[x->fundamental_mode][chord1int][chord2int] + 1;
+ // is this the new maxweight?
+ if (x->arcs[x->fundamental_mode][chord1int][chord2int] > x->maxweight[x->fundamental_mode])
+ {
+ x->maxweight[x->fundamental_mode] = x->arcs[x->fundamental_mode][chord1int][chord2int];
+ if (DEBUG)
+ post("x->maxweight[%i] = %i",x->fundamental_mode, x->maxweight[x->fundamental_mode]);
+ }
+
+}
+
+// function invoked when a new chord is added at the graph
+// the external remembers the previous played chord
+void chords_memory_add_chord(t_chords_memory *x, t_symbol *s) {
+ chord_t chord1;
+ chord1 = chords_memory_string2chord(x, s->s_name);
+ if (x->last_chord_set)
+ {
+ chords_memory_add(x, x->last_chord, chord1);
+ }
+ else
+ {
+ x->last_chord_set=1;
+ }
+ x->last_chord = chord1;
+ if (DEBUG)
+ post("chord added: %s", s->s_name);
+}
+
+// sets the current tonality
+void chords_memory_set_tonality(t_chords_memory *x, t_symbol *s) {
+ chord_t c;
+ int old_tonality;
+ int interval;
+ old_tonality = x->fundamental_note;
+ //x->fundamental_note = (x->fundamental_note + from_string_to_abs_tone(s->s_name)) % 12;
+ x->fundamental_note = from_string_to_abs_tone(s->s_name);
+ x->fundamental_mode = from_string_to_mode(s->s_name);
+ // when i set the tonality i always
+ // go on the I grade
+ if (! x->last_chord_set)
+ {
+ x->last_chord_set=1;
+ }
+ interval = x->fundamental_note - old_tonality;
+ x->last_chord.note = clean_note(x->last_chord.note - interval);
+ outlet_symbol(x->x_outtonalityname, gensym(s->s_name));
+ if (DEBUG)
+ {
+ post("chords_memory_set_tonality: new tonality note=%i mode=%i",x->fundamental_note,x->fundamental_mode);
+ post("chords_memory_set_tonality: chord.note=%i chord.mode=%i",x->last_chord.note, x->last_chord.mode);
+ }
+}
+
+// adds this modulation to memory
+// code similar to chords_memory_add
+// but adds a modulation instead of a chord
+void chords_memory_add_modulation(t_chords_memory *x, t_symbol *s) {
+ chord_t c;
+ int old_tonality;
+ int newnote,newmode,newabsnote,chord1int;
+ short int modulationInt;
+ old_tonality = x->fundamental_note;
+ //x->fundamental_note = (x->fundamental_note + from_string_to_abs_tone(s->s_name)) % 12;
+ newabsnote = from_string_to_abs_tone(s->s_name);
+ newmode = from_string_to_mode(s->s_name);
+ // when i set the tonality i always
+ // go on the I grade
+ if (! x->last_chord_set)
+ {
+ x->last_chord_set=1;
+ }
+ newnote = clean_note(newabsnote - old_tonality);
+ modulationInt = newnote*MODES_NUM + newmode;
+ chord1int = x->last_chord.note*TYPES_NUM + x->last_chord.mode;
+ x->modulations[x->fundamental_mode][chord1int][modulationInt] = x->modulations[x->fundamental_mode][chord1int][modulationInt] + 1;
+ // is this the new maxweight?
+ if (x->modulations[x->fundamental_mode][chord1int][modulationInt] > x->maxweight[x->fundamental_mode])
+ {
+ x->maxweight[x->fundamental_mode] = x->modulations[x->fundamental_mode][chord1int][modulationInt];
+ }
+ if (DEBUG)
+ {
+ post("chords_memory_add_modulation: new tonality note=%i mode=%i",newnote,newmode);
+ }
+ chords_memory_set_tonality(x, gensym(s->s_name));
+}
+
+// ---------------------- file I/O
+
+// function to read graph from a file
+void chords_memory_read_from_file(t_chords_memory *x, t_symbol *s)
+{
+ FILE *fp;
+ int i, j, m;
+ unsigned char tmp[2];
+ if ((fp=fopen(s->s_name, "r+b"))==NULL)
+ {
+ post("error: can't open file %s", s->s_name);
+ return;
+ }
+
+ for (m=0; m<MODES_NUM; m++)
+ {
+ // i read maxweight
+ x->maxweight[m] = (fgetc(fp)<<16)|(fgetc(fp));
+ // i read the matrix
+ for (i=0; i<NODES_NUM; i++)
+ {
+ for (j=0; j<NODES_NUM; j++)
+ {
+ // this should avoids problems little/big endian
+ // i force little endian (most significant byte first)
+ tmp[0] = fgetc(fp);
+ tmp[1] = fgetc(fp);
+ x->arcs[m][i][j] = (tmp[0]<<8)|(tmp[1]);
+ if (DEBUG_VERBOSE)
+ {
+ if (x->arcs[m][i][j]>0)
+ {
+ post("x->arcs[%i][%i][%i] = %i",m,i,j,x->arcs[m][i][j]);
+ }
+ }
+ }
+ for (j=0; j<MODES_NUM; j++)
+ {
+ // this should avoids problems little/big endian
+ // i force little endian (most significant byte first)
+ tmp[0] = fgetc(fp);
+ tmp[1] = fgetc(fp);
+ x->modulations[m][i][j] = (tmp[0]<<8)|(tmp[1]);
+ if (DEBUG_VERBOSE)
+ {
+ if (x->modulations[m][i][j]>0)
+ {
+ post("x->modulations[%i][%i][%i] = %i",m,i,j,x->modulations[m][i][j]);
+ }
+ }
+ }
+ }
+ if (DEBUG)
+ post("x->maxweight[%i] = %i",m, x->maxweight[m]);
+ }
+ if (DEBUG)
+ post("graph read from file %s",s->s_name);
+ fclose(fp);
+
+}
+
+// function to write graph to a file (for later loading)
+void chords_memory_write_to_file(t_chords_memory *x, t_symbol *s)
+{
+ FILE *fp;
+ int i, j, m, tmp;
+ fp=fopen(s->s_name, "w+b");
+
+ for (m=0; m<MODES_NUM; m++)
+ {
+ // i write down maxweight
+ fputc(x->maxweight[m]>>8, fp);
+ tmp = x->maxweight[m]<<8;
+ tmp = tmp >> 8;
+ fputc(tmp, fp);
+ // i write down the matrix
+ for (i=0; i<NODES_NUM; i++)
+ {
+ for (j=0; j<NODES_NUM; j++)
+ {
+ // this should avoids problems little/big endian
+ // i force little endian (most significant byte first)
+ fputc(x->arcs[m][i][j]>>8, fp);
+ tmp = x->arcs[m][i][j]<<8;
+ tmp = tmp >> 8;
+ fputc(tmp, fp);
+ }
+ for (j=0; j<MODES_NUM; j++)
+ {
+ // this should avoids problems little/big endian
+ // i force little endian (most significant byte first)
+ fputc(x->modulations[m][i][j]>>8, fp);
+ tmp = x->modulations[m][i][j]<<8;
+ tmp = tmp >> 8;
+ fputc(tmp, fp);
+ }
+ }
+ }
+ if (DEBUG)
+ post("graph wrote to file %s",s->s_name);
+ fclose(fp);
+}
+
+// TODO: function that reads chords from a textfile and trains the graph
+
+// TODO: recursive function that builds a walk from chord1 to chord2 using desired novelty
+
+// set filename
+void chords_memory_set_filename(t_chords_memory *x, t_symbol *s) {
+ x->filename = s;
+}
+
+
+
+void *chords_memory_new(t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ time_t a;
+ t_chords_memory *x = (t_chords_memory *)pd_new(chords_memory_class);
+ x->x_outchordname = outlet_new(&x->x_obj, gensym("symbol"));
+ x->x_outtonalityname = outlet_new(&x->x_obj, gensym("symbol"));
+ x->x_outchordssequence = outlet_new(&x->x_obj, &s_list);
+ srand(time(&a));
+ chords_memory_init_graph(x);
+ x->fundamental_note = C;
+ x->fundamental_mode = MAJOR;
+ // example parameter
+ if (argc>0)
+ {
+ x->filename = atom_getsymbolarg(0, argc, argv);
+ chords_memory_read_from_file(x, x->filename);
+ }
+
+ return (x);
+}
+
+// here I free allocated memory if any
+void chords_memory_free(t_chords_memory *x)
+{
+// free(x->current_fundamental);
+}
+
+// TEST
+typedef struct _bla
+{
+ int value;
+ int index;
+} bla_t;
+typedef struct _bla2
+{
+ bla_t array[10];
+} bla2_t;
+#define BLA_COMPARATOR(e1, e2) (e1.value - e2.value)
+//TEST
+void chords_memory_bang(t_chords_memory *x)
+{
+ int i;
+ bla2_t test[2];
+ for (i=0; i<10; i++)
+ {
+ test[1].array[i].index = i;
+ test[1].array[i].value = 10-i;
+ }
+SGLIB_ARRAY_QUICK_SORT (bla_t, test[1].array, 10, BLA_COMPARATOR, SGLIB_ARRAY_ELEMENTS_EXCHANGER);
+ for (i=0; i<10; i++)
+ {
+ post("array[%i].value = %i, array[%i].index = %i",i, test[1].array[i].value,i, test[1].array[i].index );
+ }
+
+}
+
+void chords_memory_setup(void)
+{
+ chords_memory_class = class_new(gensym("chords_memory"), (t_newmethod)chords_memory_new,
+ (t_method)chords_memory_free, sizeof(t_chords_memory), CLASS_DEFAULT, A_GIMME, 0);
+class_addbang(chords_memory_class, (t_method)chords_memory_bang);
+ // file I/O
+ class_addmethod(chords_memory_class, (t_method)chords_memory_write_to_file, gensym("write"),A_SYMBOL, 0);
+ class_addmethod(chords_memory_class, (t_method)chords_memory_read_from_file, gensym("read"),A_SYMBOL, 0);
+ // ask for the best choice form here
+ class_addmethod(chords_memory_class, (t_method)chords_memory_next, gensym("next"), A_DEFFLOAT, 0);
+ // ask for a path from here to desired destination
+ class_addmethod(chords_memory_class, (t_method)chords_memory_search, gensym("search"), A_GIMME, 0);
+ // add or set chord
+ class_addmethod(chords_memory_class, (t_method)chords_memory_add_chord, gensym("add"),A_SYMBOL, 0);
+ class_addmethod(chords_memory_class, (t_method)chords_memory_set_chord, gensym("set"),A_SYMBOL, 0);
+ // change current tonality
+ class_addmethod(chords_memory_class, (t_method)chords_memory_set_tonality, gensym("tonality"),A_SYMBOL, 0);
+ class_addmethod(chords_memory_class, (t_method)chords_memory_add_modulation, gensym("modulation"),A_SYMBOL, 0);
+ // reinit memory
+ class_addmethod(chords_memory_class, (t_method)chords_memory_init, gensym("init"), A_DEFFLOAT, 0);
+
+}
diff --git a/doc/LINKS.txt b/doc/LINKS.txt
new file mode 100755
index 0000000..d8685c5
--- /dev/null
+++ b/doc/LINKS.txt
@@ -0,0 +1,26 @@
+
+open source libs ready to be used...
+
+AthenaCL:
+is a python software for algorithmic composition
+we could use some code through pyext
+http://www.flexatone.net/athena.html
+this is specific for post tonal theory
+http://www.flexatone.net/athenaDocs/www/ch-analysis.htm
+
+AIMA Python code, working agents, etc.
+http://aima.cs.berkeley.edu/python/readme.html
+
+BEAGLE, implements co-evolution, open source, C++
+beagle.gel.ulaval.ca
+
+open source c++ genetic algorithm:
+http://lancet.mit.edu/ga/
+
+plain ansi C (multi platform?):
+http://sourceforge.net/projects/ga-lib
+
+another in c++:
+http://sourceforge.net/projects/ga2
+
+
diff --git a/doc/README.txt b/doc/README.txt
new file mode 100755
index 0000000..524dfc1
--- /dev/null
+++ b/doc/README.txt
@@ -0,0 +1,27 @@
+***README***
+
+Vatic, davide, please add notes and thoughts here for now...
+
+****Ruby/Gridflow instructions***
+
+In order to use some of the objects in the test patches, for now just [random_choice] within [manager] in the chord_melo_test patches, you will need GridFlow and Ruby installed.
+
+Please find instructions here:
+
+http://gridflow.ca/latest/doc/install.html
+
+Once you have Ruby 1.8.0 or above installed, and GridFlow is happily starting in Puredata, you should see the following at PD startup:
+
+setting up Ruby-for-PureData...
+we are using Ruby version 1.8.1
+[gf] This is GridFlow 0.8.1 within Ruby version 1.8.1
+
+Or, something similar.
+
+Now, you will need to copy ruby/.gridflow_startup to your home directory. If it is somewhere else than /home/you/ or /Users/you, you can always load it from pd by using the Ruby console input (see pd's console window, and under IN - OUT), by doing:
+
+load "/path/to/.gridflow_startup
+
+You're now able to write puredata objects in Ruby!
+
+
diff --git a/doc/chords_graph.doc b/doc/chords_graph.doc
new file mode 100755
index 0000000..e8390c2
--- /dev/null
+++ b/doc/chords_graph.doc
Binary files differ
diff --git a/doc/chords_graph.sxw b/doc/chords_graph.sxw
new file mode 100755
index 0000000..9f901ec
--- /dev/null
+++ b/doc/chords_graph.sxw
Binary files differ
diff --git a/doc/genomes-notes.txt b/doc/genomes-notes.txt
new file mode 100755
index 0000000..e39e524
--- /dev/null
+++ b/doc/genomes-notes.txt
@@ -0,0 +1,125 @@
+
+***read README.txt before this file***
+
+this ideas are related to shostakovich prelude n.2 in a minor
+
+
+how do we map notes <--> genome ?
+
+
+
+--------------- 1st idea: whole MIDI, absolute values
+
+keep all the chromatic values, all midi notes
+
+the fitness functions and crossover functions will manage the thing
+(no notes outside current chord, etc..)
+
+each gene is a byte,
+- first 7 bits for midi note (unsigned char, 0-127)
+- last bit for rest (1=play, 0=rest)
+
+why yes:
+-not restricted to prelude n.2 musical space
+-not restricted to tonal music space
+
+why not:
+-huge transition table, intervals table
+-we don't want values we don't need
+-difficult to write fitness functions that check for tonality, chords, etc..
+
+---------------- 2nd idea: chromatic scale, chord relative
+
+notes are relative to current chord but still in a chromatic space.
+the critics must choose the diatonic ones and discard atonal ones
+
+each gene is a byte,
+- first 7 bits for midi note (unsigned char, 0-127)
+- last bit for rest (1=play, 0=rest)
+
+
+why yes:
+-we can use the same melody to different chords
+-not restricted to prelude n.2 musical space
+-not restricted to tonal music space
+
+why not:
+-still huge tables
+-difficult to write fitness functions that check for tonality, chords, etc..
+
+---------------- 3rd idea: diatonic scale, chord relative
+
+the musical space is diatonic, no more chromatic. critics need to work much less,
+they only have to know if a note is in the chord or not.
+
+problem: how to use chromatic passing notes this way?
+
+possibile notes are 7*4=28 (7 notes per octave) + passing notes
+we could use : 1 byte for each gene
+- 5 bits for note (0-32)
+- 2 bit for cromatic passing note (0=no, 1=descending, 2=ascending, 4=not used)
+- 1 bit for rests
+
+
+why yes:
+-we can use the same melody to different chords
+-quick fitness functions
+-we don't have notes we don't want
+
+why not:
+-restricted to tonal music space
+
+---------------- 4th idea: chord notes
+
+
+the musical space are the chord notes, not even the diatonic scale.
+critics don't have to check anything!
+
+problem: how to use (chromatic or diatonic) passing notes?
+
+possibile notes are 3*4=12 (3 notes per octave) + passing notes
+we should use a struct for the gene:
+{
+ - note (from 0 to 16)
+ - rest (0/1)
+ - passing_note (from -4 to +4)
+}
+
+possible passing notes are 9:
+no passing, from -4 semitones to +4 semitones
+
+the fitness functions and crossover functions will have to care sbout rules for passing notes:
++3 and +4 are allowed only for the 3rd note of the chord
+-4 and -3 are allowed only for the 1st note of the chord
+every passing note can exist only if the note before was next to it and proceeding in the same direction
+each passing note must resolve on the nearer chord note in the right direction
+
+why yes:
+-we can use the same melody to different chords
+-quickest fitness functions
+-we don't have notes we don't want
+
+why not:
+-restricted to tonal music space
+-restricted to 3-notes-chords-based harmonies (jazz is 4 notes based)
+
+
+
+
+
+common problems:
+
+i can think a way to rule passing notes (a passing note must come from a consonant note and go to a consonant note)
+but what can we do if a passing not is at the very end of the melody? (i don't know what will the next note be)
+...we should have to know what will be the next chord...
+
+
+
+
+
+
+
+
+
+Davide Morelli
+17.09.05
diff --git a/doc/maxlibnotes.txt b/doc/maxlibnotes.txt
new file mode 100755
index 0000000..532ddf9
--- /dev/null
+++ b/doc/maxlibnotes.txt
@@ -0,0 +1,16 @@
+081005
+
+-the most universally useful maxlib object has to be [borax], since it not only gives us velocity, pitch, duration, but also can detect the number of voices currently playing, various delta values, can count note-ons (incrementally), amongst other things. It's like a swiss army knife of music analysis, and I suspect this is where our live input (in davide's diagram) needs to make use of maxlib in order to derive what we will feed the chord extractor, then graph.
+
+-[gestalt] is for monophonic melodies only, but with [tilt], will detect the onset of melodies
+
+-[chord] is based on Robert Rowe's Machine Musicianship algorithms for chord detection, and will successfully detect most chords, but most importantly will give us the MIDI note number of the bass note, and its -class-.
+
+-[history] is interesting, because while it calculates the average value fed into its first inlet over N millisecond periods, it can also tell us the general tendency (up = 1, down = -1), which may be useful somewhere in the agent, to build more musical output. Also, [edge] is interesting because it detects falling and rising 'edges' in a sequence.
+
+-[iso] is interesting, because it can store and play sequences of MIDI notes -and- onsets in milliseconds, but of course we're once again talking about monophonic melodies, unless we run several in parallel somehow, but they'd have to 'know' about each other.
+
+-interestingly, [subst] performs what I see as the bit-shifting part of our current GA construction, and may actually help in understanding how we'd build a solderer agent.
+
+-[match] could be useful, because it matches incoming data against up to 16 creation arguments, and outputs a list; this might help in determining how closely the live player is playing against generated output or suggestions? just a thought.
+
diff --git a/doc/model.doc b/doc/model.doc
new file mode 100755
index 0000000..af2fcc2
--- /dev/null
+++ b/doc/model.doc
Binary files differ
diff --git a/doc/model.sxw b/doc/model.sxw
new file mode 100755
index 0000000..b3b446f
--- /dev/null
+++ b/doc/model.sxw
Binary files differ
diff --git a/harmonizer.c b/harmonizer.c
new file mode 100755
index 0000000..7277723
--- /dev/null
+++ b/harmonizer.c
@@ -0,0 +1,629 @@
+/*
+harmonizer:
+this external build voicing from a chord to another.
+takes n voices (midi) as input
+you can set the current chord
+you can ask for next note of each voice to get to a target chord
+
+usefull to create chorals
+
+voicing is built using traditional GA (not co-evolving GA)
+
+voicing rules are hardcoded and are:
+- no parallel 8ths nor 5ths
+- better no hidden 8ths nor 5ths
+- better if uniform voice spacing (except for the bass)
+- better if little intervals
+- no all voices same direction
+- no voices outside limits
+- better complete chords
+
+TODO:
+would be nice to be able so set some rule at runtime
+or at least set the importance of rules in realtime..
+
+
+*/
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+// for string manipulation
+#include <string.h>
+#include <ctype.h>
+#include "m_pd.h"
+
+// to sort arrays
+#include "sglib.h"
+
+#define MAX_POPULATION 100
+
+#define DEF_PROB_MUTATION 0.03f
+
+#define VOICES 5
+
+#define NOTES_RANGE 80 // this should be multiple of 16
+#define LOWER_POSSIBLE_NOTE 24 // lower note possible, it should be a C
+#define POSSIBLE_NOTES (NOTES_RANGE/12*4) // 4 is the max number of notes in a chord
+
+// testing i noticed that we don't need more than 1 generation..
+// this is because we create an initial population that is really good
+// we may not need to crossover at all!
+#define GENERATIONS 1
+
+#define DEBUG 0 // messaggi di debug
+#define DEBUG_VERBOSE 0 // messaggi di debug
+
+static t_class *harmonizer_class;
+
+typedef enum {
+ kMaj=0,
+ kMin=1,
+ kDim=2,
+ kAug=3,
+ kDom7=4,
+ kMaj7=5,
+ kMin7=6,
+ kMinMaj7=7,
+ kDim7=8,
+ kHalfDim7=9
+ } mode_t;
+
+typedef enum {C=0,
+ Db=1,
+ D=2,
+ Eb=3,
+ E=4,
+ F=5,
+ Gb=6,
+ G=7,
+ Ab=8,
+ A=9,
+ Bb=10,
+ B=11
+ } note_t;
+
+
+
+// this defines a chord in a tonality
+typedef struct _chord
+{
+ mode_t mode;
+ note_t note;
+} chord_t;
+
+
+typedef struct _harmonizer
+{
+ t_object x_obj; // myself
+ // genotypes
+ int population[MAX_POPULATION][VOICES];
+ int current_voices[VOICES];
+ chord_t current_chord;
+ chord_t target_chord;
+ int target_notes[POSSIBLE_NOTES];
+ t_outlet *l_out;
+
+} t_harmonizer;
+
+// I build a table of possible notes
+// are the notes (midi)that form target_chord
+void build_possible_notes_table(t_harmonizer *x)
+{
+ int i, octave, basenote;
+ int n1, n2, n3, n4;
+ n1=n2=n3=n4=0; // there always is the fundamental
+ if (DEBUG_VERBOSE)
+ post("build_possible_notes_table target_chord.mode=%i target_chord.note=%i", x->target_chord.mode, x->target_chord.note);
+ switch (x->target_chord.mode)
+ {
+ case kMaj: n2=4; n3=7; n4=0;break;
+ case kMin: n2=3; n3=7; n4=0;break;
+ case kDim: n2=3; n3=6; n4=0;break;
+ case kAug: n2=4; n3=8; n4=0;break;
+ case kMaj7: n2=4; n3=7; n4=11;break;
+ case kDom7: n2=4; n3=7; n4=10;break;
+ case kMin7: n2=3; n3=7; n4=10;break;
+ case kHalfDim7: n2=3; n3=6; n4=10;break;
+ case kDim7: n2=3; n3=6; n4=9;break;
+ case kMinMaj7: n2=4; n3=7; n4=11;break;
+ }
+ if (DEBUG_VERBOSE)
+ post("build_possible_notes_table n2=%i n3=%i n4=%i", n2, n3, n4);
+
+ basenote=0;
+ switch (x->target_chord.note)
+ {
+ case C: basenote=0;break;
+ case Db: basenote=1;break;
+ case D: basenote=2;break;
+ case Eb: basenote=3;break;
+ case E: basenote=4;break;
+ case F: basenote=5;break;
+ case Gb: basenote=6;break;
+ case G: basenote=7;break;
+ case Ab: basenote=8;break;
+ case A: basenote=9;break;
+ case Bb: basenote=10;break;
+ case B: basenote=11;break;
+ }
+ if (DEBUG_VERBOSE)
+ post("build_possible_notes_table basenote=%i", basenote);
+ i=0;
+ octave=0;
+ while (i<(POSSIBLE_NOTES-3))
+ {
+ x->target_notes[i++]=octave*12 + LOWER_POSSIBLE_NOTE + basenote + n1;
+ x->target_notes[i++]=octave*12 + LOWER_POSSIBLE_NOTE + basenote + n2;
+ x->target_notes[i++]=octave*12 + LOWER_POSSIBLE_NOTE + basenote + n3;
+ x->target_notes[i++]=octave*12 + LOWER_POSSIBLE_NOTE + basenote + n4;
+ octave++;
+ }
+ if (DEBUG_VERBOSE)
+ {
+ i=0;
+ while (i<(POSSIBLE_NOTES))
+ {
+ post("x->target_notes[%i]=%i", i, x->target_notes[i++]);
+ }
+ }
+}
+
+// tries to find out absolute tones names in this string
+note_t string2note(const char *substr)
+{
+ if (strstr(substr, "C"))
+ return C;
+ if (strstr(substr, "Db"))
+ return Db;
+ if (strstr(substr, "D"))
+ return D;
+ if (strstr(substr, "Eb"))
+ return Eb;
+ if (strstr(substr, "E"))
+ return E;
+ if (strstr(substr, "F"))
+ return F;
+ if (strstr(substr, "Gb"))
+ return Gb;
+ if (strstr(substr, "G"))
+ return G;
+ if (strstr(substr, "Ab"))
+ return Ab;
+ if (strstr(substr, "A"))
+ return A;
+ if (strstr(substr, "Bb"))
+ return Bb;
+ if (strstr(substr, "B"))
+ return B;
+ return C;
+}
+
+mode_t string2mode(const char *substr)
+{
+ if (strstr(substr, "minor/major 7th"))
+ return kMinMaj7;
+ if (strstr(substr, "major 7th"))
+ return kMaj7;
+ if (strstr(substr, "major"))
+ return kMaj;
+ if (strstr(substr, "minor 7th"))
+ return kMin7;
+ if (strstr(substr, "minor"))
+ return kMin;
+ if (strstr(substr, "half diminished 7th"))
+ return kHalfDim7;
+ if (strstr(substr, "diminished 7th"))
+ return kDim7;
+ if (strstr(substr, "diminished"))
+ return kDim;
+ if (strstr(substr, "augmented"))
+ return kAug;
+ if (strstr(substr, "dominant 7th"))
+ return kDom7;
+ // TODO: other chords
+ // beware when adding new chords
+ // put shorter names at end of this function!
+ return C;
+}
+
+// ----------------- normal external code ...
+
+void harmonizer_init_pop(t_harmonizer *x)
+{
+ int i, j, tmp, tmp2, k, steps, note, insertpoint;
+ double rnd;
+ for (i=0; i<MAX_POPULATION; i++)
+ {
+ for (j=0; j<VOICES; j++)
+ {
+ /*
+ // totally randome version
+ rnd = rand()/((double)RAND_MAX + 1);
+ tmp = rnd * POSSIBLE_NOTES;
+ x->population[i][j] = x->target_notes[tmp];
+ */
+
+ // not totally random: i start from currend chord's notes
+ // and randomly go up or down
+ insertpoint = 0;
+ while ((insertpoint < POSSIBLE_NOTES) && (x->target_notes[insertpoint] < x->current_voices[j]))
+ insertpoint++;
+ if (insertpoint >= POSSIBLE_NOTES)
+ {
+ // i didn't find my insert point, possible?
+ // i pick a random one
+ rnd = rand()/((double)RAND_MAX + 1);
+ tmp = rnd * POSSIBLE_NOTES;
+ x->population[i][j] = x->target_notes[tmp];
+ } else
+ {
+ // insert point found
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < 0.5)
+ {
+ // i go up
+ rnd = rand()/((double)RAND_MAX + 1);
+ steps = rnd * 5; // how many step (good notes) will I ignore?
+ note = insertpoint + steps;
+ if (note >= POSSIBLE_NOTES)
+ note = POSSIBLE_NOTES-1;
+
+ } else
+ {
+ // i go down
+ rnd = rand()/((double)RAND_MAX + 1);
+ steps = rnd * 5; // how many step (good notes) will I ignore?
+ note = insertpoint - steps;
+ if (note < 0)
+ note = 0;
+ }
+ // finally assign the note
+ x->population[i][j] = x->target_notes[note];
+ }
+ }
+ }
+}
+
+
+void harmonizer_free(t_harmonizer *x)
+{
+// freebytes(x->buf_strum1, sizeof(x->buf_strum1));
+// freebytes(x->buf_strum2, sizeof(x->buf_strum2));
+}
+
+// here i evaluate this voicing
+int fitness(t_harmonizer *x, int *candidate)
+{
+ int i, j, tmp, res, last, avgHI, avgLOW;
+ short int transitions[VOICES];
+ short int directions[VOICES];
+ // intervals between voices
+ // for parallel and hidden 5ths
+ // voices spacing etc..
+ short int intervals[VOICES][VOICES];
+ short int notes[VOICES];
+ res=50; // starting fitness
+
+ if (DEBUG_VERBOSE)
+ post("evaluating fitness of %i %i %i %i", candidate[0], candidate[1], candidate[2], candidate[3]);
+
+ // shared objects
+ for (i=0; i<VOICES; i++)
+ {
+ notes[i]=candidate[i];
+ transitions[i] = candidate[i] - x->current_voices[i];
+ if (transitions[i]!=0)
+ directions[i] = transitions[i]/abs(transitions[i]);
+ else
+ directions[i] = 0;
+ if (DEBUG_VERBOSE)
+ post("directions[%i]=%i", i, directions[i]);
+
+ }
+ for (i=0; i<VOICES; i++)
+ {
+ for (j=i+1; j<VOICES; j++)
+ {
+ intervals[i][j] = (candidate[i]-candidate[j])%12 ;
+ if (DEBUG_VERBOSE)
+ post("intervals[%i][%i]=%i", i, j, intervals[i][j]);
+ }
+ }
+ SGLIB_ARRAY_SINGLE_QUICK_SORT(short int, notes, VOICES, SGLIB_NUMERIC_COMPARATOR)
+
+ // all same direction?
+ if ( directions[0]==directions[1] &&
+ directions[1]==directions[2] &&
+ directions[2]==directions[3])
+ {
+ // bad!
+ res -= 10;
+ if (DEBUG_VERBOSE)
+ post("same direction!");
+ }
+
+ // parallel 5ths or octaves? (if yes return 0)
+ // how?
+ // hidden 8ths nor 5ths ?
+ for (i=0; i<VOICES; i++)
+ {
+ for (j=i+1; j<VOICES; j++)
+ {
+ if (intervals[i][j]==7 || intervals[i][j]==0)
+ {
+ // hidden or parallel 5th,octave or unison
+ // bad!
+ if (directions[i]==directions[j])
+ {
+ res -= 10;
+ if (DEBUG_VERBOSE)
+ post("hidden or parallel consonance!");
+ }
+ }
+ }
+ }
+
+ // is voice spacing uniform ?(except for the bass)
+ // TODO: use notes[]
+ // are voices average centered?
+ tmp=0;
+ for (i=1; i<VOICES; i++)
+ {
+ tmp+=notes[i];
+ if (DEBUG_VERBOSE)
+ post("average note is %i at passage %i", tmp, i);
+ }
+ // this is the average note
+ tmp = tmp/(VOICES-1);
+ if (DEBUG_VERBOSE)
+ post("average note is %i after division by (VOICES-1)", tmp);
+ tmp = abs((LOWER_POSSIBLE_NOTE + NOTES_RANGE)*2/3 - tmp); // how much average is far from 72
+ res += 30;
+ res -= tmp;
+
+ if (DEBUG_VERBOSE)
+ post("average note is %i far from 2/3 of notes range", tmp);
+
+ tmp=0;
+ /*
+ // are voices average centered?
+ for (i=0; i<VOICES; i++)
+ {
+ tmp+=notes[i];
+ }
+ // this is the average note
+ tmp = tmp/VOICES;
+ tmp = abs(72-tmp); // how much average is far from 72
+ res += 30;
+ res -= tmp;
+ */
+
+ // are intervals small?
+ //res+=50;
+ if (DEBUG_VERBOSE)
+ post("res before transitions %i", res);
+ for (i=0; i<VOICES; i++)
+ {
+ if (DEBUG_VERBOSE)
+ post("transitions[%i] = %i",i, transitions[i]);
+ res-=abs(transitions[i]);
+ // give an incentive for semitones etc..
+ if (transitions[i]==0)
+ res += 5;
+ if (abs(transitions[i]==1))
+ res += 5;
+ if (abs(transitions[i]==2))
+ res += 5;
+ if (abs(transitions[i]==3))
+ res += 2;
+ if (abs(transitions[i]==4))
+ res += 2;
+ if (abs(transitions[i]==5))
+ res += 1;
+ if (abs(transitions[i]==6))
+ res += 1;
+ if (abs(transitions[i]>11))
+ res -= 2;
+ if (abs(transitions[i]>15))
+ res -= 5;
+
+ }
+ if (DEBUG_VERBOSE)
+ post("res after transitions %i", res);
+
+ // TODO: too many near limits?
+
+ // TODO: is a complete chord?
+
+ // penalize too many basses
+ tmp = 0;
+ for (i=0; i<VOICES; i++)
+ {
+ if (notes[i]<48)
+ tmp++;
+ }
+ switch (tmp)
+ {
+ case 0: res -= 5; break;
+ case 1: res += 10; break;
+ case 2: res -= 10; break;
+ case 3: res -= 20; break;
+ case 4: res -= 30; break;
+ }
+
+ if (DEBUG_VERBOSE)
+ post("fitness is %i", res);
+
+ return res;
+}
+
+void new_genotype(t_harmonizer *x, int *mammy, int *daddy, int *kid)
+{
+ int i, split;
+ double rnd;
+ // crossover
+ rnd = rand()/((double)RAND_MAX + 1);
+ split = rnd * VOICES;
+ for (i=0; i<split; i++)
+ {
+ kid[i]=mammy[i];
+ }
+ for (i=split; i<VOICES; i++)
+ {
+ kid[i]=daddy[i];
+ }
+
+ // mutation
+ for (i=0; i<VOICES; i++)
+ {
+ rnd = rand()/((double)RAND_MAX + 1);
+ if (rnd < DEF_PROB_MUTATION)
+ {
+ rnd = rand()/((double)RAND_MAX + 1) * POSSIBLE_NOTES;
+ kid[i]=x->target_notes[(int)rnd];
+ }
+ }
+}
+
+typedef struct fitness_list_element_t
+{
+ int index;
+ int fitness;
+} fitness_list_element;
+
+#define FITNESS_LIST_COMPARATOR(e1, e2) (e1.fitness - e2.fitness)
+
+void generate_voicing(t_harmonizer *x)
+{
+ fitness_list_element fitness_evaluations[MAX_POPULATION];
+ int i, generation, mum, dad, winner;
+ double rnd;
+ t_atom lista[VOICES];
+ // inizialize tables of notes
+ build_possible_notes_table(x);
+ // inizialize population
+ harmonizer_init_pop(x);
+ // GA code
+ for (generation=0; generation<GENERATIONS; generation++)
+ {
+ // i compute all the fitness
+ for (i=0; i<MAX_POPULATION; i++)
+ {
+ fitness_evaluations[i].index=i;
+ fitness_evaluations[i].fitness = fitness(x, x->population[i]);
+ }
+ // i sort the array
+ SGLIB_ARRAY_SINGLE_QUICK_SORT(fitness_list_element, fitness_evaluations, MAX_POPULATION, FITNESS_LIST_COMPARATOR)
+
+ // i kill half population
+ // and use the survivors to create new genotypes
+ for (i=0; i<(MAX_POPULATION/2); i++)
+ {
+ // create a new genotype
+ // parents chosen randomly
+ rnd = rand()/((double)RAND_MAX + 1);
+ mum = MAX_POPULATION/2 + rnd*MAX_POPULATION/2;
+ rnd = rand()/((double)RAND_MAX + 1);
+ dad = MAX_POPULATION/2 + rnd*MAX_POPULATION/2;
+ new_genotype(x, x->population[mum], x->population[dad], x->population[i]);
+ }
+ // repeat the process
+ }
+ // finally look for the winner
+ // i compute all the fitness
+ for (i=0; i<MAX_POPULATION; i++)
+ {
+ fitness_evaluations[i].index=i;
+ fitness_evaluations[i].fitness = fitness(x, x->population[i]);
+ }
+ // i sort the array
+ SGLIB_ARRAY_SINGLE_QUICK_SORT(fitness_list_element, fitness_evaluations, MAX_POPULATION, FITNESS_LIST_COMPARATOR)
+
+ winner = fitness_evaluations[MAX_POPULATION-1].index;
+
+ if (DEBUG)
+ post("winner fitness = %i", fitness_evaluations[MAX_POPULATION-1].fitness);
+
+ for (i=0;i<VOICES;i++)
+ {
+ SETFLOAT(lista+i, x->population[winner][i]);
+ }
+
+ // send output array to outlet
+ outlet_anything(x->l_out,
+ gensym("list") ,
+ VOICES,
+ lista);
+}
+
+// if i want another voicing i can send a bang
+static void harmonizer_bang(t_harmonizer *x) {
+ generate_voicing(x);
+}
+
+// called when i send a list (with midi values)
+void set_current_voices(t_harmonizer *x, t_symbol *sl, int argc, t_atom *argv)
+{
+ int i=0;
+
+ if (argc<VOICES)
+ {
+ error("insufficient notes sent!");
+ return;
+ }
+ // fill input array with actual data sent to inlet
+ for (i=0;i<VOICES;i++)
+ {
+ x->current_voices[i] = atom_getint(argv++);
+ }
+
+ generate_voicing(x);
+
+
+}
+// set current chord
+void set_current(t_harmonizer *x, t_symbol *s) {
+ x->current_chord.mode = string2mode(s->s_name);
+ x->current_chord.note = string2note(s->s_name);
+ if (DEBUG)
+ post("harmonizer: set_current %s",s->s_name);
+}
+
+// set target chord
+void set_target(t_harmonizer *x, t_symbol *s) {
+ x->target_chord.mode = string2mode(s->s_name);
+ x->target_chord.note = string2note(s->s_name);
+ if (DEBUG)
+ post("harmonizer: set_target %s",s->s_name);
+}
+
+
+void *harmonizer_new(t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ time_t a;
+ t_harmonizer *x = (t_harmonizer *)pd_new(harmonizer_class);
+ x->l_out = outlet_new(&x->x_obj, &s_list);
+/*
+ for (i=0; i<BUFFER_LENGHT; i++)
+ {
+ x->last[i] = harmonizer_note2gene(1,0,0,1);
+ }
+ */
+ srand(time(&a));
+
+ return (x);
+}
+
+void harmonizer_setup(void)
+{
+ harmonizer_class = class_new(gensym("harmonizer"), (t_newmethod)harmonizer_new,
+ (t_method)harmonizer_free, sizeof(t_harmonizer), CLASS_DEFAULT, A_GIMME, 0);
+ class_addbang(harmonizer_class, (t_method)harmonizer_bang);
+ class_addmethod(harmonizer_class, (t_method)set_current, gensym("current"),A_SYMBOL, 0);
+ class_addmethod(harmonizer_class, (t_method)set_target, gensym("target"),A_SYMBOL, 0);
+// class_addmethod(harmonizer_class, (t_method)harmonizer_fitness1_set, gensym("fitness1"), A_DEFFLOAT, 0);
+ class_addlist(harmonizer_class, (t_method)set_current_voices);
+
+
+}
diff --git a/makefile.darwin b/makefile.darwin
new file mode 100755
index 0000000..79914a5
--- /dev/null
+++ b/makefile.darwin
@@ -0,0 +1,37 @@
+current: pd_darwin
+
+clean: ; rm -f *.pd_linux *.o *.pd_darwin
+
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: chord_melo.pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+
+# where are the PD header files?
+# leave it blank if it is a system directory (like /usr/local/include),
+# since gcc 3.2 complains about it
+PDPATH=/Users/Development/music/puredatacvs/devel_0_39/src
+#PDPATH=/Users/davidemorelli/Desktop/robaDavide/Pd-0.38-3.app/Contents/Resources/src/
+
+# where is the PD executable?
+PD=/Applications/PdOLD.app/Contents/Resources/bin/pd
+#PD=/usr/local/lib/pd/bin/pd
+#PD=/Users/davidemorelli/Desktop/robaDavide/Pd-0.38-3.app/Contents/Resources/bin/pd
+#PD=/Users/davidemorelli/Desktop/robaDavide/Pd-0.38-3.app/Contents/Resources/src/
+
+
+DARWININCLUDE = -I../../src -I$(PDPATH)
+
+DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.pd_darwin:
+ cc $(DARWINCFLAGS) $(DARWININCLUDE) -o $*.o -c $*.c
+ cc -bundle -bundle_loader $(PD) -flat_namespace -o $*.pd_darwin *.o
+# cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin
+# rm -f $*.o
+
+# $(FANNLIB)
diff --git a/manager.pd b/manager.pd
new file mode 100755
index 0000000..f2a7ff6
--- /dev/null
+++ b/manager.pd
@@ -0,0 +1,14 @@
+#N canvas 494 138 557 435 12;
+#X obj 136 186 select 0;
+#X obj 124 266 random 2;
+#X obj 137 211 t a a a;
+#X obj 137 235 bang;
+#X obj 140 130 inlet;
+#X obj 133 304 outlet;
+#X msg 250 143 0;
+#X connect 0 0 2 0;
+#X connect 1 0 5 0;
+#X connect 2 0 3 0;
+#X connect 3 0 1 0;
+#X connect 4 0 0 0;
+#X connect 6 0 0 0;
diff --git a/patches/SHOWME.pd b/patches/SHOWME.pd
new file mode 100755
index 0000000..539fabb
--- /dev/null
+++ b/patches/SHOWME.pd
@@ -0,0 +1,28 @@
+#N canvas 203 60 777 510 12;
+#X obj 572 56 chord_melo_test2;
+#X obj 531 85 tabwrite src;
+#X obj 644 87 tabwrite dest;
+#N canvas 0 0 450 300 graph25 0;
+#X array src 16 float 1;
+#A 0 55 59 62 60 52 50 48 47 48 55 57 59 60 55 52 48;
+#X array dest 16 float 1;
+#A 0 41 67 72 57 55 53 46 44 55 64 40 72 76 62 42 60;
+#X coords 0 127 15 0 400 250 1;
+#X restore 75 32 graph;
+#X obj 572 38 tgl 15 0 empty empty START 0 -6 0 8 -258699 -1 -1 1 1
+;
+#X floatatom 550 138 5 0 0 0 - - -;
+#X floatatom 596 138 5 0 0 0 - - -;
+#X floatatom 648 137 5 0 0 0 - - -;
+#X obj 591 279 tgl 15 0 toggleSRC empty src 0 -6 0 8 -262144 -1 -1
+1 1;
+#X obj 627 279 tgl 15 0 toggleOUT empty out 0 -6 0 8 -262144 -1 -1
+0 1;
+#X connect 0 0 1 0;
+#X connect 0 0 5 0;
+#X connect 0 1 2 0;
+#X connect 0 1 6 0;
+#X connect 0 2 1 1;
+#X connect 0 2 2 1;
+#X connect 0 2 7 0;
+#X connect 4 0 0 0;
diff --git a/patches/bay.orc b/patches/bay.orc
new file mode 100755
index 0000000..e754d31
--- /dev/null
+++ b/patches/bay.orc
@@ -0,0 +1,418 @@
+; ================================================================
+; Header
+; ================================================================
+sr=44100
+kr=882
+ksmps=50
+nchnls=2
+
+; ================================================================
+; Globals
+; ================================================================
+zakinit 10,10
+
+; Global variable for the reverb unit
+ga1 init 0
+
+; ================================================================
+; Tables
+; ================================================================
+; Waveform for the string-pad
+iwave ftgen 1, 0, 4096, 10, 1, .5, .33, .25, .0, .1, .1, .1
+
+; Senoid required by chorus
+isine ftgen 2, 0, 4096, 10, 1
+
+
+; ================================================================
+; Instruments
+; ================================================================
+
+
+instr 1 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz1"
+kpos invalue "pos1"
+kamp invalue "amp1"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+
+instr 2 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz2"
+kpos invalue "pos2"
+kamp invalue "amp2"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+instr 3 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+ ; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz3"
+kpos invalue "pos3"
+kamp invalue "amp3"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+instr 4 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+; ihz = p4
+; idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+; ipos = p6
+; iamp = ampdb(idb)
+
+; modified by dmorelli
+khz invalue "hz4"
+kpos invalue "pos4"
+kamp invalue "amp4"
+kctrl = kamp*70
+kctrl = ampdb(kctrl)
+ ; Slow attack and release
+; kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, khz, 1 ; audio oscillator
+ acel1 oscil kctrl, khz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, khz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ kppan = kpos*1.570796325 ; half of PI (radians of 90o angle)
+ kpleft = cos(kppan) ; half sign "down"
+ kpright = sin(kppan) ; half sign "up"
+ asig1 = asig*kpleft;
+ asig2 = asig*kpright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+
+
+
+
+; strumento senza invalue
+
+instr 9 ;String pad
+; String-pad borrwoed from the piece "Dorian Gray",
+; http://akozar.spymac.net/music/ Modified to fit my needs
+
+ ihz = p4
+ idb = p5/127 * 70 ; rescale MIDI velocity to 70db
+ ipos = p6
+ iamp = ampdb(idb)
+
+; modified by dmorelli
+
+;kpos invalue "pos1"
+;kamp invalue "amp1"
+;kctrl = kamp*70
+;kctrl = ampdb(kctrl)
+ ; Slow attack and release
+ kctrl linseg 0, p3/4, iamp, p3/2, 0
+ ; Slight chorus effect
+ afund oscil kctrl, ihz, 1 ; audio oscillator
+ acel1 oscil kctrl, ihz - .1, 1 ; audio oscillator - flat
+ acel2 oscil kctrl, ihz + .1, 1 ; audio oscillator - sharp
+ asig = afund + acel1 + acel2
+
+ ; Cut-off high frequencies depending on midi-velocity
+ ; (larger velocity implies more brighter sound)
+ asig butterlp asig, (p5-60)*40+900
+
+ ; Panning
+ ippan = ipos*1.570796325 ; half of PI (radians of 90o angle)
+ ipleft = cos(ippan) ; half sign "down"
+ ipright = sin(ippan) ; half sign "up"
+ asig1 = asig*ipleft;
+ asig2 = asig*ipright;
+ ; To the chorus effect, through zak channels 1 and 2
+ zawm asig1, 1
+ zawm asig2, 2
+endin
+
+; ================================================================
+; EFFECTS
+; ================================================================
+
+
+; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+; Chorus effect, borrowed from http://www.jlpublishing.com/Csound.htm
+; I made some of its parameters accesible trhough score
+instr 10 ;Chorus
+ ; Read input from zak
+ a1 zar 1
+ a2 zar 2
+ idlyml=p4 ;delay in milliseconds
+ k1 oscili idlyml/p5, 1, 2
+ ar1l vdelay3 a1, idlyml/5+k1, 900 ;delayed sound 1
+ ar1r vdelay3 a2, idlyml/5+k1, 900 ;delayed sound 1
+ k2 oscili idlyml/p5, .995, 2
+ ar2l vdelay3 a1, idlyml/5+k2, 700 ;delayed sound 2
+ ar2r vdelay3 a2, idlyml/5+k2, 700 ;delayed sound 2
+ k3 oscili idlyml/p5, 1.05, 2
+ ar3l vdelay3 a1, idlyml/5+k3, 700 ;delayed sound 3
+ ar3r vdelay3 a2, idlyml/5+k3, 700 ;delayed sound 3
+ k4 oscili idlyml/p5, 1, 2
+ ar4l vdelay3 a1, idlyml/5+k4, 900 ;delayed sound 4
+ ar4r vdelay3 a2, idlyml/5+k4, 900 ;delayed sound 4
+ aoutl = (a1+ar1l+ar2l+ar3l+ar4l)*.5
+ aoutr = (a2+ar1r+ar2r+ar3r+ar4r)*.5
+
+ ; To the output mixer
+ zawm aoutl, 5
+ zawm aoutr, 6
+ ; and also to the reverb unit
+ ga1 = ga1 + (aoutl+aoutr)*.5
+endin
+
+; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+; Reverb
+; 8 delay line FDN reverb, with feedback matrix based upon
+; physical modeling scattering junction of 8 lossless waveguides
+; of equal characteristic impedance. Based on Julius O. Smith III,
+; "A New Approach to Digital Reverberation using Closed Waveguide
+; Networks," Proceedings of the International Computer Music
+; Conference 1985, p. 47-53 (also available as a seperate
+; publication from CCRMA), as well as some more recent papers by
+; Smith and others.
+;
+; Coded by Sean Costello, October 1999
+instr 25 ;Reverb
+ ; Note: ga1 is the global input to the reverb.
+ afilt1 init 0
+ afilt2 init 0
+ afilt3 init 0
+ afilt4 init 0
+ afilt5 init 0
+ afilt6 init 0
+ afilt7 init 0
+ afilt8 init 0
+ idel1 = (2473.000/sr)
+ idel2 = (2767.000/sr)
+ idel3 = (3217.000/sr)
+ idel4 = (3557.000/sr)
+ idel5 = (3907.000/sr)
+ idel6 = (4127.000/sr)
+ idel7 = (2143.000/sr)
+ idel8 = (1933.000/sr)
+
+
+ igain = p4 ; gain of reverb. Adjust empirically
+ ; for desired reverb time. .6 gives
+ ; a good small "live" room sound, .8
+ ; a small hall, .9 a large hall,
+ ; .99 an enormous stone cavern.
+
+ ipitchmod = p5 ; amount of random pitch modulation
+ ; for the delay lines. 1 is the "normal"
+ ; amount, but this may be too high for
+ ; held pitches such as piano tones.
+ ; Adjust to taste.
+
+ itone = p6 ; Cutoff frequency of lowpass filters
+ ; in feedback loops of delay lines,
+ ; in Hz. Lower cutoff frequencies results
+ ; in a sound with more high-frequency
+ ; damping.
+
+ ; k1-k8 are used to add random pitch modulation to the
+ ; delay lines. Helps eliminate metallic overtones
+ ; in the reverb sound.
+ k1 randi .001, 3.1, .06
+ k2 randi .0011, 3.5, .9
+ k3 randi .0017, 1.11, .7
+ k4 randi .0006, 3.973, .3
+ k5 randi .001, 2.341, .63
+ k6 randi .0011, 1.897, .7
+ k7 randi .0017, 0.891, .9
+ k8 randi .0006, 3.221, .44
+ ; apj is used to calculate "resultant junction pressure" for
+ ; the scattering junction of 8 lossless waveguides
+ ; of equal characteristic impedance. If you wish to
+ ; add more delay lines, simply add them to the following
+ ; equation, and replace the .25 by 2/N, where N is the
+ ; number of delay lines.
+ apj = .25 * (afilt1 + afilt2 + afilt3 + afilt4 + afilt5 + afilt6 + afilt7 + afilt8)
+
+
+ adum1 delayr 1
+ adel1 deltapi idel1 + k1 * ipitchmod
+ delayw ga1 + apj - afilt1
+
+ adum2 delayr 1
+ adel2 deltapi idel2 + k2 * ipitchmod
+ delayw ga1 + apj - afilt2
+
+ adum3 delayr 1
+ adel3 deltapi idel3 + k3 * ipitchmod
+ delayw ga1 + apj - afilt3
+
+ adum4 delayr 1
+ adel4 deltapi idel4 + k4 * ipitchmod
+ delayw ga1 + apj - afilt4
+
+ adum5 delayr 1
+ adel5 deltapi idel5 + k5 * ipitchmod
+ delayw ga1 + apj - afilt5
+
+ adum6 delayr 1
+ adel6 deltapi idel6 + k6 * ipitchmod
+ delayw ga1 + apj - afilt6
+
+ adum7 delayr 1
+ adel7 deltapi idel7 + k7 * ipitchmod
+ delayw ga1 + apj - afilt7
+
+ adum8 delayr 1
+ adel8 deltapi idel8 + k8 * ipitchmod
+ delayw ga1 + apj - afilt8
+
+ ; 1st order lowpass filters in feedback
+ ; loops of delay lines.
+ afilt1 tone adel1 * igain, itone
+ afilt2 tone adel2 * igain, itone
+ afilt3 tone adel3 * igain, itone
+ afilt4 tone adel4 * igain, itone
+ afilt5 tone adel5 * igain, itone
+ afilt6 tone adel6 * igain, itone
+ afilt7 tone adel7 * igain, itone
+ afilt8 tone adel8 * igain, itone
+
+ ; The outputs of the delay lines are summed
+ ; and sent to the stereo outputs. This could
+ ; easily be modified for a 4 or 8-channel
+ ; sound system.
+ aout1 = (afilt1 + afilt3 + afilt5 + afilt7)
+ aout2 = (afilt2 + afilt4 + afilt6 + afilt8)
+ ;outs aout1, aout2
+ ; To the output mixer
+ zawm aout1, 5
+ zawm aout2, 6
+ ga1 = 0
+endin
+
+
+; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+; Output mixer
+; It applies a bass enhancement, compression and fadeout
+; to the whole piece,
+instr 30 ;Mixer
+ ; Read input from zak
+ a1 zar 5
+ a2 zar 6
+ ; Bass enhancement
+ al1 butterlp a1, 100
+ al2 butterlp a2, 100
+ a1 = al1*1.5 +a1
+ a2 = al2*1.5 +a2
+
+ ; Global amplitude shape
+ ; It applies a gain of p4 to the whole piece, and creates a
+ ; fadeout the last p5 seconds
+ kenv linseg p4, p3-p5, p4, p5, 0
+ a1=a1*kenv
+ a2=a2*kenv
+
+ ; Compression
+ a1 dam a1, 5000, 0.5, 1, 0.2, 0.1
+ a2 dam a2, 5000, 0.5, 1, 0.2, 0.1
+
+ outs a1, a2
+ zacl 0, 10
+endin
+
diff --git a/patches/test-harmonizer2.pd b/patches/test-harmonizer2.pd
new file mode 100755
index 0000000..ed41e1e
--- /dev/null
+++ b/patches/test-harmonizer2.pd
@@ -0,0 +1,185 @@
+#N canvas 74 28 903 675 12;
+#X symbolatom 157 205 18 0 0 2 next_chord - -;
+#N canvas 39 349 531 328 readme 0;
+#X text 59 31 howto populate the graph: play the chord \, when the
+output of [chord] is ok bang the "add" message. bang it each time you
+change chord \, it will store the transitions;
+#X text 56 120 howto ask for the next chord: play the chord \, bang
+the "set" message \, this will set the current chord without adding
+it to the graph's memory \, now bang the next 1 message. this chord_graph
+will respond with the chord you played most of the times after the
+current chord. you can send "next x" where x is from 0 to 1 \, 0 =
+max novelty \, 1= min novelty;
+#X text 56 259 you can save graph state sending the write message;
+#X restore 607 47 pd readme;
+#X obj 121 329 harmonizer;
+#X msg 52 286 current \$1;
+#X msg 158 283 target \$1;
+#X obj 52 262 symbol;
+#X obj 52 242 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 157 261 symbol;
+#X obj 289 261 int 36;
+#X obj 355 262 int 60;
+#X obj 426 260 int 67;
+#X obj 494 259 int 76;
+#X obj 566 262 int 84;
+#X obj 335 289 pack f f f f f;
+#X obj 358 233 t b b b b b;
+#X obj 246 369 unpack f f f f f;
+#X obj 153 97 symbol;
+#X obj 98 43 bng 15 250 50 0 empty empty change_chord 0 -6 0 8 -262144
+-1 -1;
+#X msg 153 121 set \$1;
+#N canvas 0 0 706 416 midi 0;
+#X obj 141 253 outlet;
+#X obj 271 31 notein;
+#X obj 271 66 chord 59;
+#X msg 175 149 add \$1;
+#X obj 175 121 symbol;
+#X obj 176 94 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 248 163 symbol;
+#X obj 249 136 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 248 191 set \$1;
+#X symbolatom 311 101 25 0 0 0 - - -;
+#X connect 1 0 2 0;
+#X connect 1 1 2 1;
+#X connect 2 2 4 1;
+#X connect 2 2 6 1;
+#X connect 2 2 9 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 8 0;
+#X connect 7 0 6 0;
+#X connect 8 0 0 0;
+#X restore 423 135 pd midi;
+#N canvas 0 0 454 304 fileIO 0;
+#X obj 143 225 outlet;
+#X msg 115 77 write test.graph;
+#X msg 145 105 read test.graph;
+#X msg 175 135 init 1;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X restore 340 134 pd fileIO;
+#X obj 100 73 t b b;
+#X obj 157 228 t b a;
+#X obj 28 404 bang;
+#X obj 203 420 mtof;
+#X obj 252 419 mtof;
+#X obj 337 423 mtof;
+#X obj 180 601 dac~;
+#X obj 109 431 print;
+#X obj 74 111 f 1;
+#X msg 59 135 next \$1;
+#X obj 63 70 vsl 15 30 0 1 0 0 empty empty empty 0 -8 0 8 -262144 -1
+-1 2900 1;
+#X floatatom 32 112 5 0 0 0 - - -;
+#X obj 178 571 csoundapi~ bay.orc;
+#X msg 488 520 event i 10 0 17000 10 30;
+#X msg 488 543 event i 30 0 17000 2 30;
+#X msg 489 496 event i 25 0 17000 0.98 0.8 20000;
+#X obj 482 458 loadbang;
+#X msg 196 492 event i 9 0 10 \$1 80 0.5;
+#X obj 295 422 mtof;
+#X obj 381 424 mtof;
+#X obj 462 22 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 462 41 metro 7000;
+#X obj 13 32 r novelty;
+#X obj 599 121 int 0;
+#X obj 646 120 + 1;
+#X obj 600 171 tabread tab-novelty;
+#X obj 600 194 s novelty;
+#X obj 685 119 table tab-novelty;
+#X obj 600 147 % 10;
+#X obj 462 63 t b b;
+#X msg 467 377 \; tab-novelty 0 1 1 0.8 0.7 0.3 0.5 0.9 0.1 0 0.2;
+#X obj 220 96 symbol;
+#X msg 220 124 tonality \$1;
+#X obj 220 72 bng 15 250 50 0 empty empty change 0 -6 0 8 -262144 -1
+-1;
+#X obj 19 160 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X symbolatom 305 204 15 0 0 2 tonality - -;
+#X obj 83 169 chords_memory test.graph;
+#X connect 2 0 15 0;
+#X connect 2 0 28 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 4 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 1;
+#X connect 10 0 13 2;
+#X connect 11 0 13 3;
+#X connect 12 0 13 4;
+#X connect 13 0 2 0;
+#X connect 14 0 8 0;
+#X connect 14 1 9 0;
+#X connect 14 2 10 0;
+#X connect 14 3 11 0;
+#X connect 14 4 12 0;
+#X connect 15 0 8 1;
+#X connect 15 0 23 0;
+#X connect 15 0 24 0;
+#X connect 15 1 9 1;
+#X connect 15 1 25 0;
+#X connect 15 2 10 1;
+#X connect 15 2 39 0;
+#X connect 15 3 11 1;
+#X connect 15 3 26 0;
+#X connect 15 4 12 1;
+#X connect 15 4 40 0;
+#X connect 16 0 18 0;
+#X connect 17 0 21 0;
+#X connect 18 0 57 0;
+#X connect 19 0 57 0;
+#X connect 20 0 57 0;
+#X connect 21 0 29 0;
+#X connect 22 0 14 0;
+#X connect 22 1 7 0;
+#X connect 23 0 5 0;
+#X connect 24 0 38 0;
+#X connect 25 0 38 0;
+#X connect 26 0 38 0;
+#X connect 29 0 30 0;
+#X connect 30 0 57 0;
+#X connect 31 0 29 1;
+#X connect 31 0 32 0;
+#X connect 33 0 27 0;
+#X connect 33 1 27 1;
+#X connect 34 0 33 0;
+#X connect 35 0 33 0;
+#X connect 36 0 33 0;
+#X connect 37 0 36 0;
+#X connect 37 0 34 0;
+#X connect 37 0 35 0;
+#X connect 37 0 51 0;
+#X connect 38 0 33 0;
+#X connect 39 0 38 0;
+#X connect 40 0 38 0;
+#X connect 41 0 42 0;
+#X connect 42 0 50 0;
+#X connect 43 0 31 0;
+#X connect 44 0 45 0;
+#X connect 44 0 49 0;
+#X connect 45 0 44 1;
+#X connect 46 0 47 0;
+#X connect 49 0 46 0;
+#X connect 50 0 21 0;
+#X connect 50 1 44 0;
+#X connect 52 0 53 0;
+#X connect 53 0 57 0;
+#X connect 54 0 52 0;
+#X connect 55 0 57 0;
+#X connect 57 0 0 0;
+#X connect 57 0 5 1;
+#X connect 57 0 22 0;
+#X connect 57 0 52 1;
+#X connect 57 0 16 0;
+#X connect 57 1 56 0;
diff --git a/patches/test.graph b/patches/test.graph
new file mode 100755
index 0000000..0c18d7e
--- /dev/null
+++ b/patches/test.graph
Binary files differ
diff --git a/ritmo1.c b/ritmo1.c
new file mode 100755
index 0000000..e7a848a
--- /dev/null
+++ b/ritmo1.c
@@ -0,0 +1,115 @@
+/*
+ritmo1
+try to extract the current pattern
+*/
+#include "m_pd.h"
+
+#define BUFFER_LENGHT 16
+
+static t_class *ritmo1_class;
+
+typedef struct _ritmo1
+{
+ t_object x_obj; // myself
+ t_symbol *x_arrayname_src; // where i read the current pattern
+ t_symbol *x_arrayname_dest; // where i put the computed pattern
+ t_float *buf1;
+ t_float *buf2;
+ t_float *buf3;
+} t_ritmo1;
+
+void ritmo1_allocate_buffers(t_ritmo1 *x)
+{
+ x->buf1 = (t_float *)getbytes(BUFFER_LENGHT * sizeof(t_float));
+ x->buf2 = (t_float *)getbytes(BUFFER_LENGHT * sizeof(t_float));
+ x->buf3 = (t_float *)getbytes(BUFFER_LENGHT * sizeof(t_float));
+}
+
+void ritmo1_free(t_ritmo1 *x)
+{
+ freebytes(x->buf1, sizeof(x->buf1));
+ freebytes(x->buf2, sizeof(x->buf2));
+ freebytes(x->buf3, sizeof(x->buf3));}
+
+static void ritmo1_bang(t_ritmo1 *x) {
+
+ int i, vecsize;
+ t_garray *arysrc;
+ t_garray *arydest;
+ t_float *vecsrc;
+ t_float *vecdest;
+
+ if (!(arysrc = (t_garray *)pd_findbyclass(x->x_arrayname_src, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_src->s_name);
+ }
+ else if (!garray_getfloatarray(arysrc, &vecsize, &vecsrc))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_src->s_name);
+ }
+ else if (!(arydest = (t_garray *)pd_findbyclass(x->x_arrayname_dest, garray_class)))
+ {
+ pd_error(x, "%s: no such array", x->x_arrayname_dest->s_name);
+ }
+ else if (!garray_getfloatarray(arydest, &vecsize, &vecdest))
+ {
+ pd_error(x, "%s: bad template for tabwrite", x->x_arrayname_dest->s_name);
+ }
+ else // I got arrays and data
+ {
+ // step 1: compute the pattern
+ // and write it in vecdest
+ for (i=0; i<16; i++)
+ {
+ vecdest[i] = (x->buf1[i] + x->buf2[i] + x->buf3[i] + vecsrc[i])/4;
+ }
+ // redraw the arrays
+ garray_redraw(arysrc);
+ garray_redraw(arydest);
+
+ // step 2: cycle buffers
+ x->buf3 = x->buf2;
+ x->buf2 = x->buf1;
+ x->buf1 = x->buf3;
+ // fill the first buffer with src data
+ for (i=0; i<16; i++)
+ {
+ x->buf1[i] = vecsrc[i];
+ vecsrc[i]=0;
+ }
+ }
+}
+
+static void ritmo1_src(t_ritmo1 *x, t_symbol *s) {
+ x->x_arrayname_src = s;
+}
+
+static void ritmo1_dest(t_ritmo1 *x, t_symbol *s) {
+ x->x_arrayname_dest = s;
+}
+
+static void *ritmo1_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_ritmo1 *x = (t_ritmo1 *)pd_new(ritmo1_class);
+ ritmo1_allocate_buffers(x);
+ if (argc>0)
+ {
+ x->x_arrayname_src = atom_getsymbolarg(0, argc, argv);
+ }
+ if (argc>1)
+ {
+ x->x_arrayname_dest = atom_getsymbolarg(1, argc, argv);
+ }
+ return (x);
+}
+
+void ritmo1_setup(void)
+{
+ ritmo1_class = class_new(gensym("ritmo1"), (t_newmethod)ritmo1_new,
+ (t_method)ritmo1_free, sizeof(t_ritmo1), CLASS_DEFAULT, A_GIMME, 0);
+ class_addbang(ritmo1_class, (t_method)ritmo1_bang);
+ class_addmethod(ritmo1_class, (t_method)ritmo1_src, gensym("src"),A_SYMBOL, 0);
+ class_addmethod(ritmo1_class, (t_method)ritmo1_dest, gensym("dest"),A_SYMBOL, 0);
+}
+
+
diff --git a/sglib.h b/sglib.h
new file mode 100755
index 0000000..6c88a32
--- /dev/null
+++ b/sglib.h
@@ -0,0 +1,1947 @@
+/*
+
+ This is SGLIB version 1.0.3
+
+ (C) by Marian Vittek, Bratislava, http://www.xref-tech.com/sglib, 2003-5
+
+ License Conditions: You can use a verbatim copy (including this
+ copyright notice) of sglib freely in any project, commercial or not.
+ You can also use derivative forms freely under terms of Open Source
+ Software license or under terms of GNU Public License. If you need
+ to use a derivative form in a commercial project, or you need sglib
+ under any other license conditions, contact the author.
+
+*/
+
+
+#ifndef _SGLIB__h_
+#define _SGLIB__h_
+
+/* the assert is used exclusively to write unexpected error messages */
+#include <assert.h>
+
+
+/* ---------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------- */
+/* - LEVEL - 0 INTERFACE - */
+/* ---------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------------- */
+/* ------------------------------ STATIC ARRAYS ------------------------------- */
+/* ---------------------------------------------------------------------------- */
+
+/*
+
+ Basic algorithms for sorting arrays. Multiple depending arrays can
+ be rearranged using user defined 'elem_exchangers'
+
+*/
+
+/* HEAP - SORT (level 0) */
+
+#define SGLIB_ARRAY_SINGLE_HEAP_SORT(type, a, max, comparator) {\
+ SGLIB_ARRAY_HEAP_SORT(type, a, max, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\
+}
+
+#define SGLIB_ARRAY_HEAP_SORT(type, a, max, comparator, elem_exchanger) {\
+ int _k_;\
+ for(_k_=(max)/2; _k_>=0; _k_--) {\
+ SGLIB___ARRAY_HEAP_DOWN(type, a, _k_, max, comparator, elem_exchanger);\
+ }\
+ for(_k_=(max)-1; _k_>=0; _k_--) {\
+ elem_exchanger(type, a, 0, _k_);\
+ SGLIB___ARRAY_HEAP_DOWN(type, a, 0, _k_, comparator, elem_exchanger);\
+ }\
+}
+
+#define SGLIB___ARRAY_HEAP_DOWN(type, a, ind, max, comparator, elem_exchanger) {\
+ type _t_;\
+ int _m_, _l_, _r_, _i_;\
+ _i_ = (ind);\
+ _m_ = _i_;\
+ do {\
+ _i_ = _m_; \
+ _l_ = 2*_i_+1;\
+ _r_ = _l_+1;\
+ if (_l_ < (max)){\
+ if (comparator(((a)[_m_]), ((a)[_l_])) < 0) _m_ = _l_;\
+ if (_r_ < (max)) {\
+ if (comparator(((a)[_m_]), ((a)[_r_])) < 0) _m_ = _r_;\
+ }\
+ }\
+ if (_m_ != _i_) {\
+ elem_exchanger(type, a, _i_, _m_);\
+ }\
+ } while (_m_ != _i_);\
+}
+
+
+/* QUICK - SORT (level 0) */
+
+#define SGLIB_ARRAY_SINGLE_QUICK_SORT(type, a, max, comparator) {\
+ SGLIB_ARRAY_QUICK_SORT(type, a, max, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\
+}
+
+#define SGLIB_ARRAY_QUICK_SORT(type, a, max, comparator, elem_exchanger) {\
+ int _i_, _j_, _p_, _stacki_, _start_, _end_;\
+ /* can sort up to 2^64 elements */\
+ int _startStack_[64]; \
+ int _endStack_[64];\
+ type _tmp_;\
+ _startStack_[0] = 0;\
+ _endStack_[0] = (max);\
+ _stacki_ = 1;\
+ while (_stacki_ > 0) {\
+ _stacki_ --;\
+ _start_ = _startStack_[_stacki_];\
+ _end_ = _endStack_[_stacki_];\
+ while (_end_ - _start_ > 2) {\
+ _p_ = _start_;\
+ _i_ = _start_ + 1;\
+ _j_ = _end_ - 1;\
+ while (_i_<_j_) {\
+ for(; _i_<=_j_ && comparator(((a)[_i_]),((a)[_p_]))<=0; _i_++) ;\
+ if (_i_ > _j_) {\
+ /* all remaining elements lesseq than pivot */\
+ elem_exchanger(type, a, _j_, _p_);\
+ _i_ = _j_;\
+ } else {\
+ for(; _i_<=_j_ && comparator(((a)[_j_]),((a)[_p_]))>=0; _j_--) ;\
+ if (_i_ > _j_) {\
+ /* all remaining elements greater than pivot */\
+ elem_exchanger(type, a, _j_, _p_);\
+ _i_ = _j_;\
+ } else if (_i_ < _j_) {\
+ elem_exchanger(type, a, _i_, _j_);\
+ if (_i_+2 < _j_) {_i_++; _j_--;}\
+ else if (_i_+1 < _j_) _i_++;\
+ }\
+ }\
+ }\
+ /* O.K. i==j and pivot is on a[i] == a[j] */\
+ /* handle recursive calls without recursion */\
+ if (_i_-_start_ > 1 && _end_-_j_ > 1) {\
+ /* two recursive calls, use array-stack */\
+ if (_i_-_start_ < _end_-_j_-1) {\
+ _startStack_[_stacki_] = _j_+1;\
+ _endStack_[_stacki_] = _end_;\
+ _stacki_ ++;\
+ _end_ = _i_;\
+ } else {\
+ _startStack_[_stacki_] = _start_;\
+ _endStack_[_stacki_] = _i_;\
+ _stacki_ ++;\
+ _start_ = _j_+1;\
+ }\
+ } else {\
+ if (_i_-_start_ > 1) {\
+ _end_ = _i_;\
+ } else {\
+ _start_ = _j_+1;\
+ }\
+ }\
+ }\
+ if (_end_ - _start_ == 2) {\
+ if (comparator(((a)[_start_]),((a)[_end_-1])) > 0) {\
+ elem_exchanger(type, a, _start_, _end_-1);\
+ }\
+ }\
+ }\
+}
+
+/* BINARY SEARCH (level 0) */
+
+#define SGLIB_ARRAY_BINARY_SEARCH(type, a, start_index, end_index, key, comparator, found, result_index) {\
+ int _kk_, _cc_, _ii_, _jj_, _ff_;\
+ _ii_ = (start_index); \
+ _jj_ = (end_index);\
+ _ff_ = 0;\
+ while (_ii_ <= _jj_ && _ff_==0) {\
+ _kk_ = (_jj_+_ii_)/2;\
+ _cc_ = comparator(((a)[_kk_]), (key));\
+ if (_cc_ == 0) {\
+ (result_index) = _kk_; \
+ _ff_ = 1;\
+ } else if (_cc_ < 0) {\
+ _ii_ = _kk_+1;\
+ } else {\
+ _jj_ = _kk_-1;\
+ }\
+ }\
+ if (_ff_ == 0) {\
+ /* not found, but set its resulting place in the array */\
+ (result_index) = _jj_+1;\
+ }\
+ (found) = _ff_;\
+}
+
+/* -------------------------------- queue (in an array) ------------------ */
+/* queue is a quadruple (a,i,j,dim) such that: */
+/* a is the array storing values */
+/* i is the index of the first used element in the array */
+/* j is the index of the first free element in the array */
+/* dim is the size of the array a */
+/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */
+
+#define SGLIB_QUEUE_INIT(type, a, i, j) { i = j = 0; }
+#define SGLIB_QUEUE_IS_EMPTY(type, a, i, j) ((i)==(j))
+#define SGLIB_QUEUE_IS_FULL(type, a, i, j, dim) ((i)==((j)+1)%(dim))
+#define SGLIB_QUEUE_FIRST_ELEMENT(type, a, i, j) (a[i])
+#define SGLIB_QUEUE_ADD_NEXT(type, a, i, j, dim) {\
+ if (SGLIB_QUEUE_IS_FULL(type, a, i, j, dim)) assert(0 && "the queue is full");\
+ (j) = ((j)+1) % (dim);\
+}
+#define SGLIB_QUEUE_ADD(type, a, elem, i, j, dim) {\
+ a[j] = (elem);\
+ SGLIB_QUEUE_ADD_NEXT(type, a, i, j, dim);\
+}
+#define SGLIB_QUEUE_DELETE_FIRST(type, a, i, j, dim) {\
+ if (SGLIB_QUEUE_IS_EMPTY(type, a, i, j)) assert(0 && "the queue is empty");\
+ (i) = ((i)+1) % (dim);\
+}
+#define SGLIB_QUEUE_DELETE(type, a, i, j, dim) {\
+ SGLIB_QUEUE_DELETE_FIRST(type, a, i, j, dim);\
+}
+
+/* ----------------- priority queue (heap) (in an array) -------------------- */
+/* heap is a triple (a,i,dim) such that: */
+/* a is the array storing values */
+/* i is the index of the first free element in the array */
+/* dim is the size of the array a */
+/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */
+
+#define SGLIB_HEAP_INIT(type, a, i) { i = 0; }
+#define SGLIB_HEAP_IS_EMPTY(type, a, i) ((i)==0)
+#define SGLIB_HEAP_IS_FULL(type, a, i, dim) ((i)==(dim))
+#define SGLIB_HEAP_FIRST_ELEMENT(type, a, i) (a[0])
+#define SGLIB_HEAP_ADD_NEXT(type, a, i, dim, comparator, elem_exchanger) {\
+ int _i_;\
+ if (SGLIB_HEAP_IS_FULL(type, a, i, dim)) assert(0 && "the heap is full");\
+ _i_ = (i)++;\
+ while (_i_ > 0 && comparator(a[_i_/2], a[_i_]) < 0) {\
+ elem_exchanger(type, a, (_i_/2), _i_);\
+ _i_ = _i_/2;\
+ }\
+}
+#define SGLIB_HEAP_ADD(type, a, elem, i, dim, comparator) {\
+ if (SGLIB_HEAP_IS_FULL(type, a, i, dim)) assert(0 && "the heap is full");\
+ a[i] = (elem);\
+ SGLIB_HEAP_ADD_NEXT(type, a, i, dim, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\
+}
+#define SGLIB_HEAP_DELETE_FIRST(type, a, i, dim, comparator, elem_exchanger) {\
+ if (SGLIB_HEAP_IS_EMPTY(type, a, i)) assert(0 && "the heap is empty");\
+ (i)--;\
+ a[0] = a[i];\
+ SGLIB___ARRAY_HEAP_DOWN(type, a, 0, i, comparator, elem_exchanger);\
+}
+#define SGLIB_HEAP_DELETE(type, a, i, dim, comparator) {\
+ SGLIB_HEAP_DELETE_FIRST(type, a, i, dim, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\
+}
+
+
+/* ----------------- hashed table of pointers (in an array) -------------------- */
+
+/*
+
+ This hashed table is storing pointers to objects (not containers).
+ In this table there is a one-to-one mapping between 'objects' stored
+ in the table and indexes where they are placed. Each index is
+ pointing to exactly one 'object' and each 'object' stored in the
+ table occurs on exactly one index. Once an object is stored in the
+ table, it can be represented via its index.
+
+ In case of collision while adding an object the index shifted
+ by SGLIB_HASH_TAB_SHIFT_CONSTANT (constant can be redefined)
+
+ You can NOT delete an element from such hash table. The only
+ justification (I can see) for this data structure is an exchange
+ file format, having an index table at the beginning and then
+ refering objects via indexes.
+
+ !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!!
+
+*/
+
+#define SGLIB_HASH_TAB_INIT(type, table, dim) {\
+ int _i_;\
+ for(_i_ = 0; _i_ < (dim); _i_++) (table)[_i_] = NULL;\
+}
+
+#define SGLIB_HASH_TAB_ADD_IF_NOT_MEMBER(type, table, dim, elem, hash_function, comparator, member){\
+ unsigned _pos_;\
+ type *_elem_;\
+ SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, _pos_, _elem_);\
+ (member) = (table)[_pos_];\
+ if (_elem_ == NULL) {\
+ if ((table)[_pos_] != NULL) assert(0 && "the hash table is full");\
+ (table)[_pos_] = (elem);\
+ }\
+}
+
+#define SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, hash_function, comparator, resultIndex, resultMember) {\
+ unsigned _i_;\
+ int _count_;\
+ type *_e_;\
+ _count = 0;\
+ _i_ = hash_function(elem);\
+ _i_ %= (dim);\
+ while ((_e_=(table)[_i_])!=NULL && comparator(_e_, (elem))!=0 && _count_<(dim)) {\
+ _count_ ++;\
+ _i_ = (_i_ + SGLIB_HASH_TAB_SHIFT_CONSTANT) % (dim);\
+ }\
+ (resultIndex) = _i_;\
+ if (_count_ < (dim)) (resultMember) = _e_;\
+ else (resultMember) = NULL;\
+}
+
+#define SGLIB_HASH_TAB_IS_MEMBER(type, table, dim, elem, hash_function, resultIndex) {\
+ unsigned _i_;\
+ int _c_;\
+ type *_e_;\
+ _count = 0;\
+ _i_ = hash_function(elem);\
+ _i_ %= (dim);\
+ while ((_e_=(table)[_i_])!=NULL && _e_!=(elem) && _c_<(dim)) {\
+ _c_ ++;\
+ _i_ = (_i_ + SGLIB_HASH_TAB_SHIFT_CONSTANT) % (dim);\
+ }\
+ if (_e_==(elem)) (resultIndex) = _i_;\
+ else (resultIndex) = -1;\
+}
+
+#define SGLIB_HASH_TAB_MAP_ON_ELEMENTS(type, table, dim, iteratedIndex, iteratedVariable, command) {\
+ unsigned iteratedIndex;\
+ type *iteratedVariable;\
+ for(iteratedIndex=0; iteratedIndex < (dim); iteratedIndex++) {\
+ iteratedVariable = (table)[iteratedIndex];\
+ if (iteratedVariable != NULL) {command;}\
+ }\
+}
+
+
+/* ---------------------------------------------------------------------------- */
+/* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */
+/* ---------------------------------------------------------------------------- */
+
+/* ------------------------------------ lists (level 0) --------------------- */
+
+#define SGLIB_LIST_ADD(type, list, elem, next) {\
+ (elem)->next = (list);\
+ (list) = (elem);\
+}
+
+#define SGLIB_LIST_CONCAT(type, first, second, next) {\
+ if ((first)==NULL) {\
+ (first) = (second);\
+ } else {\
+ type *_p_;\
+ for(_p_ = (first); _p_->next!=NULL; _p_=_p_->next) ;\
+ _p_->next = (second);\
+ }\
+}
+
+#define SGLIB_LIST_DELETE(type, list, elem, next) {\
+ type **_p_;\
+ for(_p_ = &(list); *_p_!=NULL && *_p_!=(elem); _p_= &(*_p_)->next) ;\
+ assert(*_p_!=NULL && "element is not member of the container, use DELETE_IF_MEMBER instead"!=NULL);\
+ *_p_ = (*_p_)->next;\
+}
+
+#define SGLIB_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, next, member) {\
+ type *_p_;\
+ for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) != 0; _p_= _p_->next) ;\
+ (member) = _p_;\
+ if (_p_ == NULL) {\
+ SGLIB_LIST_ADD(type, list, elem, next);\
+ }\
+}
+
+#define SGLIB_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, next, member) {\
+ type **_p_;\
+ for(_p_ = &(list); *_p_!=NULL && comparator((*_p_), (elem)) != 0; _p_= &(*_p_)->next) ;\
+ (member) = *_p_;\
+ if (*_p_ != NULL) {\
+ *_p_ = (*_p_)->next;\
+ }\
+}
+
+#define SGLIB_LIST_IS_MEMBER(type, list, elem, next, result) {\
+ type *_p_;\
+ for(_p_ = (list); _p_!=NULL && _p_ != (elem); _p_= _p_->next) ;\
+ (result) = (_p_!=NULL);\
+}
+
+#define SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, next, member) {\
+ type *_p_;\
+ for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) != 0; _p_= _p_->next) ;\
+ (member) = _p_;\
+}
+
+#define SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command) {\
+ type *_ne_;\
+ type *iteratedVariable;\
+ (iteratedVariable) = (list); \
+ while ((iteratedVariable)!=NULL) {\
+ _ne_ = (iteratedVariable)->next;\
+ {command;};\
+ (iteratedVariable) = _ne_;\
+ }\
+}
+
+#define SGLIB_LIST_LEN(type, list, next, result) {\
+ type *_ce_;\
+ (result) = 0;\
+ SGLIB_LIST_MAP_ON_ELEMENTS(type, list, _ce_, next, (result)++);\
+}
+
+#define SGLIB_LIST_REVERSE(type, list, next) {\
+ type *_list_,*_tmp_,*_res_;\
+ _list_ = (list);\
+ _res_ = NULL;\
+ while (_list_!=NULL) {\
+ _tmp_ = _list_->next; _list_->next = _res_;\
+ _res_ = _list_; _list_ = _tmp_;\
+ }\
+ (list) = _res_;\
+}
+
+#define SGLIB_LIST_SORT(type, list, comparator, next) {\
+ /* a non-recursive merge sort on lists */\
+ type *_r_;\
+ type *_a_, *_b_, *_todo_, *_t_, **_restail_;\
+ int _i_, _n_, _contFlag_;\
+ _r_ = (list);\
+ _contFlag_ = 1;\
+ for(_n_ = 1; _contFlag_; _n_ = _n_+_n_) {\
+ _todo_ = _r_; _r_ = NULL; _restail_ = &_r_; _contFlag_ =0;\
+ while (_todo_!=NULL) {\
+ _a_ = _todo_;\
+ for(_i_ = 1, _t_ = _a_; _i_ < _n_ && _t_!=NULL; _i_++, _t_ = _t_->next) ;\
+ if (_t_ ==NULL) {\
+ *_restail_ = _a_;\
+ break;\
+ }\
+ _b_ = _t_->next; _t_->next=NULL;\
+ for(_i_ =1, _t_ = _b_; _i_<_n_ && _t_!=NULL; _i_++, _t_ = _t_->next) ;\
+ if (_t_ ==NULL) {\
+ _todo_ =NULL;\
+ } else {\
+ _todo_ = _t_->next; _t_->next=NULL;\
+ }\
+ /* merge */\
+ while (_a_!=NULL && _b_!=NULL) {\
+ if (comparator(_a_, _b_) < 0) {\
+ *_restail_ = _a_; _restail_ = &(_a_->next); _a_ = _a_->next;\
+ } else {\
+ *_restail_ = _b_; _restail_ = &(_b_->next); _b_ = _b_->next;\
+ }\
+ }\
+ if (_a_!=NULL) *_restail_ = _a_;\
+ else *_restail_ = _b_;\
+ while (*_restail_!=NULL) _restail_ = &((*_restail_)->next);\
+ _contFlag_ =1;\
+ }\
+ }\
+ (list) = _r_;\
+}
+
+/* --------------------------------- sorted list (level 0) --------------------- */
+/*
+ All operations suppose that the list is sorted and they preserve
+ this property.
+*/
+
+
+#define SGLIB_SORTED_LIST_ADD(type, list, elem, comparator, next) {\
+ type **_e_;\
+ int _cmpres_;\
+ SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmpres_, _e_);\
+ (elem)->next = *_e_;\
+ *_e_ = (elem);\
+}
+
+#define SGLIB_SORTED_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, next, member) {\
+ type **_e_;\
+ int _cmp_res_;\
+ SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmp_res_, _e_);\
+ if (_cmp_res_ != 0) {\
+ (elem)->next = *_e_;\
+ *_e_ = (elem);\
+ (member) = NULL;\
+ } else {\
+ (member) = *_e_;\
+ }\
+}
+
+#define SGLIB_SORTED_LIST_DELETE(type, list, elem, next) {\
+ SGLIB_LIST_DELETE(type, list, elem, next);\
+}
+
+#define SGLIB_SORTED_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, next, member) {\
+ type **_e_;\
+ int _cmp_res_;\
+ SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmp_res_, _e_);\
+ if (_cmp_res_ == 0) {\
+ (member) = *_e_;\
+ *_e_ = (*_e_)->next;\
+ } else {\
+ (member) = NULL;\
+ }\
+}
+
+#define SGLIB_SORTED_LIST_FIND_MEMBER(type, list, elem, comparator, next, member) {\
+ type *_p_;\
+ int _cmpres_;\
+ for(_p_ = (list); _p_!=NULL && (_cmpres_=comparator(_p_, (elem))) < 0; _p_=_p_->next) ;\
+ if (_cmpres_ != 0) (member) = NULL;\
+ else (member) = _p_;\
+}
+
+#define SGLIB_SORTED_LIST_IS_MEMBER(type, list, elem, comparator, next, result) {\
+ type *_p_;\
+ int _cmpres_;\
+ for(_p_ = (list); _p_!=NULL && (_cmpres_=comparator(_p_, (elem))) < 0; _p_=_p_->next) ;\
+ while (_p_ != NULL && _p_ != (elem) && (_cmpres_ = comparator(_p_, (elem))) == 0) _p_=_p_->next;\
+ (result) = (_p_ == (elem));\
+}
+
+#define SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, comparator_result, member_ptr) {\
+ for((member_ptr) = &(list); \
+ *(member_ptr)!=NULL && ((comparator_result)=comparator((*member_ptr), (elem))) < 0; \
+ (member_ptr) = &(*(member_ptr))->next) ;\
+ if (*(member_ptr) == NULL) (comparator_result) = -1;\
+}
+
+#define SGLIB_SORTED_LIST_LEN(type, list, next, result) {\
+ SGLIB_LIST_LEN(type, list, next, result);\
+}
+
+#define SGLIB_SORTED_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command) {\
+ SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command);\
+}
+
+
+/* ------------------------------- double linked list (level 0) ------------------------- */
+/*
+ Lists with back pointer to previous element. Those lists implements deletion
+ of an element in a constant time.
+*/
+
+#define SGLIB___DL_LIST_CREATE_SINGLETON(type, list, elem, previous, next) {\
+ (list) = (elem);\
+ (list)->next = (list)->previous = NULL;\
+}
+
+#define SGLIB_DL_LIST_ADD_AFTER(type, place, elem, previous, next) {\
+ if ((place) == NULL) {\
+ SGLIB___DL_LIST_CREATE_SINGLETON(type, place, elem, previous, next);\
+ } else {\
+ (elem)->next = (place)->next;\
+ (elem)->previous = (place);\
+ (place)->next = (elem);\
+ if ((elem)->next != NULL) (elem)->next->previous = (elem);\
+ }\
+}
+
+#define SGLIB_DL_LIST_ADD_BEFORE(type, place, elem, previous, next) {\
+ if ((place) == NULL) {\
+ SGLIB___DL_LIST_CREATE_SINGLETON(type, place, elem, previous, next);\
+ } else {\
+ (elem)->next = (place);\
+ (elem)->previous = (place)->previous;\
+ (place)->previous = (elem);\
+ if ((elem)->previous != NULL) (elem)->previous->next = (elem);\
+ }\
+}
+
+#define SGLIB_DL_LIST_ADD(type, list, elem, previous, next) {\
+ SGLIB_DL_LIST_ADD_BEFORE(type, list, elem, previous, next)\
+}
+
+#define SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, the_add_operation) {\
+ type *_dlp_;\
+ for(_dlp_ = (list); _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->previous) ;\
+ if (_dlp_ == NULL && (list) != NULL) {\
+ for(_dlp_ = (list)->next; _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->next) ;\
+ }\
+ (member) = _dlp_;\
+ if (_dlp_ == NULL) {\
+ the_add_operation(type, list, elem, previous, next);\
+ }\
+}
+
+#define SGLIB_DL_LIST_ADD_BEFORE_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\
+ SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD_BEFORE);\
+}
+
+#define SGLIB_DL_LIST_ADD_AFTER_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\
+ SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD_AFTER);\
+}
+
+#define SGLIB_DL_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\
+ SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD);\
+}
+
+#define SGLIB_DL_LIST_CONCAT(type, first, second, previous, next) {\
+ if ((first)==NULL) {\
+ (first) = (second);\
+ } else if ((second)!=NULL) {\
+ type *_dlp_;\
+ for(_dlp_ = (first); _dlp_->next!=NULL; _dlp_=_dlp_->next) ;\
+ SGLIB_DL_LIST_ADD_AFTER(type, _dlp_, second, previous, next);\
+ }\
+}
+
+#define SGLIB_DL_LIST_DELETE(type, list, elem, previous, next) {\
+ type *_l_;\
+ _l_ = (list);\
+ if (_l_ == (elem)) {\
+ if ((elem)->previous != NULL) _l_ = (elem)->previous;\
+ else _l_ = (elem)->next;\
+ }\
+ if ((elem)->next != NULL) (elem)->next->previous = (elem)->previous;\
+ if ((elem)->previous != NULL) (elem)->previous->next = (elem)->next;\
+ (list) = _l_;\
+}
+
+#define SGLIB_DL_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, previous, next, member) {\
+ type *_dlp_;\
+ for(_dlp_ = (list); _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->previous) ;\
+ if (_dlp_ == NULL && (list) != NULL) {\
+ for(_dlp_ = (list)->next; _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->next) ;\
+ }\
+ (member) = _dlp_;\
+ if (_dlp_ != NULL) {\
+ SGLIB_DL_LIST_DELETE(type, list, _dlp_, previous, next);\
+ }\
+}
+
+#define SGLIB_DL_LIST_IS_MEMBER(type, list, elem, previous, next, result) {\
+ type *_dlp_;\
+ SGLIB_LIST_IS_MEMBER(type, list, elem, previous, result);\
+ if (result == 0 && (list) != NULL) {\
+ _dlp_ = (list)->next;\
+ SGLIB_LIST_IS_MEMBER(type, _dlp_, elem, next, result);\
+ }\
+}
+
+#define SGLIB_DL_LIST_FIND_MEMBER(type, list, elem, comparator, previous, next, member) {\
+ type *_dlp_;\
+ SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, previous, member);\
+ if ((member) == NULL && (list) != NULL) {\
+ _dlp_ = (list)->next;\
+ SGLIB_LIST_FIND_MEMBER(type, _dlp_, elem, comparator, next, member);\
+ }\
+}
+
+#define SGLIB_DL_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, previous, next, command) {\
+ type *_dl_;\
+ type *iteratedVariable;\
+ if ((list)!=NULL) {\
+ _dl_ = (list)->next;\
+ SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, previous, command);\
+ SGLIB_LIST_MAP_ON_ELEMENTS(type, _dl_, iteratedVariable, next, command);\
+ }\
+}
+
+#define SGLIB_DL_LIST_SORT(type, list, comparator, previous, next) {\
+ type *_dll_, *_dlp_, *_dlt_;\
+ _dll_ = (list);\
+ if (_dll_ != NULL) {\
+ for(; _dll_->previous!=NULL; _dll_=_dll_->previous) ;\
+ SGLIB_LIST_SORT(type, _dll_, comparator, next);\
+ SGLIB___DL_LIST_CREATE_FROM_LIST(type, _dll_, previous, next);\
+ (list) = _dll_;\
+ }\
+}
+
+#define SGLIB_DL_LIST_GET_FIRST(type, list, previous, next, result) {\
+ type *_dll_;\
+ _dll_ = (list);\
+ if (_dll_ != NULL) {\
+ for(; _dll_->previous!=NULL; _dll_=_dll_->previous) ;\
+ }\
+ (result) = _dll_;\
+}
+
+#define SGLIB_DL_LIST_GET_LAST(type, list, previous, next, result) {\
+ type *_dll_;\
+ _dll_ = (list);\
+ if (_dll_ != NULL) {\
+ for(; _dll_->next!=NULL; _dll_=_dll_->next) ;\
+ }\
+ (result) = _dll_;\
+}
+
+#define SGLIB_DL_LIST_LEN(type, list, previous, next, result) {\
+ type *_dl_;\
+ int _r1_, _r2_;\
+ if ((list)==NULL) {\
+ (result) = 0;\
+ } else {\
+ SGLIB_LIST_LEN(type, list, previous, _r1_);\
+ _dl_ = (list)->next;\
+ SGLIB_LIST_LEN(type, _dl_, next, _r2_);\
+ (result) = _r1_ + _r2_;\
+ }\
+}
+
+#define SGLIB_DL_LIST_REVERSE(type, list, previous, next) {\
+ type *_list_,*_nlist_,*_dlp_,*_dln_;\
+ _list_ = (list);\
+ if (_list_!=NULL) {\
+ _nlist_ = _list_->next;\
+ while (_list_!=NULL) {\
+ _dln_ = _list_->next; \
+ _dlp_ = _list_->previous; \
+ _list_->next = _dlp_;\
+ _list_->previous = _dln_;\
+ _list_ = _dlp_;\
+ }\
+ while (_nlist_!=NULL) {\
+ _dln_ = _nlist_->next; \
+ _dlp_ = _nlist_->previous; \
+ _nlist_->next = _dlp_;\
+ _nlist_->previous = _dln_;\
+ _nlist_ = _dln_;\
+ }\
+ }\
+}
+
+#define SGLIB___DL_LIST_CREATE_FROM_LIST(type, list, previous, next) {\
+ type *_dlp_, *_dlt_;\
+ _dlp_ = NULL;\
+ for(_dlt_ = (list); _dlt_!=NULL; _dlt_ = _dlt_->next) {\
+ _dlt_->previous = _dlp_;\
+ _dlp_ = _dlt_;\
+ }\
+}
+
+
+/* ------------------------------- binary tree traversal (level 0) -------------------- */
+
+
+#define SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, iteratedVariable, order, left, right, command) {\
+ /* this is non-recursive implementation of tree traversal */\
+ /* it maintains the path to the current node in the array '_path_' */\
+ /* the _path_[0] contains the root of the tree; */\
+ /* the _path_[_pathi_] contains the _current_element_ */\
+ /* the macro does not use the _current_element_ after execution of command */\
+ /* command can destroy it, it can free the element for example */\
+ type *_path_[SGLIB_MAX_TREE_DEEP];\
+ type *_right_[SGLIB_MAX_TREE_DEEP];\
+ char _pass_[SGLIB_MAX_TREE_DEEP];\
+ type *_cn_;\
+ int _pathi_;\
+ type *iteratedVariable;\
+ _cn_ = (tree);\
+ _pathi_ = 0;\
+ while (_cn_!=NULL) {\
+ /* push down to leftmost innermost element */\
+ while(_cn_!=NULL) {\
+ _path_[_pathi_] = _cn_;\
+ _right_[_pathi_] = _cn_->right;\
+ _pass_[_pathi_] = 0;\
+ _cn_ = _cn_->left;\
+ if (order == 0) {\
+ iteratedVariable = _path_[_pathi_];\
+ {command;}\
+ }\
+ _pathi_ ++;\
+ if (_pathi_ >= SGLIB_MAX_TREE_DEEP) assert(0 && "the binary_tree is too deep");\
+ }\
+ do {\
+ _pathi_ --;\
+ if ((order==1 && _pass_[_pathi_] == 0)\
+ || (order == 2 && (_pass_[_pathi_] == 1 || _right_[_pathi_]==NULL))) {\
+ iteratedVariable = _path_[_pathi_];\
+ {command;}\
+ }\
+ _pass_[_pathi_] ++;\
+ } while (_pathi_>0 && _right_[_pathi_]==NULL) ;\
+ _cn_ = _right_[_pathi_];\
+ _right_[_pathi_] = NULL;\
+ _pathi_ ++;\
+ }\
+}
+
+#define SGLIB_BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, left, right, command) {\
+ SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 1, left, right, command);\
+}
+
+#define SGLIB_BIN_TREE_MAP_ON_ELEMENTS_PREORDER(type, tree, _current_element_, left, right, command) {\
+ SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 0, left, right, command);\
+}
+
+#define SGLIB_BIN_TREE_MAP_ON_ELEMENTS_POSTORDER(type, tree, _current_element_, left, right, command) {\
+ SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 2, left, right, command);\
+}
+
+#define SGLIB___BIN_TREE_FIND_MEMBER(type, tree, elem, left, right, comparator, res) {\
+ type *_s_;\
+ int _c_;\
+ _s_ = (tree);\
+ while (_s_!=NULL) {\
+ _c_ = comparator((elem), _s_);\
+ if (_c_ < 0) _s_ = _s_->left;\
+ else if (_c_ > 0) _s_ = _s_->right;\
+ else break;\
+ }\
+ (res) = _s_;\
+}
+
+/* ---------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------- */
+/* - LEVEL - 1 INTERFACE - */
+/* ---------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------- */
+
+
+
+/* ---------------------------------------------------------------------------- */
+/* ------------------------------ STATIC ARRAYS ------------------------------- */
+/* ---------------------------------------------------------------------------- */
+
+/* ----------------------------- array sorting (level 1) ---------------------- */
+
+#define SGLIB_DEFINE_ARRAY_SORTING_PROTOTYPES(type, comparator) \
+ extern void sglib_##type##_array_quick_sort(type *a, int max);\
+ extern void sglib_##type##_array_heap_sort(type *a, int max);\
+
+
+#define SGLIB_DEFINE_ARRAY_SORTING_FUNCTIONS(type, comparator) \
+ void sglib_##type##_array_quick_sort(type *a, int max) {\
+ SGLIB_ARRAY_SINGLE_QUICK_SORT(type, a, max, comparator);\
+ }\
+ void sglib_##type##_array_heap_sort(type *a, int max) {\
+ SGLIB_ARRAY_SINGLE_HEAP_SORT(type, a, max, comparator);\
+ }\
+
+
+/* ----------------------------- array queue (level 1) ------------------- */
+/* sglib's queue is stored in a fixed sized array */
+/* queue_type MUST be a structure containing fields: */
+/* afield is the array storing elem_type */
+/* ifield is the index of the first element in the queue */
+/* jfield is the index of the first free element after the queue */
+/* dim is the size of the array afield */
+/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */
+
+
+#define SGLIB_DEFINE_QUEUE_PROTOTYPES(queue_type, elem_type, afield, ifield, jfield, dim) \
+ extern void sglib_##queue_type##_init(queue_type *q); \
+ extern int sglib_##queue_type##_is_empty(queue_type *q); \
+ extern int sglib_##queue_type##_is_full(queue_type *q); \
+ extern elem_type sglib_##queue_type##_first_element(queue_type *q); \
+ extern elem_type *sglib_##queue_type##_first_element_ptr(queue_type *q); \
+ extern void sglib_##queue_type##_add_next(queue_type *q); \
+ extern void sglib_##queue_type##_add(queue_type *q, elem_type elem); \
+ extern void sglib_##queue_type##_delete_first(queue_type *q); \
+ extern void sglib_##queue_type##_delete(queue_type *q);
+
+
+#define SGLIB_DEFINE_QUEUE_FUNCTIONS(queue_type, elem_type, afield, ifield, jfield, dim) \
+ void sglib_##queue_type##_init(queue_type *q) {\
+ SGLIB_QUEUE_INIT(elem_type, q->afield, q->ifield, q->jfield);\
+ }\
+ int sglib_##queue_type##_is_empty(queue_type *q) {\
+ return(SGLIB_QUEUE_IS_EMPTY(elem_type, q->afield, q->ifield, q->jfield));\
+ }\
+ int sglib_##queue_type##_is_full(queue_type *q) {\
+ return(SGLIB_QUEUE_IS_FULL(elem_type, q->afield, q->ifield, q->jfield));\
+ }\
+ elem_type sglib_##queue_type##_first_element(queue_type *q) {\
+ return(SGLIB_QUEUE_FIRST_ELEMENT(elem_type, q->afield, q->ifield, q->jfield));\
+ }\
+ elem_type *sglib_##queue_type##_first_element_ptr(queue_type *q) {\
+ return(& SGLIB_QUEUE_FIRST_ELEMENT(elem_type, q->afield, q->ifield, q->jfield));\
+ }\
+ void sglib_##queue_type##_add_next(queue_type *q) {\
+ SGLIB_QUEUE_ADD_NEXT(elem_type, q->afield, q->ifield, q->jfield, dim);\
+ }\
+ void sglib_##queue_type##_add(queue_type *q, elem_type elem) {\
+ SGLIB_QUEUE_ADD(elem_type, q->afield, elem, q->ifield, q->jfield, dim);\
+ }\
+ void sglib_##queue_type##_delete_first(queue_type *q) {\
+ SGLIB_QUEUE_DELETE_FIRST(elem_type, q->afield, q->ifield, q->jfield, dim);\
+ }\
+ void sglib_##queue_type##_delete(queue_type *q) {\
+ SGLIB_QUEUE_DELETE_FIRST(elem_type, q->afield, q->ifield, q->jfield, dim);\
+ }
+
+
+/* ------------------------ array heap (level 1) ------------------------- */
+/* sglib's heap is a priority queue implemented in a fixed sized array */
+/* heap_type MUST be a structure containing fields: */
+/* afield is the array of size dim storing elem_type */
+/* ifield is the index of the first free element after the queue */
+/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */
+
+
+#define SGLIB_DEFINE_HEAP_PROTOTYPES(heap_type, elem_type, afield, ifield, dim, comparator, elem_exchanger) \
+ extern void sglib_##heap_type##_init(heap_type *q); \
+ extern int sglib_##heap_type##_is_empty(heap_type *q); \
+ extern int sglib_##heap_type##_is_full(heap_type *q); \
+ extern elem_type sglib_##heap_type##_first_element(heap_type *q); \
+ extern elem_type *sglib_##heap_type##_first_element_ptr(heap_type *q); \
+ extern void sglib_##heap_type##_add_next(heap_type *q); \
+ extern void sglib_##heap_type##_add(heap_type *q, elem_type elem); \
+ extern void sglib_##heap_type##_delete_first(heap_type *q); \
+ extern void sglib_##heap_type##_delete(heap_type *q)
+
+#define SGLIB_DEFINE_HEAP_FUNCTIONS(heap_type, elem_type, afield, ifield, dim, comparator, elem_exchanger) \
+ void sglib_##heap_type##_init(heap_type *q) {\
+ SGLIB_HEAP_INIT(elem_type, q->afield, q->ifield);\
+ }\
+ int sglib_##heap_type##_is_empty(heap_type *q) {\
+ return(SGLIB_HEAP_IS_EMPTY(elem_type, q->afield, q->ifield));\
+ }\
+ int sglib_##heap_type##_is_full(heap_type *q) {\
+ return(SGLIB_HEAP_IS_FULL(elem_type, q->afield, q->ifield));\
+ }\
+ elem_type sglib_##heap_type##_first_element(heap_type *q) {\
+ return(SGLIB_HEAP_FIRST_ELEMENT(elem_type, q->afield, q->ifield));\
+ }\
+ elem_type *sglib_##heap_type##_first_element_ptr(heap_type *q) {\
+ return(& SGLIB_HEAP_FIRST_ELEMENT(elem_type, q->afield, q->ifield));\
+ }\
+ void sglib_##heap_type##_add_next(heap_type *q) {\
+ SGLIB_HEAP_ADD_NEXT(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\
+ }\
+ void sglib_##heap_type##_add(heap_type *q, elem_type elem) {\
+ SGLIB_HEAP_ADD(elem_type, q->afield, elem, q->ifield, dim, comparator, elem_exchanger);\
+ }\
+ void sglib_##heap_type##_delete_first(heap_type *q) {\
+ SGLIB_HEAP_DELETE_FIRST(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\
+ }\
+ void sglib_##heap_type##_delete(heap_type *q) {\
+ SGLIB_HEAP_DELETE_FIRST(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\
+ }
+
+
+/* ------------------------ hashed table (level 1) ------------------------- */
+/*
+
+ sglib's hash table is an array storing directly pointers to objects (not containers).
+ In this table there is a one-to-one mapping between 'objects' stored
+ in the table and indexes where they are placed. Each index is
+ pointing to exactly one 'object' and each 'object' stored in the
+ table occurs on exactly one index. Once an object is stored in the
+ table, it can be represented via its index.
+
+ type - is the type of elements
+ dim - is the size of the hash array
+ hash_function - is a hashing function mapping type* to unsigned
+ comparator - is a comparator on elements
+
+ !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!!
+*/
+
+#define SGLIB_DEFINE_HASHED_TABLE_PROTOTYPES(type, dim, hash_function, comparator) \
+ struct sglib_hashed_##type##_iterator {\
+ int currentIndex;\
+ int (*subcomparator)(type *, type *);\
+ type *equalto;\
+ };\
+ extern void sglib_hashed_##type##_init(type *table[dim]);\
+ extern int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member);\
+ extern int sglib_hashed_##type##_is_member(type *table[dim], type *elem);\
+ extern type * sglib_hashed_##type##_find_member(type *table[dim], type *elem);\
+ extern type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]); \
+ extern type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto); \
+ extern type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it); \
+ extern type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it);
+
+#define SGLIB_DEFINE_HASHED_TABLE_FUNCTIONS(type, dim, hash_function, comparator) \
+ struct sglib_hashed_##type##_iterator {\
+ int currentIndex;\
+ type **table;\
+ int (*subcomparator)(type *, type *);\
+ type *equalto;\
+ };\
+ void sglib_hashed_##type##_init(type *table[dim]) {\
+ SGLIB_HASH_TAB_INIT(type, table, dim);\
+ }\
+ int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member) {\
+ SGLIB_HASH_TAB_ADD_IF_NOT_MEMBER(type, table, dim, elem, hash_function, comparator, *member);\
+ }\
+ int sglib_hashed_##type##_is_member(type *table[dim], type *elem) {\
+ int ind;\
+ SGLIB_HASH_TAB_IS_MEMBER(type, table, dim, elem, hash_function, ind);\
+ return(ind != -1);\
+ }\
+ type * sglib_hashed_##type##_find_member(type *table[dim], type *elem) {\
+ type *mmb;\
+ int ind;\
+ SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, hash_function, comparator, ind, mmb);\
+ return(mmb);\
+ }\
+ type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto) {\
+ int i;\
+ it->table = table;\
+ it->subcomparator = subcomparator;\
+ it->equalto = equalto;\
+ for(i=0; i<(dim) && table[i]==NULL; i++) ;\
+ it->currentIndex = i;\
+ if (i<(dim)) return(table[i]);\
+ return(NULL);\
+ }\
+ type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]) {\
+ sglib_hashed_##type##_it_init_on_equal(it, table, NULL, NULL);\
+ }\
+ type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it) {\
+ return(table[it->currentIndex]);\
+ }\
+ type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it) {\
+ i=it->currentIndex;\
+ if (i<(dim)) {\
+ for(i++; i<(dim) && table[i]==NULL; i++) ;\
+ }\
+ it->currentIndex = i;\
+ if (i<(dim)) return(table[i]);\
+ return(NULL);\
+ }
+
+
+/* ------------------- hashed container (only for level 1) -------------------- */
+/*
+ hashed container is a table of given fixed size containing another
+ (dynamic) base container in each cell. Once an object should be
+ inserted into the hashed container, a hash function is used to
+ determine the cell where the object belongs and the object is
+ inserted into the base container stored in this cell. Usually the
+ base container is simply a list or a sorted list, but it can be a
+ red-black tree as well.
+
+ parameters:
+ type - the type of the container stored in each cell.
+ dim - the size of the hashed array
+ hash_function - the hashing function hashing 'type *' to unsigned.
+
+*/
+
+#define SGLIB_DEFINE_HASHED_CONTAINER_PROTOTYPES(type, dim, hash_function) \
+ struct sglib_hashed_##type##_iterator {\
+ struct sglib_##type##_iterator containerIt;\
+ type **table;\
+ int currentIndex;\
+ int (*subcomparator)(type *, type *);\
+ type *equalto;\
+ };\
+ extern void sglib_hashed_##type##_init(type *table[dim]);\
+ extern void sglib_hashed_##type##_add(type *table[dim], type *elem);\
+ extern int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member);\
+ extern void sglib_hashed_##type##_delete(type *table[dim], type *elem);\
+ extern int sglib_hashed_##type##_delete_if_member(type *table[dim], type *elem, type **memb);\
+ extern int sglib_hashed_##type##_is_member(type *table[dim], type *elem);\
+ extern type * sglib_hashed_##type##_find_member(type *table[dim], type *elem);\
+ extern type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]); \
+ extern type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto); \
+ extern type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it); \
+ extern type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it);
+
+#define SGLIB_DEFINE_HASHED_CONTAINER_FUNCTIONS(type, dim, hash_function) \
+ /*extern unsigned hash_function(type *elem);*/\
+ void sglib_hashed_##type##_init(type *table[dim]) {\
+ unsigned i;\
+ for(i=0; i<(dim); i++) table[i] = NULL;\
+ }\
+ void sglib_hashed_##type##_add(type *table[dim], type *elem) {\
+ unsigned i;\
+ i = ((unsigned)hash_function(elem)) % (dim);\
+ sglib_##type##_add(&(table)[i], elem);\
+ }\
+ int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member) {\
+ unsigned i;\
+ i = ((unsigned)hash_function(elem)) % (dim);\
+ return(sglib_##type##_add_if_not_member(&(table)[i], elem, member));\
+ }\
+ void sglib_hashed_##type##_delete(type *table[dim], type *elem) {\
+ unsigned i;\
+ i = ((unsigned)hash_function(elem)) % (dim);\
+ sglib_##type##_delete(&(table)[i], elem);\
+ }\
+ int sglib_hashed_##type##_delete_if_member(type *table[dim], type *elem, type **memb) {\
+ unsigned i;\
+ i = ((unsigned)hash_function(elem)) % (dim);\
+ return(sglib_##type##_delete_if_member(&(table)[i], elem, memb));\
+ }\
+ int sglib_hashed_##type##_is_member(type *table[dim], type *elem) {\
+ unsigned i;\
+ i = ((unsigned)hash_function(elem)) % (dim);\
+ return(sglib_##type##_is_member((table)[i], elem));\
+ }\
+ type * sglib_hashed_##type##_find_member(type *table[dim], type *elem) {\
+ unsigned i;\
+ i = ((unsigned)hash_function(elem)) % (dim);\
+ return(sglib_##type##_find_member((table)[i], elem));\
+ }\
+ type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto) {\
+ type *e;\
+ it->table = table;\
+ it->currentIndex = 0;\
+ it->subcomparator = subcomparator;\
+ it->equalto = equalto;\
+ e = sglib_##type##_it_init_on_equal(&it->containerIt, table[it->currentIndex], it->subcomparator, it->equalto);\
+ if (e==NULL) e = sglib_hashed_##type##_it_next(it);\
+ return(e);\
+ }\
+ type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]) {\
+ return(sglib_hashed_##type##_it_init_on_equal(it, table, NULL, NULL));\
+ }\
+ type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it) {\
+ return(sglib_##type##_it_current(&it->containerIt));\
+ }\
+ type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it) {\
+ type *e;\
+ e = sglib_##type##_it_next(&it->containerIt);\
+ while (e==NULL && (++(it->currentIndex))<(dim)) {\
+ e = sglib_##type##_it_init_on_equal(&it->containerIt, it->table[it->currentIndex], it->subcomparator, it->equalto);\
+ }\
+ return(e);\
+ }
+
+
+
+/* ---------------------------------------------------------------------------- */
+/* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */
+/* ---------------------------------------------------------------------------- */
+
+
+
+/* ------------------------------------ list (level 1) -------------------------------- */
+
+#define SGLIB_DEFINE_LIST_PROTOTYPES(type, comparator, next) \
+ struct sglib_##type##_iterator {\
+ type *currentelem;\
+ type *nextelem;\
+ int (*subcomparator)(type *, type *);\
+ type *equalto;\
+ };\
+ extern void sglib_##type##_add(type **list, type *elem);\
+ extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\
+ extern void sglib_##type##_concat(type **first, type *second);\
+ extern void sglib_##type##_delete(type **list, type *elem);\
+ extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\
+ extern int sglib_##type##_is_member(type *list, type *elem);\
+ extern type *sglib_##type##_find_member(type *list, type *elem);\
+ extern void sglib_##type##_sort(type **list);\
+ extern int sglib_##type##_len(type *list);\
+ extern void sglib_##type##_reverse(type **list);\
+ extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list); \
+ extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto); \
+ extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \
+ extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it);
+
+
+#define SGLIB_DEFINE_LIST_FUNCTIONS(type, comparator, next) \
+ int sglib_##type##_is_member(type *list, type *elem) {\
+ int result;\
+ SGLIB_LIST_IS_MEMBER(type, list, elem, next, result);\
+ return(result);\
+ }\
+ type *sglib_##type##_find_member(type *list, type *elem) {\
+ type *result;\
+ SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, next, result);\
+ return(result);\
+ }\
+ int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\
+ SGLIB_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, next, *member);\
+ return(*member==NULL);\
+ }\
+ void sglib_##type##_add(type **list, type *elem) {\
+ SGLIB_LIST_ADD(type, *list, elem, next);\
+ }\
+ void sglib_##type##_concat(type **first, type *second) {\
+ SGLIB_LIST_CONCAT(type, *first, second, next);\
+ }\
+ void sglib_##type##_delete(type **list, type *elem) {\
+ SGLIB_LIST_DELETE(type, *list, elem, next);\
+ }\
+ int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\
+ SGLIB_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, next, *member);\
+ return(*member!=NULL);\
+ }\
+ void sglib_##type##_sort(type **list) { \
+ SGLIB_LIST_SORT(type, *list, comparator, next);\
+ }\
+ int sglib_##type##_len(type *list) {\
+ int res;\
+ SGLIB_LIST_LEN(type, list, next, res);\
+ return(res);\
+ }\
+ void sglib_##type##_reverse(type **list) {\
+ SGLIB_LIST_REVERSE(type, *list, next);\
+ }\
+ \
+ type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\
+ it->subcomparator = subcomparator;\
+ it->equalto = equalto;\
+ it->nextelem = list;\
+ return(sglib_##type##_it_next(it));\
+ }\
+ type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\
+ return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\
+ }\
+ type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\
+ return(it->currentelem);\
+ }\
+ type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\
+ type *ce, *eq;\
+ int (*scp)(type *, type *);\
+ ce = it->nextelem;\
+ it->nextelem = NULL;\
+ if (it->subcomparator != NULL) {\
+ eq = it->equalto; \
+ scp = it->subcomparator;\
+ while (ce!=NULL && scp(ce, eq)!=0) ce = ce->next;\
+ }\
+ it->currentelem = ce;\
+ if (ce != NULL) it->nextelem = ce->next;\
+ return(ce);\
+ }
+
+/* ----------------------------- sorted list (level 1) ----------------------------------- */
+
+
+#define SGLIB_DEFINE_SORTED_LIST_PROTOTYPES(type, comparator, next) \
+ struct sglib_##type##_iterator {\
+ type *currentelem;\
+ type *nextelem;\
+ int (*subcomparator)(type *, type *);\
+ type *equalto;\
+ };\
+ extern void sglib_##type##_add(type **list, type *elem);\
+ extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\
+ extern void sglib_##type##_delete(type **list, type *elem);\
+ extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\
+ extern int sglib_##type##_is_member(type *list, type *elem);\
+ extern type *sglib_##type##_find_member(type *list, type *elem);\
+ extern int sglib_##type##_len(type *list);\
+ extern void sglib_##type##_sort(type **list);\
+ extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list); \
+ extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto); \
+ extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \
+ extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it);
+
+
+#define SGLIB_DEFINE_SORTED_LIST_FUNCTIONS(type, comparator, next) \
+ int sglib_##type##_is_member(type *list, type *elem) {\
+ int result;\
+ SGLIB_SORTED_LIST_IS_MEMBER(type, list, elem, comparator, next, result);\
+ return(result);\
+ }\
+ type *sglib_##type##_find_member(type *list, type *elem) {\
+ type *result;\
+ SGLIB_SORTED_LIST_FIND_MEMBER(type, list, elem, comparator, next, result);\
+ return(result);\
+ }\
+ int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\
+ SGLIB_SORTED_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, next, *member);\
+ return(*member==NULL);\
+ }\
+ void sglib_##type##_add(type **list, type *elem) {\
+ SGLIB_SORTED_LIST_ADD(type, *list, elem, comparator, next);\
+ }\
+ void sglib_##type##_delete(type **list, type *elem) {\
+ SGLIB_SORTED_LIST_DELETE(type, *list, elem, next);\
+ }\
+ int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\
+ SGLIB_SORTED_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, next, *member);\
+ return(*member!=NULL);\
+ }\
+ int sglib_##type##_len(type *list) {\
+ int res;\
+ SGLIB_SORTED_LIST_LEN(type, list, next, res);\
+ return(res);\
+ }\
+ void sglib_##type##_sort(type **list) { \
+ SGLIB_LIST_SORT(type, *list, comparator, next);\
+ }\
+ \
+ type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\
+ it->subcomparator = subcomparator;\
+ it->equalto = equalto;\
+ it->nextelem = list;\
+ return(sglib_##type##_it_next(it));\
+ }\
+ type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\
+ return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\
+ }\
+ type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\
+ return(it->currentelem);\
+ }\
+ type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\
+ type *ce, *eq;\
+ int (*scp)(type *, type *);\
+ int c;\
+ ce = it->nextelem;\
+ it->nextelem = NULL;\
+ if (it->subcomparator != NULL) {\
+ eq = it->equalto; \
+ scp = it->subcomparator;\
+ while (ce!=NULL && (c=scp(ce, eq)) < 0) ce = ce->next;\
+ if (ce != NULL && c > 0) ce = NULL;\
+ }\
+ it->currentelem = ce;\
+ if (ce != NULL) it->nextelem = ce->next;\
+ return(ce);\
+ }
+
+
+/* ----------------------------- double linked list (level 1) ------------------------------ */
+
+
+#define SGLIB_DEFINE_DL_LIST_PROTOTYPES(type, comparator, previous, next) \
+ struct sglib_##type##_iterator {\
+ type *currentelem;\
+ type *prevelem;\
+ type *nextelem;\
+ int (*subcomparator)(type *, type *);\
+ type *equalto;\
+ };\
+ extern void sglib_##type##_add(type **list, type *elem);\
+ extern void sglib_##type##_add_before(type **list, type *elem);\
+ extern void sglib_##type##_add_after(type **list, type *elem);\
+ extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\
+ extern int sglib_##type##_add_before_if_not_member(type **list, type *elem, type **member);\
+ extern int sglib_##type##_add_after_if_not_member(type **list, type *elem, type **member);\
+ extern void sglib_##type##_concat(type **first, type *second);\
+ extern void sglib_##type##_delete(type **list, type *elem);\
+ extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\
+ extern int sglib_##type##_is_member(type *list, type *elem);\
+ extern type *sglib_##type##_find_member(type *list, type *elem);\
+ extern type *sglib_##type##_get_first(type *list);\
+ extern type *sglib_##type##_get_last(type *list);\
+ extern void sglib_##type##_sort(type **list);\
+ extern int sglib_##type##_len(type *list);\
+ extern void sglib_##type##_reverse(type **list);\
+ extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list); \
+ extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto); \
+ extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \
+ extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it);
+
+
+#define SGLIB_DEFINE_DL_LIST_FUNCTIONS(type, comparator, previous, next) \
+ void sglib_##type##_add(type **list, type *elem) {\
+ SGLIB_DL_LIST_ADD(type, *list, elem, previous, next);\
+ }\
+ void sglib_##type##_add_after(type **list, type *elem) {\
+ SGLIB_DL_LIST_ADD_AFTER(type, *list, elem, previous, next);\
+ }\
+ void sglib_##type##_add_before(type **list, type *elem) {\
+ SGLIB_DL_LIST_ADD_BEFORE(type, *list, elem, previous, next);\
+ }\
+ int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\
+ SGLIB_DL_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\
+ return(*member==NULL);\
+ }\
+ int sglib_##type##_add_after_if_not_member(type **list, type *elem, type **member) {\
+ SGLIB_DL_LIST_ADD_AFTER_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\
+ return(*member==NULL);\
+ }\
+ int sglib_##type##_add_before_if_not_member(type **list, type *elem, type **member) {\
+ SGLIB_DL_LIST_ADD_BEFORE_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\
+ return(*member==NULL);\
+ }\
+ void sglib_##type##_concat(type **first, type *second) {\
+ SGLIB_DL_LIST_CONCAT(type, *first, second, previous, next);\
+ }\
+ void sglib_##type##_delete(type **list, type *elem) {\
+ SGLIB_DL_LIST_DELETE(type, *list, elem, previous, next);\
+ }\
+ int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\
+ SGLIB_DL_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, previous, next, *member);\
+ return(*member!=NULL);\
+ }\
+ int sglib_##type##_is_member(type *list, type *elem) {\
+ int result;\
+ SGLIB_DL_LIST_IS_MEMBER(type, list, elem, previous, next, result);\
+ return(result);\
+ }\
+ type *sglib_##type##_find_member(type *list, type *elem) {\
+ type *result;\
+ SGLIB_DL_LIST_FIND_MEMBER(type, list, elem, comparator, previous, next, result);\
+ return(result);\
+ }\
+ type *sglib_##type##_get_first(type *list) {\
+ type *result;\
+ SGLIB_DL_LIST_GET_FIRST(type, list, previous, next, result);\
+ return(result);\
+ }\
+ type *sglib_##type##_get_last(type *list) {\
+ type *result;\
+ SGLIB_DL_LIST_GET_LAST(type, list, previous, next, result);\
+ return(result);\
+ }\
+ void sglib_##type##_sort(type **list) {\
+ SGLIB_DL_LIST_SORT(type, *list, comparator, previous, next);\
+ }\
+ int sglib_##type##_len(type *list) {\
+ int res;\
+ SGLIB_DL_LIST_LEN(type, list, previous, next, res);\
+ return(res);\
+ }\
+ void sglib_##type##_reverse(type **list) {\
+ SGLIB_DL_LIST_REVERSE(type, *list, previous, next);\
+ }\
+ \
+ type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\
+ it->subcomparator = subcomparator;\
+ it->equalto = equalto;\
+ it->prevelem = list;\
+ it->nextelem = list;\
+ if (list != NULL) it->nextelem = list->next;\
+ return(sglib_##type##_it_next(it));\
+ }\
+ type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\
+ return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\
+ }\
+ type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\
+ return(it->currentelem);\
+ }\
+ type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\
+ type *ce, *eq;\
+ int (*scp)(type *, type *);\
+ ce = it->prevelem;\
+ it->prevelem = NULL;\
+ if (it->subcomparator != NULL) {\
+ eq = it->equalto; \
+ scp = it->subcomparator;\
+ while (ce!=NULL && scp(eq, ce)!=0) ce = ce->previous;\
+ }\
+ if (ce != NULL) {\
+ it->prevelem = ce->previous;\
+ } else {\
+ ce = it->nextelem;\
+ it->nextelem = NULL;\
+ if (it->subcomparator != NULL) {\
+ eq = it->equalto; \
+ scp = it->subcomparator;\
+ while (ce!=NULL && scp(ce, eq)!=0) ce = ce->next;\
+ }\
+ if (ce != NULL) it->nextelem = ce->next;\
+ }\
+ it->currentelem = ce;\
+ return(ce);\
+ }
+
+
+/* --------------------------------- red-black trees (level 1) -------------------------------- */
+
+/*
+
+This implementation requires pointers to left and right sons (no
+parent pointer is needed) and one bit of additional information
+storing the color of the node. The implementation follows discrepancy
+fixing rules from:
+http://www.cis.ohio-state.edu/~gurari/course/cis680/cis680Ch11.html
+
+*/
+
+#define SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, leftt, rightt, bits, RED, BLACK) {\
+ type *t, *tl, *a, *b, *c, *ar, *bl, *br, *cl, *cr;\
+ t = *tree;\
+ tl = t->leftt;\
+ if (t->rightt!=NULL && SGLIB___GET_VALUE(t->rightt->bits)==RED) {\
+ if (SGLIB___GET_VALUE(tl->bits)==RED) {\
+ if ((tl->leftt!=NULL && SGLIB___GET_VALUE(tl->leftt->bits)==RED) \
+ || (tl->rightt!=NULL && SGLIB___GET_VALUE(tl->rightt->bits)==RED)) {\
+ SGLIB___SET_VALUE(t->leftt->bits,BLACK);\
+ SGLIB___SET_VALUE(t->rightt->bits,BLACK);\
+ SGLIB___SET_VALUE(t->bits,RED);\
+ }\
+ }\
+ } else {\
+ if (SGLIB___GET_VALUE(tl->bits)==RED) {\
+ if (tl->leftt!=NULL && SGLIB___GET_VALUE(tl->leftt->bits)==RED) {\
+ a = t; b = tl; c = tl->leftt;\
+ br = b->rightt;\
+ a->leftt = br;\
+ b->leftt = c; b->rightt = a;\
+ SGLIB___SET_VALUE(a->bits,RED);\
+ SGLIB___SET_VALUE(b->bits,BLACK);\
+ *tree = b;\
+ } else if (tl->rightt!=NULL && SGLIB___GET_VALUE(tl->rightt->bits)==RED) {\
+ a = t; b = tl; ar=a->rightt;\
+ bl=b->leftt; c=b->rightt;\
+ cl=c->leftt; cr=c->rightt;\
+ b->rightt = cl;\
+ a->leftt = cr;\
+ c->leftt = b;\
+ c->rightt = a;\
+ SGLIB___SET_VALUE(c->bits,BLACK);\
+ SGLIB___SET_VALUE(a->bits,RED);\
+ *tree = c;\
+ }\
+ }\
+ }\
+}
+
+#define SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, leftt, rightt, bits, RED, BLACK, res) {\
+ type *t, *a, *b, *c, *d, *ar, *bl, *br, *cl, *cr, *dl, *dr;\
+ t = a = *tree;\
+ assert(t!=NULL);\
+ ar = a->rightt;\
+ b = t->leftt;\
+ if (b==NULL) {\
+ assert(SGLIB___GET_VALUE(t->bits)==RED);\
+ SGLIB___SET_VALUE(t->bits,BLACK);\
+ res = 0;\
+ } else {\
+ bl = b->leftt;\
+ br = b->rightt;\
+ if (SGLIB___GET_VALUE(b->bits)==RED) {\
+ if (br==NULL) {\
+ *tree = b;\
+ SGLIB___SET_VALUE(b->bits,BLACK);\
+ b->rightt = a;\
+ a->leftt = br;\
+ res = 0;\
+ } else {\
+ c = br;\
+ assert(c!=NULL && SGLIB___GET_VALUE(c->bits)==BLACK);\
+ cl = c->leftt;\
+ cr = c->rightt;\
+ if ((cl==NULL||SGLIB___GET_VALUE(cl->bits)==BLACK) && (cr==NULL||SGLIB___GET_VALUE(cr->bits)==BLACK)) {\
+ *tree = b;\
+ b->rightt = a;\
+ SGLIB___SET_VALUE(b->bits,BLACK);\
+ a->leftt = c;\
+ SGLIB___SET_VALUE(c->bits,RED);\
+ res = 0;\
+ } else if (cl!=NULL && SGLIB___GET_VALUE(cl->bits)==RED) {\
+ if (cr!=NULL && SGLIB___GET_VALUE(cr->bits)==RED) {\
+ d = cr;\
+ dl = d->leftt;\
+ dr = d->rightt;\
+ *tree = d;\
+ SGLIB___SET_VALUE(d->bits,BLACK);\
+ d->leftt = b;\
+ c->rightt = dl;\
+ d->rightt = a;\
+ a->leftt = dr;\
+ res = 0;\
+ } else {\
+ *tree = c;\
+ c->leftt = b;\
+ c->rightt = a;\
+ b->leftt = bl;\
+ b->rightt = cl;\
+ a->leftt = cr;\
+ SGLIB___SET_VALUE(cl->bits,BLACK);\
+ res = 0;\
+ }\
+ } else if (cr!=NULL && SGLIB___GET_VALUE(cr->bits)==RED) {\
+ assert(cl==NULL || SGLIB___GET_VALUE(cl->bits)==BLACK);\
+ d = cr;\
+ dl = d->leftt;\
+ dr = d->rightt;\
+ *tree = d;\
+ SGLIB___SET_VALUE(d->bits,BLACK);\
+ d->leftt = b;\
+ c->rightt = dl;\
+ d->rightt = a;\
+ a->leftt = dr;\
+ res = 0;\
+ } else {\
+ assert(0);\
+ res = 0;\
+ }\
+ }\
+ } else {\
+ if ((bl==NULL || SGLIB___GET_VALUE(bl->bits)==BLACK) && (br==NULL || SGLIB___GET_VALUE(br->bits)==BLACK)) {\
+ res = (SGLIB___GET_VALUE(a->bits)==BLACK);\
+ SGLIB___SET_VALUE(a->bits,BLACK);\
+ SGLIB___SET_VALUE(b->bits,RED);\
+ } else if (bl!=NULL && SGLIB___GET_VALUE(bl->bits)==RED) {\
+ if (br==NULL || SGLIB___GET_VALUE(br->bits)==BLACK) {\
+ *tree = b;\
+ SGLIB___SET_VALUE(b->bits,SGLIB___GET_VALUE(a->bits));\
+ SGLIB___SET_VALUE(a->bits,BLACK);\
+ b->rightt = a;\
+ a->leftt = br;\
+ SGLIB___SET_VALUE(bl->bits,BLACK);\
+ res = 0;\
+ } else {\
+ assert(bl!=NULL);\
+ assert(br!=NULL);\
+ assert(SGLIB___GET_VALUE(bl->bits)==RED);\
+ assert(SGLIB___GET_VALUE(br->bits)==RED);\
+ c = br;\
+ cl = c->leftt;\
+ cr = c->rightt;\
+ *tree = c;\
+ SGLIB___SET_VALUE(c->bits,SGLIB___GET_VALUE(a->bits));\
+ SGLIB___SET_VALUE(a->bits,BLACK);\
+ c->leftt = b;\
+ c->rightt = a;\
+ b->rightt = cl;\
+ a->leftt = cr;\
+ res = 0;\
+ }\
+ } else {\
+ assert(br!=NULL && SGLIB___GET_VALUE(br->bits)==RED);\
+ c = br;\
+ cl = c->leftt;\
+ cr = c->rightt;\
+ *tree = c;\
+ SGLIB___SET_VALUE(c->bits,SGLIB___GET_VALUE(a->bits));\
+ SGLIB___SET_VALUE(a->bits,BLACK);\
+ c->leftt = b;\
+ c->rightt = a;\
+ b->rightt = cl;\
+ a->leftt = cr;\
+ res = 0;\
+ }\
+ }\
+ }\
+}
+
+
+#define SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, bits, comparator, RED, BLACK) \
+static void sglib___##type##_fix_left_insertion_discrepancy(type **tree) {\
+ SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, left, right, bits, RED, BLACK);\
+}\
+\
+static void sglib___##type##_fix_right_insertion_discrepancy(type **tree) {\
+ SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, right, left, bits, RED, BLACK);\
+}\
+\
+static int sglib___##type##_fix_left_deletion_discrepancy(type **tree) {\
+ int res;\
+ SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, right, left, bits, RED, BLACK, res);\
+ return(res);\
+}\
+\
+static int sglib___##type##_fix_right_deletion_discrepancy(type **tree) {\
+ int res;\
+ SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, left, right, bits, RED, BLACK, res);\
+ return(res);\
+}\
+\
+static void sglib___##type##_add_recursive(type **tree, type *elem) {\
+ int cmp;\
+ type *t;\
+ t = *tree;\
+ if (t == NULL) {\
+ SGLIB___SET_VALUE(elem->bits,RED);\
+ *tree =elem;\
+ } else {\
+ cmp = comparator(elem, t);\
+ if (cmp < 0 || (cmp==0 && elem<t)) {\
+ sglib___##type##_add_recursive(&t->left, elem);\
+ if (SGLIB___GET_VALUE(t->bits)==BLACK) sglib___##type##_fix_left_insertion_discrepancy(tree);\
+ } else {\
+ sglib___##type##_add_recursive(&t->right, elem);\
+ if (SGLIB___GET_VALUE(t->bits)==BLACK) sglib___##type##_fix_right_insertion_discrepancy(tree);\
+ }\
+ }\
+}\
+\
+static int sglib___##type##_delete_rightmost_leaf(type **tree, type **theLeaf) {\
+ type *t;\
+ int res, deepDecreased;\
+ t = *tree;\
+ res = 0;\
+ assert(t!=NULL);\
+ if (t->right == NULL) {\
+ *theLeaf = t;\
+ if (t->left!=NULL) {\
+ if (SGLIB___GET_VALUE(t->bits)==BLACK && SGLIB___GET_VALUE(t->left->bits)==BLACK) res = 1;\
+ SGLIB___SET_VALUE(t->left->bits,BLACK);\
+ *tree = t->left;\
+ } else {\
+ *tree = NULL;\
+ res = (SGLIB___GET_VALUE(t->bits)==BLACK);\
+ }\
+ } else {\
+ deepDecreased = sglib___##type##_delete_rightmost_leaf(&t->right, theLeaf);\
+ if (deepDecreased) res = sglib___##type##_fix_right_deletion_discrepancy(tree);\
+ }\
+ return(res);\
+}\
+\
+int sglib___##type##_delete_recursive(type **tree, type *elem) {\
+ type *t, *theLeaf;\
+ int cmp, res, deepDecreased;\
+ t = *tree;\
+ res = 0;\
+ if (t==NULL) {\
+ assert(0 && "The element to delete not found in the tree, use 'delete_if_member'"!=NULL);\
+ } else {\
+ cmp = comparator(elem, t);\
+ if (cmp < 0 || (cmp==0 && elem<t)) {\
+ deepDecreased = sglib___##type##_delete_recursive(&t->left, elem);\
+ if (deepDecreased) {\
+ res = sglib___##type##_fix_left_deletion_discrepancy(tree);\
+ }\
+ } else if (cmp > 0 || (cmp==0 && elem>t)) {\
+ deepDecreased = sglib___##type##_delete_recursive(&t->right, elem);\
+ if (deepDecreased) {\
+ res = sglib___##type##_fix_right_deletion_discrepancy(tree);\
+ }\
+ } else {\
+ assert(elem==t && "Deleting an element which is non member of the tree, use 'delete_if_member'"!=NULL);\
+ if (t->left == NULL) {\
+ if (t->right == NULL) {\
+ /* a leaf, delete, it; */\
+ *tree = NULL;\
+ res = (SGLIB___GET_VALUE(t->bits)==BLACK);\
+ } else {\
+ if (SGLIB___GET_VALUE(t->bits)==0 && SGLIB___GET_VALUE(t->right->bits)==0) res = 1;\
+ SGLIB___SET_VALUE(t->right->bits,BLACK);\
+ *tree = t->right;\
+ }\
+ } else {\
+ /* propagate deletion until righmost leaf of left subtree */\
+ deepDecreased = sglib___##type##_delete_rightmost_leaf(&t->left, &theLeaf);\
+ theLeaf->left = t->left;\
+ theLeaf->right = t->right;\
+ SGLIB___SET_VALUE(theLeaf->bits,SGLIB___GET_VALUE(t->bits));\
+ *tree = theLeaf;\
+ if (deepDecreased) res = sglib___##type##_fix_left_deletion_discrepancy(tree);\
+ }\
+ }\
+ }\
+ return(res);\
+}\
+\
+void sglib_##type##_add(type **tree, type *elem) {\
+ elem->left = elem->right = NULL;\
+ sglib___##type##_add_recursive(tree, elem);\
+ SGLIB___SET_VALUE((*tree)->bits,BLACK);\
+}\
+\
+void sglib_##type##_delete(type **tree, type *elem) {\
+ sglib___##type##_delete_recursive(tree, elem);\
+ if (*tree!=NULL) SGLIB___SET_VALUE((*tree)->bits,BLACK);\
+}\
+\
+type *sglib_##type##_find_member(type *t, type *elem) {\
+ type *res;\
+ SGLIB___BIN_TREE_FIND_MEMBER(type, t, elem, left, right, comparator, res);\
+ return(res);\
+}\
+\
+int sglib_##type##_is_member(type *t, type *elem) {\
+ int cmp;\
+ while (t!=NULL) {\
+ cmp = comparator(elem, t);\
+ if (cmp < 0 || (cmp==0 && elem<t)) {\
+ t = t->left;\
+ } else if (cmp > 0 || (cmp==0 && elem>t)) {\
+ t = t->right;\
+ } else {\
+ assert(t == elem);\
+ return(1);\
+ }\
+ }\
+ return(0);\
+}\
+\
+int sglib_##type##_delete_if_member(type **tree, type *elem, type **memb) {\
+ if ((*memb=sglib_##type##_find_member(*tree, elem))!=NULL) {\
+ sglib_##type##_delete(tree, *memb);\
+ return(1);\
+ } else {\
+ return(0);\
+ }\
+}\
+int sglib_##type##_add_if_not_member(type **tree, type *elem, type **memb) {\
+ if ((*memb=sglib_##type##_find_member(*tree, elem))==NULL) {\
+ sglib_##type##_add(tree, elem);\
+ return(1);\
+ } else {\
+ return(0);\
+ }\
+}\
+int sglib_##type##_len(type *t) {\
+ int n;\
+ type *e;\
+ n = 0;\
+ SGLIB_BIN_TREE_MAP_ON_ELEMENTS(type, t, e, left, right, n++);\
+ return(n);\
+}\
+\
+void sglib__##type##_it_compute_current_elem(struct sglib_##type##_iterator *it) {\
+ int i,j,cmp;\
+ type *s, *eqt;\
+ int (*subcomparator)(type *, type *);\
+ eqt = it->equalto;\
+ subcomparator = it->subcomparator;\
+ it->currentelem = NULL;\
+ while(it->pathi > 0 && it->currentelem==NULL) {\
+ i = it->pathi-1;\
+ if (i >= 0) {\
+ if (it->pass[i] >= 2) {\
+ /* goto up */\
+ it->pathi --;\
+ } else {\
+ if (it->pass[i] == 0) {\
+ /* goto left */\
+ s = it->path[i]->left;\
+ } else {\
+ /* goto right */\
+ s = it->path[i]->right;\
+ }\
+ if (eqt != NULL) {\
+ if (subcomparator == NULL) {\
+ SGLIB___BIN_TREE_FIND_MEMBER(type, s, eqt, left, right, comparator, s);\
+ } else {\
+ SGLIB___BIN_TREE_FIND_MEMBER(type, s, eqt, left, right, subcomparator, s);\
+ }\
+ }\
+ if (s != NULL) {\
+ j = i+1;\
+ it->path[j] = s;\
+ it->pass[j] = 0;\
+ it->pathi ++;\
+ }\
+ it->pass[i] ++;\
+ }\
+ }\
+ if (it->pathi>0 && it->order == it->pass[it->pathi-1]) {\
+ it->currentelem = it->path[it->pathi-1];\
+ }\
+ }\
+}\
+type *sglib__##type##_it_init(struct sglib_##type##_iterator *it, type *tree, int order, int (*subcomparator)(type *, type *), type *equalto) {\
+ type *t;\
+ assert(it!=NULL);\
+ it->order = order;\
+ it->equalto = equalto;\
+ it->subcomparator = subcomparator;\
+ if (equalto == NULL) { \
+ t = tree;\
+ } else {\
+ if (subcomparator == NULL) {\
+ SGLIB___BIN_TREE_FIND_MEMBER(type, tree, equalto, left, right, comparator, t);\
+ } else {\
+ SGLIB___BIN_TREE_FIND_MEMBER(type, tree, equalto, left, right, subcomparator, t);\
+ }\
+ }\
+ if (t == NULL) {\
+ it->pathi = 0;\
+ it->currentelem = NULL;\
+ } else {\
+ it->pathi = 1;\
+ it->pass[0] = 0;\
+ it->path[0] = t;\
+ if (order == 0) {\
+ it->currentelem = t;\
+ } else {\
+ sglib__##type##_it_compute_current_elem(it);\
+ }\
+ }\
+ return(it->currentelem);\
+}\
+type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *tree) {\
+ return(sglib__##type##_it_init(it, tree, 2, NULL, NULL));\
+}\
+type *sglib_##type##_it_init_preorder(struct sglib_##type##_iterator *it, type *tree) {\
+ return(sglib__##type##_it_init(it, tree, 0, NULL, NULL));\
+}\
+type *sglib_##type##_it_init_inorder(struct sglib_##type##_iterator *it, type *tree) {\
+ return(sglib__##type##_it_init(it, tree, 1, NULL, NULL));\
+}\
+type *sglib_##type##_it_init_postorder(struct sglib_##type##_iterator *it, type *tree) {\
+ return(sglib__##type##_it_init(it, tree, 2, NULL, NULL));\
+}\
+type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *tree, int (*subcomparator)(type *, type *), type *equalto) {\
+ return(sglib__##type##_it_init(it, tree, 1, subcomparator, equalto));\
+}\
+type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\
+ return(it->currentelem);\
+}\
+type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\
+ sglib__##type##_it_compute_current_elem(it);\
+ return(it->currentelem);\
+}\
+\
+static void sglib___##type##_consistency_check_recursive(type *t, int *pathdeep, int cdeep) {\
+ if (t==NULL) {\
+ if (*pathdeep < 0) *pathdeep = cdeep;\
+ else assert(*pathdeep == cdeep);\
+ } else {\
+ if (t->left!=NULL) assert(comparator(t->left, t) <= 0);\
+ if (t->right!=NULL) assert(comparator(t, t->right) <= 0);\
+ if (SGLIB___GET_VALUE(t->bits) == RED) {\
+ assert(t->left == NULL || SGLIB___GET_VALUE(t->left->bits)==BLACK);\
+ assert(t->right == NULL || SGLIB___GET_VALUE(t->right->bits)==BLACK);\
+ sglib___##type##_consistency_check_recursive(t->left, pathdeep, cdeep);\
+ sglib___##type##_consistency_check_recursive(t->right, pathdeep, cdeep);\
+ } else {\
+ sglib___##type##_consistency_check_recursive(t->left, pathdeep, cdeep+1);\
+ sglib___##type##_consistency_check_recursive(t->right, pathdeep, cdeep+1);\
+ }\
+ }\
+}\
+\
+void sglib___##type##_consistency_check(type *t) {\
+ int pathDeep;\
+ assert(t==NULL || SGLIB___GET_VALUE(t->bits) == BLACK);\
+ pathDeep = -1;\
+ sglib___##type##_consistency_check_recursive(t, &pathDeep, 0);\
+}
+
+
+#define SGLIB_DEFINE_RBTREE_PROTOTYPES(type, left, right, colorbit, comparator) \
+ struct sglib_##type##_iterator {\
+ type *currentelem;\
+ char pass[SGLIB_MAX_TREE_DEEP];\
+ type *path[SGLIB_MAX_TREE_DEEP];\
+ short int pathi;\
+ short int order;\
+ type *equalto;\
+ int (*subcomparator)(type *, type *);\
+ };\
+ extern void sglib___##type##_consistency_check(type *t); \
+ extern void sglib_##type##_add(type **tree, type *elem); \
+ extern int sglib_##type##_add_if_not_member(type **tree, type *elem, type **memb); \
+ extern void sglib_##type##_delete(type **tree, type *elem); \
+ extern int sglib_##type##_delete_if_member(type **tree, type *elem, type **memb); \
+ extern int sglib_##type##_is_member(type *t, type *elem); \
+ extern type *sglib_##type##_find_member(type *t, type *elem); \
+ extern int sglib_##type##_len(type *t); \
+ extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *tree); \
+ extern type *sglib_##type##_it_init_preorder(struct sglib_##type##_iterator *it, type *tree); \
+ extern type *sglib_##type##_it_init_inorder(struct sglib_##type##_iterator *it, type *tree); \
+ extern type *sglib_##type##_it_init_postorder(struct sglib_##type##_iterator *it, type *tree); \
+ extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *tree, int (*subcomparator)(type *, type *), type *equalto); \
+ extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \
+ extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); \
+
+
+#define SGLIB_DEFINE_RBTREE_FUNCTIONS(type, left, right, colorbit, comparator) \
+ SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, colorbit, comparator, 1, 0)
+
+
+
+/* ---------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------- */
+/* - SUPPLEMENTARY DEFINITIONS - */
+/* ---------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------- */
+
+
+#define SGLIB___GET_VALUE(x) (x)
+#define SGLIB___SET_VALUE(x, value) {(x) = (value);}
+#define SGLIB_ARRAY_ELEMENTS_EXCHANGER(type, a, i, j) {type _sgl_aee_tmp_; _sgl_aee_tmp_=(a)[(i)]; (a)[(i)]=(a)[(j)]; (a)[(j)]= _sgl_aee_tmp_;}
+
+
+#define SGLIB_NUMERIC_COMPARATOR(x, y) ((int)((x) - (y)))
+#define SGLIB_REVERSE_NUMERIC_COMPARATOR(x, y) ((int)((y) - (x)))
+
+#ifndef SGLIB_MAX_TREE_DEEP
+#define SGLIB_MAX_TREE_DEEP 128
+#endif
+
+#ifndef SGLIB_HASH_TAB_SHIFT_CONSTANT
+#define SGLIB_HASH_TAB_SHIFT_CONSTANT 16381 /* should be a prime */
+/* #define SGLIB_HASH_TAB_SHIFT_CONSTANT 536870912 for large tables */
+#endif
+
+#endif /* _SGLIB__h_ */
diff --git a/test-chords_graph.pd b/test-chords_graph.pd
new file mode 100755
index 0000000..639eac8
--- /dev/null
+++ b/test-chords_graph.pd
@@ -0,0 +1,46 @@
+#N canvas 241 61 710 346 12;
+#X msg 63 130 write test.graph;
+#X msg 93 158 read test.graph;
+#X obj 389 33 notein;
+#X obj 389 68 chord 59;
+#X msg 293 151 add \$1;
+#X obj 71 255 chords_graph;
+#X obj 293 123 symbol;
+#X obj 294 96 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 285 234 next 1;
+#X obj 366 165 symbol;
+#X obj 367 138 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 366 193 set \$1;
+#X msg 123 188 init 1;
+#X symbolatom 71 281 20 0 0 0 - - -;
+#X symbolatom 429 103 25 0 0 0 - - -;
+#N canvas 39 349 531 328 readme 0;
+#X text 59 31 howto populate the graph: play the chord \, when the
+output of [chord] is ok bang the "add" message. bang it each time you
+change chord \, it will store the transitions;
+#X text 56 120 howto ask for the next chord: play the chord \, bang
+the "set" message \, this will set the current chord without adding
+it to the graph's memory \, now bang the next 1 message. this chord_graph
+will respond with the chord you played most of the times after the
+current chord. you can send "next x" where x is from 0 to 1 \, 0 =
+max novelty \, 1= min novelty;
+#X text 56 259 you can save graph state sending the write message;
+#X restore 385 252 pd readme;
+#X connect 0 0 5 0;
+#X connect 1 0 5 0;
+#X connect 2 0 3 0;
+#X connect 2 1 3 1;
+#X connect 3 2 6 1;
+#X connect 3 2 9 1;
+#X connect 3 2 14 0;
+#X connect 4 0 5 0;
+#X connect 5 0 13 0;
+#X connect 6 0 4 0;
+#X connect 7 0 6 0;
+#X connect 8 0 5 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 0;
+#X connect 11 0 5 0;
+#X connect 12 0 5 0;
diff --git a/test-harmonizer.pd b/test-harmonizer.pd
new file mode 100755
index 0000000..f8e4ebd
--- /dev/null
+++ b/test-harmonizer.pd
@@ -0,0 +1,172 @@
+#N canvas 328 37 702 643 12;
+#X symbolatom 179 191 20 0 0 0 - - -;
+#N canvas 39 349 531 328 readme 0;
+#X text 59 31 howto populate the graph: play the chord \, when the
+output of [chord] is ok bang the "add" message. bang it each time you
+change chord \, it will store the transitions;
+#X text 56 120 howto ask for the next chord: play the chord \, bang
+the "set" message \, this will set the current chord without adding
+it to the graph's memory \, now bang the next 1 message. this chord_graph
+will respond with the chord you played most of the times after the
+current chord. you can send "next x" where x is from 0 to 1 \, 0 =
+max novelty \, 1= min novelty;
+#X text 56 259 you can save graph state sending the write message;
+#X restore 496 48 pd readme;
+#X obj 121 316 harmonizer;
+#X msg 52 273 current \$1;
+#X msg 158 270 target \$1;
+#X obj 52 249 symbol;
+#X obj 52 229 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 157 248 symbol;
+#X obj 289 248 int 36;
+#X obj 355 249 int 60;
+#X obj 426 247 int 67;
+#X obj 494 246 int 76;
+#X obj 566 249 int 84;
+#X obj 335 276 pack f f f f f;
+#X obj 358 220 t b b b b b;
+#X obj 246 356 unpack f f f f f;
+#X obj 135 105 symbol;
+#X obj 98 43 bng 15 250 50 0 empty empty change_chord 0 -6 0 8 -262144
+-1 -1;
+#X msg 135 133 set \$1;
+#N canvas 0 0 706 416 midi 0;
+#X obj 141 253 outlet;
+#X obj 271 31 notein;
+#X obj 271 66 chord 59;
+#X msg 175 149 add \$1;
+#X obj 175 121 symbol;
+#X obj 176 94 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 248 163 symbol;
+#X obj 249 136 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 248 191 set \$1;
+#X symbolatom 311 101 25 0 0 0 - - -;
+#X connect 1 0 2 0;
+#X connect 1 1 2 1;
+#X connect 2 2 4 1;
+#X connect 2 2 6 1;
+#X connect 2 2 9 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 8 0;
+#X connect 7 0 6 0;
+#X connect 8 0 0 0;
+#X restore 326 134 pd midi;
+#N canvas 0 0 454 304 fileIO 0;
+#X obj 143 225 outlet;
+#X msg 115 77 write test.graph;
+#X msg 145 105 read test.graph;
+#X msg 175 135 init 1;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X restore 243 133 pd fileIO;
+#X obj 100 81 t b b;
+#X obj 157 215 t b a;
+#X obj 28 391 bang;
+#X symbolatom 256 35 20 0 0 0 - - -;
+#X obj 256 11 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 203 407 mtof;
+#X obj 203 431 sig~;
+#X obj 204 457 osc~ 440;
+#X obj 280 405 mtof;
+#X obj 280 429 sig~;
+#X obj 281 455 osc~ 440;
+#X obj 338 509 mtof;
+#X obj 338 533 sig~;
+#X obj 339 559 osc~ 440;
+#X obj 375 403 mtof;
+#X obj 375 427 sig~;
+#X obj 376 453 osc~ 440;
+#X obj 425 509 mtof;
+#X obj 424 532 sig~;
+#X obj 425 558 osc~ 440;
+#X obj 186 491 throw~ audio;
+#X obj 284 482 throw~ audio;
+#X obj 391 483 throw~ audio;
+#X obj 337 586 throw~ audio;
+#X obj 439 588 throw~ audio;
+#X obj 99 533 catch~ audio;
+#X obj 99 585 dac~;
+#X obj 99 558 *~ 0.2;
+#X obj 109 418 print;
+#X obj 83 169 chords_graph test.graph;
+#X obj 74 111 f 1;
+#X msg 59 135 next \$1;
+#X obj 63 70 vsl 15 30 0 1 0 0 empty empty empty 0 -8 0 8 -262144 -1
+-1 2900 1;
+#X floatatom 32 112 5 0 0 0 - - -;
+#X connect 2 0 15 0;
+#X connect 2 0 49 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 4 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 1;
+#X connect 10 0 13 2;
+#X connect 11 0 13 3;
+#X connect 12 0 13 4;
+#X connect 13 0 2 0;
+#X connect 14 0 8 0;
+#X connect 14 1 9 0;
+#X connect 14 2 10 0;
+#X connect 14 3 11 0;
+#X connect 14 4 12 0;
+#X connect 15 0 8 1;
+#X connect 15 0 23 0;
+#X connect 15 0 26 0;
+#X connect 15 1 9 1;
+#X connect 15 1 29 0;
+#X connect 15 2 10 1;
+#X connect 15 2 32 0;
+#X connect 15 3 11 1;
+#X connect 15 3 35 0;
+#X connect 15 4 12 1;
+#X connect 15 4 38 0;
+#X connect 16 0 18 0;
+#X connect 17 0 21 0;
+#X connect 18 0 50 0;
+#X connect 19 0 50 0;
+#X connect 20 0 50 0;
+#X connect 21 0 51 0;
+#X connect 21 1 16 0;
+#X connect 22 0 14 0;
+#X connect 22 1 7 0;
+#X connect 23 0 5 0;
+#X connect 24 0 5 1;
+#X connect 24 0 16 0;
+#X connect 24 0 7 0;
+#X connect 25 0 24 0;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 28 0 41 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 0;
+#X connect 31 0 42 0;
+#X connect 32 0 33 0;
+#X connect 33 0 34 0;
+#X connect 34 0 44 0;
+#X connect 35 0 36 0;
+#X connect 36 0 37 0;
+#X connect 37 0 43 0;
+#X connect 38 0 39 0;
+#X connect 39 0 40 0;
+#X connect 40 0 45 0;
+#X connect 46 0 48 0;
+#X connect 48 0 47 0;
+#X connect 48 0 47 1;
+#X connect 50 0 0 0;
+#X connect 50 0 5 1;
+#X connect 50 0 16 1;
+#X connect 50 0 22 0;
+#X connect 51 0 52 0;
+#X connect 52 0 50 0;
+#X connect 53 0 51 1;
+#X connect 53 0 54 0;
diff --git a/test-harmonizer2.pd b/test-harmonizer2.pd
new file mode 100755
index 0000000..b6f6756
--- /dev/null
+++ b/test-harmonizer2.pd
@@ -0,0 +1,197 @@
+#N canvas 72 0 919 691 12;
+#X symbolatom 157 205 18 0 0 2 next_chord - -;
+#N canvas 39 349 531 328 readme 0;
+#X text 59 31 howto populate the graph: play the chord \, when the
+output of [chord] is ok bang the "add" message. bang it each time you
+change chord \, it will store the transitions;
+#X text 56 120 howto ask for the next chord: play the chord \, bang
+the "set" message \, this will set the current chord without adding
+it to the graph's memory \, now bang the next 1 message. this chord_graph
+will respond with the chord you played most of the times after the
+current chord. you can send "next x" where x is from 0 to 1 \, 0 =
+max novelty \, 1= min novelty;
+#X text 56 259 you can save graph state sending the write message;
+#X restore 607 47 pd readme;
+#X obj 121 329 harmonizer;
+#X msg 52 286 current \$1;
+#X msg 158 283 target \$1;
+#X obj 52 262 symbol;
+#X obj 52 242 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 157 261 symbol;
+#X obj 289 261 int 36;
+#X obj 355 262 int 60;
+#X obj 426 260 int 67;
+#X obj 494 259 int 76;
+#X obj 566 262 int 84;
+#X obj 335 289 pack f f f f f;
+#X obj 358 233 t b b b b b;
+#X obj 246 369 unpack f f f f f;
+#X obj 127 108 symbol;
+#X obj 98 43 bng 15 250 50 0 empty empty change_chord 0 -6 0 8 -262144
+-1 -1;
+#X msg 127 132 set \$1;
+#N canvas 0 0 714 424 midi 0;
+#X obj 141 253 outlet;
+#X obj 271 31 notein;
+#X obj 271 66 chord 59;
+#X msg 175 149 add \$1;
+#X obj 175 121 symbol;
+#X obj 176 94 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 248 163 symbol;
+#X obj 249 136 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 248 191 set \$1;
+#X symbolatom 311 101 25 0 0 0 - - -;
+#X connect 1 0 2 0;
+#X connect 1 1 2 1;
+#X connect 2 2 4 1;
+#X connect 2 2 6 1;
+#X connect 2 2 9 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 8 0;
+#X connect 7 0 6 0;
+#X connect 8 0 0 0;
+#X restore 512 135 pd midi;
+#N canvas 0 0 458 308 fileIO 0;
+#X obj 143 225 outlet;
+#X msg 115 77 write test.graph;
+#X msg 145 105 read test.graph;
+#X msg 175 135 init 1;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X restore 429 134 pd fileIO;
+#X obj 100 73 t b b;
+#X obj 157 228 t b a;
+#X obj 28 404 bang;
+#X obj 203 420 mtof;
+#X obj 252 419 mtof;
+#X obj 337 423 mtof;
+#X obj 180 601 dac~;
+#X obj 109 431 print;
+#X obj 74 111 f 1;
+#X msg 59 135 next \$1;
+#X obj 63 70 vsl 15 30 0 1 0 0 empty empty empty 0 -8 0 8 -262144 -1
+-1 2610 1;
+#X floatatom 32 112 5 0 0 0 - - -;
+#X obj 178 571 csoundapi~ bay.orc;
+#X msg 488 520 event i 10 0 17000 10 30;
+#X msg 488 543 event i 30 0 17000 2 30;
+#X msg 489 496 event i 25 0 17000 0.98 0.8 20000;
+#X obj 482 458 loadbang;
+#X msg 196 492 event i 9 0 10 \$1 80 0.5;
+#X obj 295 422 mtof;
+#X obj 381 424 mtof;
+#X obj 462 22 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 462 41 metro 7000;
+#X obj 13 32 r novelty;
+#X obj 599 121 int 0;
+#X obj 646 120 + 1;
+#X obj 600 171 tabread tab-novelty;
+#X obj 600 194 s novelty;
+#X obj 685 119 table tab-novelty;
+#X obj 600 147 % 10;
+#X obj 462 63 t b b;
+#X msg 467 377 \; tab-novelty 0 1 1 0.8 0.7 0.3 0.5 0.9 0.1 0 0.2;
+#X obj 203 97 symbol;
+#X msg 203 125 tonality \$1;
+#X obj 203 73 bng 15 250 50 0 empty empty change 0 -6 0 8 -262144 -1
+-1;
+#X obj 19 160 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X symbolatom 305 204 15 0 0 2 tonality - -;
+#X obj 83 169 chords_memory test.graph;
+#X obj 307 94 symbol;
+#X obj 307 70 bng 15 250 50 0 empty empty change 0 -6 0 8 -262144 -1
+-1;
+#X msg 307 122 modulation \$1;
+#X obj 445 189 print sequence;
+#X msg 235 15 search 9 1 5 0.9;
+#X connect 2 0 15 0;
+#X connect 2 0 28 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 4 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 1;
+#X connect 10 0 13 2;
+#X connect 11 0 13 3;
+#X connect 12 0 13 4;
+#X connect 13 0 2 0;
+#X connect 14 0 8 0;
+#X connect 14 1 9 0;
+#X connect 14 2 10 0;
+#X connect 14 3 11 0;
+#X connect 14 4 12 0;
+#X connect 15 0 8 1;
+#X connect 15 0 23 0;
+#X connect 15 0 24 0;
+#X connect 15 1 9 1;
+#X connect 15 1 25 0;
+#X connect 15 2 10 1;
+#X connect 15 2 39 0;
+#X connect 15 3 11 1;
+#X connect 15 3 26 0;
+#X connect 15 4 12 1;
+#X connect 15 4 40 0;
+#X connect 16 0 18 0;
+#X connect 17 0 21 0;
+#X connect 18 0 57 0;
+#X connect 19 0 57 0;
+#X connect 20 0 57 0;
+#X connect 21 0 29 0;
+#X connect 22 0 14 0;
+#X connect 22 1 7 0;
+#X connect 23 0 5 0;
+#X connect 24 0 38 0;
+#X connect 25 0 38 0;
+#X connect 26 0 38 0;
+#X connect 29 0 30 0;
+#X connect 30 0 57 0;
+#X connect 31 0 29 1;
+#X connect 31 0 32 0;
+#X connect 33 0 27 0;
+#X connect 33 1 27 1;
+#X connect 34 0 33 0;
+#X connect 35 0 33 0;
+#X connect 36 0 33 0;
+#X connect 37 0 36 0;
+#X connect 37 0 34 0;
+#X connect 37 0 35 0;
+#X connect 37 0 51 0;
+#X connect 38 0 33 0;
+#X connect 39 0 38 0;
+#X connect 40 0 38 0;
+#X connect 41 0 42 0;
+#X connect 42 0 50 0;
+#X connect 43 0 31 0;
+#X connect 44 0 45 0;
+#X connect 44 0 49 0;
+#X connect 45 0 44 1;
+#X connect 46 0 47 0;
+#X connect 49 0 46 0;
+#X connect 50 0 21 0;
+#X connect 50 1 44 0;
+#X connect 52 0 53 0;
+#X connect 53 0 57 0;
+#X connect 54 0 52 0;
+#X connect 55 0 57 0;
+#X connect 57 0 0 0;
+#X connect 57 0 5 1;
+#X connect 57 0 22 0;
+#X connect 57 0 52 1;
+#X connect 57 0 16 0;
+#X connect 57 0 58 1;
+#X connect 57 1 56 0;
+#X connect 57 2 61 0;
+#X connect 58 0 60 0;
+#X connect 59 0 58 0;
+#X connect 60 0 57 0;
+#X connect 62 0 57 0;
diff --git a/test.graph b/test.graph
new file mode 100755
index 0000000..73c168c
--- /dev/null
+++ b/test.graph
Binary files differ