#include "common.h" #include #include #include "m_pd.h" // to post errors and debug messages t_duration int2duration(int n) { t_duration dur; int curr, i, j, ok, currden; curr=0; ok=0; for (i=0; iprevious = 0; newElement->next = 0; newElement->voice=voice; newElement->duration.numerator = res.numerator; newElement->duration.denominator = res.denominator; res = float2duration(fstart); newElement->start.numerator = res.numerator; newElement->start.denominator = res.denominator; *firstEvent = newElement; } void concatenateBeat(t_rhythm_event *currentEvent, unsigned short int voice, float fstart, float fduration) { t_duration res; t_rhythm_event *newElement, *lastElement; lastElement = currentEvent; while(lastElement->next) lastElement = lastElement->next; // convert from float to duration res = float2duration(fduration); // allocate a new element of the list newElement = (t_rhythm_event *) malloc(sizeof(t_rhythm_event)); // set the pointers newElement->previous = lastElement; newElement->next = 0; lastElement->next = newElement; newElement->voice=voice; newElement->duration.numerator = res.numerator; newElement->duration.denominator = res.denominator; res = float2duration(fstart); newElement->start.numerator = res.numerator; newElement->start.denominator = res.denominator; } void freeBeats(t_rhythm_event *currentEvent) { t_rhythm_event *prev; t_rhythm_event *next; // go to the first element of the list while(currentEvent->previous) currentEvent = currentEvent->previous; // now free each element next=currentEvent->next; do { prev = currentEvent; next = currentEvent->next; free(currentEvent); } while(next); } void add_t_rhythm_memory_arc(t_rhythm_memory_node *srcNode, unsigned short int dstNode) { t_rhythm_memory_arc *newArc; t_rhythm_memory_arc *lastArc; // create a new arc newArc = (t_rhythm_memory_arc *) malloc(sizeof(t_rhythm_memory_arc)); newArc->to_node_index = dstNode; // go to the last arc in the list // and add this arc as the last lastArc = srcNode->arcs; if (lastArc) { // this is not the first arc while(lastArc->next_arc) lastArc = lastArc->next_arc; lastArc->next_arc = newArc; } else { // this is the first arc srcNode->arcs = newArc; } } // initialize this representation, allocates memory for the pointers void create_rhythm_memory_representation(t_rhythm_memory_representation **this_rep, unsigned short int id) { int i; // allocate space for the data structure *this_rep = (t_rhythm_memory_representation *)malloc(sizeof(t_rhythm_memory_representation)); // space for transitions (*this_rep)->transitions = (t_rhythm_memory_node *) malloc(sizeof(t_rhythm_memory_node) * possible_durations()); // initialize transitions for (i=0; itransitions[i].first=0; (*this_rep)->transitions[i].weight=0; (*this_rep)->transitions[i].arcs=0; } (*this_rep)->rhythms = 0; // the naming variables (*this_rep)->id = id; // the main id (*this_rep)->last_sub_id = 0; // the sub id } // add a new rhythm in the list of similar thythms related to one main rhythm unsigned short int add_t_rhythm_memory_element(t_rhythm_memory_representation *this_rep, t_rhythm_event *new_rhythm) { t_rhythm_memory_element *curr; t_rhythm_memory_element *newElement; t_rhythm_event *currEvent; t_rhythm_memory_arc *currArc, *newArc, *prevArc; unsigned short int last, sub_id; int i, arcFound; // creates a new element of the list of similar rhythms newElement = (t_rhythm_memory_element *) malloc(sizeof(t_rhythm_memory_element)); newElement->rhythm = new_rhythm; newElement->next = 0; sub_id = this_rep->last_sub_id; newElement->id = sub_id; this_rep->last_sub_id++; // finds the last element and adds itself curr = this_rep->rhythms; if (curr) { while (curr->next) curr=curr->next; curr->next = newElement; } else { this_rep->rhythms = newElement; } // now update the transition table.. currEvent = new_rhythm; // set the first event.. i = duration2int(new_rhythm->start); this_rep->transitions[i].first++; last = 0; while (currEvent) { // get the duration and translate into an int i = duration2int(currEvent->start); if (last) // NB if last==0 then last is not set { // add an arc between last and i currArc = this_rep->transitions[last].arcs; arcFound=0; // is this arc rpesent? // also i need to get to the last element of the lsit while (currArc) { // for each arc in the list if (currArc->to_node_index == i) { // this arc is already present arcFound=1; } prevArc = currArc; // last valid arc currArc = currArc->next_arc; } if (!arcFound) { // this arc was not present, add it! newArc = (t_rhythm_memory_arc *) malloc(sizeof(t_rhythm_memory_arc)); newArc->next_arc = 0; newArc->to_node_index = i; // set my destination if (this_rep->transitions[last].arcs) { // this is not the first arc // then prevArc is set and valid prevArc->next_arc = newArc; } else { // this is the first arc this_rep->transitions[last].arcs = newArc; } } } // increment the weight this_rep->transitions[i].weight++; if (this_rep->transitions[i].weight > this_rep->max_weight) { // a new champion! this_rep->max_weight = this_rep->transitions[i].weight; } last = i; currEvent = currEvent->next; } return sub_id; } // free the list of representations void free_memory_representations(t_rhythm_memory_representation *this_rep) { int i, maxi; t_rhythm_memory_representation *currRep, *oldRep; t_rhythm_memory_element *currElement, *tmpElement; t_rhythm_memory_arc *currArc, *tmpArc; currRep = this_rep; while(currRep) { // free the table maxi = possible_durations(); for (i=0; itransitions[i].arcs; while (currArc) { tmpArc = currArc; currArc = currArc->next_arc; free(tmpArc); } } free(currRep->transitions); // free the list of similar rhythms currElement = currRep->rhythms; while (currElement) { freeBeats(currElement->rhythm); tmpElement = currElement; currElement = currElement->next; free(tmpElement); } oldRep = currRep; currRep = currRep->next; free(oldRep); } } void create_array_beats(unsigned short int **this_array, t_rhythm_event *currentEvent) { unsigned short int *new_array; t_rhythm_event *curr_event; int i, maxi, startint; maxi = possible_durations(); // allocate space for the nodes new_array = (unsigned short int *) malloc(sizeof(unsigned short int) * maxi); // set default values for (i=0; istart); new_array[startint]=1; curr_event = curr_event->next; } *this_array = new_array; } // compares this rhythm to this representation // and tells you how close it is to it void compare_rhythm_vs_representation(t_rhythm_memory_representation *this_rep, t_rhythm_event *src_rhythm, // the src rhythm unsigned short int *sub_id, // the sub-id of the closest sub-rhythm float *root_closeness, // how much this rhythm is close to the root (1=identical, 0=nothing common) float *sub_closeness // how much this rhythm is close to the closest sub-rhythm (1=identical, 0=nothing common) ) { t_duration tmp_dur, this_dur; t_rhythm_event *curr_event; float this_weight_float, average_weight, strong_ratio; int i, max_i, int_from_dur, this_weight_int, beats, strong_ok, strong_no; unsigned short int *src_rhythm_array, *tmp_rhythm_array; unsigned short int best_subid, curr_subid; float best_closeness, curr_closeness; int sub_ok, sub_no; t_rhythm_memory_element *possible_rhythms; // check that the return values have been allocated if ((sub_id==0)||(root_closeness==0)||(sub_closeness==0)) { post("error in find_similar_rhythm(): return values not allocated"); return; } max_i = possible_durations(); // create an array of bools create_array_beats(&src_rhythm_array, src_rhythm); // look the main table for closeness to the main rhythm curr_event = src_rhythm; beats=0; strong_ok=0; strong_no=0; strong_ratio=0; average_weight = 0; while(curr_event) { int_from_dur = duration2int(curr_event->start); // get the weight of this beat this_weight_int = this_rep->transitions[int_from_dur].weight; this_weight_float = (float) ( ((float) this_weight_int) / ((float) this_rep->max_weight)); average_weight += this_weight_float; beats++; curr_event = curr_event->next; } // look all the representation's rhythm // looking for strong beats corrispondance for (i=0; i min_to_be_main_rhythm_beat) { this_weight_int = this_rep->transitions[i].weight; this_weight_float = (float) (((float) this_weight_int) / ((float) this_rep->max_weight)); // this is a main rhythm beat if (src_rhythm_array[i]>0) { // both playing strong_ok++; } else { // strong beat miss strong_no++; } } } // this is the average weight of this rhythm in this representation if (beats==0) { average_weight = 0; } else { average_weight = (float) (average_weight / ((float) beats)); } // ratio of corresponding strong beats.. // close to 0 = no corrispondance // close to 1 = corrispondance if (strong_no==0) { strong_ratio = 1; } else { strong_ratio = (float) ( ((float) strong_ok) / ((float)strong_no) ); } // for each rhythm in the list // count the number of identical nodes // cound thenumber of different nodes best_subid = curr_subid = INVALID_RHYTHM; best_closeness = curr_closeness = 0; possible_rhythms = this_rep->rhythms; while(possible_rhythms) { // create the table of this rhythm create_array_beats(&tmp_rhythm_array, possible_rhythms->rhythm); sub_ok = sub_no = 0; for (i=0; i0 && src_rhythm_array[i]>0) { sub_ok++; } else if (tmp_rhythm_array[i]==0 && src_rhythm_array[i]==0) { // nothing important } else { sub_no++; } } if (sub_no == 0) { curr_closeness = 1; } else { curr_closeness = (float) ( ((float) sub_ok) / ((float) sub_no) ); } if (curr_closeness > best_closeness) { best_closeness = curr_closeness; best_subid = possible_rhythms->id; } possible_rhythms = possible_rhythms->next; free(tmp_rhythm_array); } // return the better matching rhythm id // and the closeness floats *sub_id = best_subid; *sub_closeness = best_closeness; *root_closeness = strong_ratio; // free allocated memory free(src_rhythm_array); } void find_rhythm_in_memory(t_rhythm_memory_representation *rep_list, t_rhythm_event *src_rhythm, // the src rhythm unsigned short int *id, // the id of the closest rhythm unsigned short int *sub_id, // the sub-id of the closest sub-rhythm float *root_closeness, // how much this rhythm is close to the root (1=identical, 0=nothing common) float *sub_closeness // how much this rhythm is close to the closest sub-rhythm (1=identical, 0=nothing common) ) { unsigned short int best_id, curr_id, best_subid, curr_subid; float best_closeness, curr_closeness, best_sub_closeness, curr_sub_closeness; t_rhythm_memory_representation *this_rep; best_closeness = curr_closeness = best_sub_closeness = curr_sub_closeness = 0; best_id = curr_id = best_subid = curr_subid = INVALID_RHYTHM; // for each element of the rep_list this_rep = rep_list; while(this_rep) { compare_rhythm_vs_representation(this_rep, src_rhythm, &curr_subid, &curr_closeness, &curr_sub_closeness); if (curr_closeness > best_closeness) { best_closeness = curr_closeness; best_id = this_rep->id; best_sub_closeness = curr_sub_closeness; best_subid = curr_subid; } } *id = best_id; *sub_id = best_subid; *root_closeness = best_closeness; *sub_closeness = best_sub_closeness; } // ------------------- themes manipulation functions // set the first note of a sequence void setFirstNote(t_note_event **firstEvent, unsigned short int voice, float fstart, float fduration, t_note note) { t_duration res; t_note_event *newElement; // convert from float to duration res = float2duration(fduration); // allocate a new element of the list newElement = malloc(sizeof(t_note_event)); // set the pointers newElement->previous = 0; newElement->next = 0; newElement->voice=voice; newElement->note.chord = note.chord; newElement->note.diatonic = note.diatonic; newElement->note.interval = note.interval; newElement->duration.numerator = res.numerator; newElement->duration.denominator = res.denominator; res = float2duration(fstart); newElement->start.numerator = res.numerator; newElement->start.denominator = res.denominator; *firstEvent = newElement; } //adds a note at the end of this list void concatenateNote(t_note_event *currentEvent, unsigned short int voice, float fstart, float fduration, t_note note) { t_duration res; t_note_event *newElement, *lastElement; lastElement = currentEvent; while(lastElement->next) lastElement = lastElement->next; // convert from float to duration res = float2duration(fduration); // allocate a new element of the list newElement = (t_note_event *) malloc(sizeof(t_note_event)); // set the pointers newElement->previous = lastElement; newElement->next = 0; lastElement->next = newElement; newElement->voice=voice; newElement->note.chord = note.chord; newElement->note.diatonic = note.diatonic; newElement->note.interval = note.interval; newElement->duration.numerator = res.numerator; newElement->duration.denominator = res.denominator; res = float2duration(fstart); newElement->start.numerator = res.numerator; newElement->start.denominator = res.denominator; } // used to free the memory allocated by this list void freeNotes(t_note_event *currentEvent) { t_note_event *prev; t_note_event *next; // go to the first element of the list while(currentEvent->previous) currentEvent = currentEvent->previous; // now free each element next=currentEvent->next; do { prev = currentEvent; next = currentEvent->next; free(currentEvent); } while(next); }