From f4ad91a62cf11ef1c3bd71c864ca76a324debc6e Mon Sep 17 00:00:00 2001 From: Davide Morelli Date: Wed, 4 Jan 2006 23:33:33 +0000 Subject: checking in the themes_memory skeleton, just a copy of rhythms_memory svn path=/trunk/externals/frankenstein/; revision=4362 --- themes_memory.c | 431 +++++++++++++++++++++++++++++++++++++++++++++++++++ themes_memory.sln | 21 +++ themes_memory.suo | Bin 0 -> 7680 bytes themes_memory.vcproj | 130 ++++++++++++++++ 4 files changed, 582 insertions(+) create mode 100755 themes_memory.c create mode 100755 themes_memory.sln create mode 100755 themes_memory.suo create mode 100755 themes_memory.vcproj diff --git a/themes_memory.c b/themes_memory.c new file mode 100755 index 0000000..d4d716a --- /dev/null +++ b/themes_memory.c @@ -0,0 +1,431 @@ +/* +themes_memory + +Authors: +Davide Morelli http://www.davidemorelli.it +David Plans Casal http://www.studios.uea.ac.uk/people/staff/casal + +uses graphs to store melodies + +it is just like rhythms_memory but works on the more complex world of themes + +TODO: + * memory save/load to file (?) + * output rhythms in the form of list of floats (easy) + * add velo (?) + * input rhythms from a list (second inlet) (easy) + * let it create variations on known rhythms (?) + * let it merge rhythms (?) + +*/ + +#include "m_pd.h" + +#include "common.h" +#include +#include +#include + +static t_class *themes_memory_class; + +typedef struct event event; +typedef struct event +{ + unsigned short int voice; + double when; + event *next; +}; + +typedef struct _themes_memory +{ + t_object x_obj; // myself + // 3 outlets: + // bangs_out plays the wanted rhythmsin realtime + // list_out outputs the wanted rhythm as a list of floats + // info_out outputs info on the last recognized rhythm + t_outlet *bangs_out, *list_out, *info_out; + t_rhythm_event *curr_seq; + int seq_initialized; + // the memory + t_rhythm_memory_representation *themes_memory; + // measure length + double measure_start_time; + double measure_length; + // input rhythm's events + event *events; + // output rhythm's events + unsigned short int next_main_rhythm_out; + unsigned short int next_sub_rhythm_out; + event *events_out; + t_clock *x_clock; + double x_deltime; + double last_event_out_time; + +} t_themes_memory; + +void themes_memory_free(t_themes_memory *x) +{ + if (x->curr_seq) + freeBeats(x->curr_seq); + if (x->themes_memory) + rhythm_memory_free(x->themes_memory); + + clock_free(x->x_clock); +} + +// called when a new measure starts +void start_measure(t_themes_memory *x) +{ + // I call the pd functions to get a representation + // of this very moment + x->measure_start_time = clock_getlogicaltime(); + x->last_event_out_time = 0; +} + +// called when a new event occours +void add_event(t_themes_memory *x, unsigned short int voice) +{ + event *newEvent, *currEvent, *lastEvent; + double when; + when = clock_gettimesince(x->measure_start_time); + newEvent = (event *) malloc(sizeof(event)); + newEvent->when = when; + newEvent->voice = voice; + newEvent->next = 0; + currEvent = x->events; + if (currEvent) + { + // this is not the first event + while(currEvent) + { + lastEvent = currEvent; + currEvent = currEvent->next; + } + lastEvent->next = newEvent; + } else + { + // this is the first event + x->events = newEvent; + } + post("event added"); +} + +// called when a measure ends +void end_measure(t_themes_memory *x) +{ + float fduration; + event *currEvent, *lastEvent; + unsigned short int is_it_a_new_rhythm; + unsigned short int id, subid; + float root_closeness, sub_closeness; + int counter; + t_atom *lista; + // these 2 are for output rhythm + int rhythm_found; + t_rhythm_event *wanted_rhythm; + t_rhythm_event *curr_rhythm; + event *lastOutEvent; + + // I call the pd functions to get a representation + // of this very moment + x->measure_length = clock_gettimesince(x->measure_start_time); + // now that i know the exact length of the current measure + // i can process the rhythm in the current measure + // and evaluate it + currEvent = x->events; + // this is not the first event + // now I translate events in rhythm + counter = 0; + while(currEvent) + { + fduration = (float) (((float) currEvent->when) / ((float) x->measure_length)); + if (x->seq_initialized) + { + concatenateBeat(x->curr_seq, currEvent->voice, fduration, 1); + } else + { + setFirstBeat(&(x->curr_seq), currEvent->voice, fduration, 1); + x->seq_initialized = 1; + } + currEvent = currEvent->next; + counter++; + } + + // delete events after having evaluated them + currEvent = x->events; + // this is not the first event + while(currEvent) + { + lastEvent = currEvent; + currEvent = currEvent->next; + free(lastEvent); + } + x->events = 0; + + if (x->curr_seq) + { + // now I evaluate this rhythm with the memory + rhythm_memory_evaluate(x->themes_memory, x->curr_seq, &is_it_a_new_rhythm, + &id, &subid, &root_closeness, &sub_closeness); + // tell out the answer + // allocate space for the list + lista = (t_atom *) malloc(sizeof(t_atom) * 5); + SETFLOAT(lista, (float) is_it_a_new_rhythm); + SETFLOAT(lista+1, (float) id); + SETFLOAT(lista+2, (float) subid); + SETFLOAT(lista+3, (float) root_closeness); + SETFLOAT(lista+4, (float) sub_closeness); + outlet_anything(x->info_out, + gensym("list") , + 5, + lista); + free(lista); + // rhythm_memory_evaluate freed the memory for the rhythm if needed + x->seq_initialized = 0; + x->curr_seq = 0; + } + + // I free the list of events_out (if present) + currEvent = x->events_out; + // this is not the first event + while(currEvent) + { + lastEvent = currEvent; + currEvent = currEvent->next; + free(lastEvent); + } + x->events_out = 0; + // i set up the list of events_out + // for the wanted rhythm + if (x->next_main_rhythm_out) + { + wanted_rhythm = 0; + // ask the memory for the wanted rhythm + rhythm_found = rhythm_memory_get_rhythm(x->themes_memory, // the memory + &wanted_rhythm, // a pointer to the returned rhythm + // the id of the main rhythm wanted + x->next_main_rhythm_out, + // the sub-id of the sub-rhythm wanted + x->next_sub_rhythm_out); + if (rhythm_found==0) + { + post("themes_memory: rhythm %i %i was not found ", x->next_main_rhythm_out, x->next_sub_rhythm_out); + return 0; + } + + if (wanted_rhythm==0) + { + error("themes_memory: wanted_rhythm should not be null! "); + return 0; + } + + // now I setup the events_out list + // for each event in wanted_rhythm + // allocate and link an element of elements_out + curr_rhythm = wanted_rhythm; + lastOutEvent = 0; + while (curr_rhythm) + { + event *newEvent; + newEvent = malloc(sizeof(event)); + newEvent->next = 0; + newEvent->voice = curr_rhythm->voice; + newEvent->when = (double) (duration2float(curr_rhythm->start) * x->measure_length); + post("DEBUG: add event in moment: %f", newEvent->when); + if (x->events_out) + { + // this is not the first event + // assign the next + lastOutEvent->next = newEvent; + } else + { + // this is the first event + x->events_out = newEvent; + } + // change the last pointer + lastOutEvent = newEvent; + curr_rhythm = curr_rhythm->next; + } + + // also setup the timer for the first event + if (x->events_out) + { + // setup the clock + clock_delay(x->x_clock, x->events_out->when); + // remember when next event will occour + x->last_event_out_time = x->events_out->when; + // remember the curr event + lastOutEvent = x->events_out; + //reassign next event + x->events_out = x->events_out->next; + // free old event + free(lastOutEvent); + } + x->next_main_rhythm_out = 0; + + } + + // also start the new measure! + start_measure(x); + + +} + +// this function is called by pd +// when the timer bangs +static void rhythms_tick(t_themes_memory *x) +{ + event *lastOutEvent; + // here i must: + // take the next element in x->events_out + // and compute when I'll need to schedule next event + // (next_event - curr_event) + // set the next element as the current one + // and free the memory allocated for the old curr event + // set up the timer + post("DEBUG: eveng bang"); + // first of all trigger the bang! + outlet_bang(x->bangs_out); + //then do the stuff + if (x->events_out) + { + // setup the clock + clock_delay(x->x_clock, x->events_out->when - x->last_event_out_time); + // remember when next event will occour + x->last_event_out_time = x->events_out->when ; + // remember the curr event + lastOutEvent = x->events_out; + //reassign next event + x->events_out = x->events_out->next; + // free old event + free(lastOutEvent); + } +} + +// the user wants me to play a rhythm in the next measure +// the user MUST pass 2 args: main_rhythm and sub_rhythm wanted +static void ask_rhythm(t_themes_memory *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc<2) + { + error("this method needs at least 2 floats: main_rhythm and sub_rhythm wanted"); + return; + } + //argv++; + x->next_main_rhythm_out = atom_getfloat(argv++); + x->next_sub_rhythm_out = atom_getfloat(argv); + post("DEBUG: asked rhythm %i %i", x->next_main_rhythm_out, x->next_sub_rhythm_out); + // i have nothing left to do: + // when this measure will end a list of events_out will be set + // from the current values of x->next_main_rhythm_out and x->next_sub_rhythm_out +} + +// add this rhythm to the memory +static void add_rhythm(t_themes_memory *x, t_symbol *s, int argc, t_atom *argv) +{ + // TODO + post("TODO"); +} + +// creates a variation of a given rhythm (in memory) +// with a given degree of closeness +static void variation(t_themes_memory *x, t_symbol *s, int argc, t_atom *argv) +{ + // TODO + post("TODO"); + + // get the rhythm + + // using the transitions table create a new one + + // add it to the memory? + + // output to the list outlet? + + // set it as the next played rhythm +} + +static void themes_memory_bang(t_themes_memory *x) { + + // generate a random value + float rnd; + t_rhythm_event *events; + t_duration dur; + + rnd = rand()/((double)RAND_MAX + 1); + dur = float2duration(rnd); + + post("random value=%f duration.numerator=%i duration.denominator=%i", rnd, dur.numerator, dur.denominator); + + if (x->seq_initialized) + { + concatenateBeat(x->curr_seq, 0, rnd, 1); + } else + { + setFirstBeat(&(x->curr_seq), 0, rnd, 1); + x->seq_initialized = 1; + } + + // print the sequence + events = x->curr_seq; + while(events) + { + post("event: numerator=%i, denominator=%i", events->duration.numerator, events->duration.denominator); + events=events->next; + } + +} + +void *themes_memory_new(t_symbol *s, int argc, t_atom *argv) +{ + int i; + time_t a; + t_themes_memory *x = (t_themes_memory *)pd_new(themes_memory_class); + // first is for bangs (to let this external play in realtime + //x->l_out = outlet_new(&x->x_obj, &s_list); + x->bangs_out = outlet_new(&x->x_obj, gensym("bang")); + // this outputs lists of events + x->list_out = outlet_new(&x->x_obj, "symbol"); + // this outputs info on the last detected rhythm + x->info_out = outlet_new(&x->x_obj, "symbol"); + + // inlet for rhythms in the form of lists + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("list"), gensym("rhythm_in")); + + x->x_clock = clock_new(x, (t_method)rhythms_tick); + x->seq_initialized = 0; + + rhythm_memory_create(&(x->themes_memory)); + start_measure(x); + + return (x); +} + +// debugging function +void crash(t_themes_memory *x) +{ + int *a; + a = malloc(sizeof(int)); + a[9999999999999999999] = 1; +} + +void themes_memory_setup(void) +{ + themes_memory_class = class_new(gensym("themes_memory"), (t_newmethod)themes_memory_new, + (t_method)themes_memory_free, sizeof(t_themes_memory), CLASS_DEFAULT, A_GIMME, 0); + class_addbang(themes_memory_class, (t_method)themes_memory_bang); + class_addmethod(themes_memory_class, (t_method)end_measure, gensym("measure"), 0); + class_doaddfloat(themes_memory_class, (t_method)add_event); + class_addmethod(themes_memory_class, (t_method)crash, gensym("crash"), 0); + // the user asks for a rhythm + class_addmethod(themes_memory_class, (t_method)ask_rhythm, gensym("rhythm_out"), + A_GIMME, 0); + // adds a rhythm passing it as a list of floats + class_addmethod(themes_memory_class, (t_method)add_rhythm, gensym("rhythm_in"), + A_GIMME, 0); + // builds a variation of a given rhythm + class_addmethod(themes_memory_class, (t_method)variation, gensym("variation"), + A_GIMME, 0); +} + + diff --git a/themes_memory.sln b/themes_memory.sln new file mode 100755 index 0000000..4ff3387 --- /dev/null +++ b/themes_memory.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "themes_memory", "themes_memory.vcproj", "{DBC75D2A-816A-4C0A-8FE7-2016518D2D19}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {DBC75D2A-816A-4C0A-8FE7-2016518D2D19}.Debug.ActiveCfg = Debug|Win32 + {DBC75D2A-816A-4C0A-8FE7-2016518D2D19}.Debug.Build.0 = Debug|Win32 + {DBC75D2A-816A-4C0A-8FE7-2016518D2D19}.Release.ActiveCfg = Release|Win32 + {DBC75D2A-816A-4C0A-8FE7-2016518D2D19}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/themes_memory.suo b/themes_memory.suo new file mode 100755 index 0000000..07c81e2 Binary files /dev/null and b/themes_memory.suo differ diff --git a/themes_memory.vcproj b/themes_memory.vcproj new file mode 100755 index 0000000..aaf3309 --- /dev/null +++ b/themes_memory.vcproj @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.1