/frontends/CsoundAC/allegro.cpp
C++ | 3516 lines | 2491 code | 387 blank | 638 comment | 558 complexity | f781d11ec5458eac6955eee0a82cddf9 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, BSD-3-Clause, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- // Allegro: music representation system, with
- // extensible in-memory sequence structure
- // upward compatible with MIDI
- // implementations in C++ and Serpent
- // external, text-based representation
- // compatible with Aura
- //
- /* CHANGE LOG:
- 04 apr 03 -- fixed bug in add_track that caused infinite loop
- */
- #include "assert.h"
- #include "stdlib.h"
- #include "stdio.h"
- #include "string.h"
- #include "memory.h"
- #include <iostream>
- #include <fstream>
- using namespace std;
- #include "allegro.h"
- #include "algrd_internal.h"
- #include "algsmfrd_internal.h"
- // #include "trace.h" -- only needed for debugging
- #include "math.h"
- #define STREQL(x, y) (strcmp(x, y) == 0)
- #define MAX(x, y) ((x) > (y) ? (x) : (y))
- #define ROUND(x) ((int) ((x) + 0.5))
- // 4311 is type cast ponter to long warning
- // 4996 is warning against strcpy
- // 4267 is size_t to long warning
- #pragma warning(disable: 4311 4996 4267)
- Alg_atoms symbol_table;
- Serial_read_buffer Alg_track::ser_read_buf; // declare the static variables
- Serial_write_buffer Alg_track::ser_write_buf;
- bool within(double d1, double d2, double epsilon)
- {
- d1 -= d2;
- return d1 < epsilon && d1 > -epsilon;
- }
- char *heapify(const char *s)
- {
- char *h = new char[strlen(s) + 1];
- strcpy(h, s);
- return h;
- }
- void Alg_atoms::expand()
- {
- maxlen = (maxlen + 5); // extra growth for small sizes
- maxlen += (maxlen >> 2); // add 25%
- Alg_attribute *new_atoms = new Alg_attribute[maxlen];
- // now do copy
- memcpy(new_atoms, atoms, len * sizeof(Alg_attribute));
- if (atoms) delete[] atoms;
- atoms = new_atoms;
- }
- // insert_new -- insert an attribute name and type
- //
- // attributes are stored as a string consisting of the type
- // (a char) followed by the attribute name. This makes it
- // easy to retrieve the type or the name or both.
- //
- Alg_attribute Alg_atoms::insert_new(const char *name, char attr_type)
- {
- if (len == maxlen) expand();
- char *h = new char[strlen(name) + 2];
- strcpy(h + 1, name);
- *h = attr_type;
- atoms[len++] = h;
- return h;
- }
- Alg_attribute Alg_atoms::insert_attribute(Alg_attribute attr)
- {
- // should use hash algorithm
- for (int i = 0; i < len; i++) {
- if (STREQL(attr, atoms[i])) {
- return atoms[i];
- }
- }
- return insert_new(attr + 1, attr[0]);
- }
- Alg_attribute Alg_atoms::insert_string(const char *name)
- {
- char attr_type = name[strlen(name) - 1];
- for (int i = 0; i < len; i++) {
- if (attr_type == atoms[i][0] &&
- STREQL(name, atoms[i] + 1)) {
- return atoms[i];
- }
- }
- return insert_new(name, attr_type);
- }
- void Alg_parameter::copy(Alg_parameter_ptr parm)
- {
- *this = *parm; // copy all fields
- // if the value is a string, copy the string
- if (attr_type() == 's') {
- s = heapify(s);
- }
- }
- void Alg_parameter::show()
- {
- switch (attr[0]) {
- case 'r':
- printf("%s:%g", attr_name(), r);
- break;
- case 's':
- printf("%s:%s", attr_name(), s);
- break;
- case 'i':
- printf("%s:%ld", attr_name(), i);
- break;
- case 'l':
- printf("%s:%s", attr_name(), (l ? "t" : "f"));
- break;
- case 'a':
- printf("%s:%s", attr_name(), a);
- break;
- }
- }
- Alg_parameter::~Alg_parameter()
- {
- if (attr_type() == 's' && s) {
- delete[] s;
- }
- }
- void Alg_parameters::insert_real(Alg_parameters **list, const char *name,
- double r)
- {
- Alg_parameters_ptr a = new Alg_parameters(*list);
- *list = a;
- a->parm.set_attr(symbol_table.insert_string(name));
- a->parm.r = r;
- assert(a->parm.attr_type() == 'r');
- }
- void Alg_parameters::insert_string(Alg_parameters **list, const char *name,
- const char *s)
- {
- Alg_parameters_ptr a = new Alg_parameters(*list);
- *list = a;
- a->parm.set_attr(symbol_table.insert_string(name));
- // string is deleted when parameter is deleted
- a->parm.s = heapify(s);
- assert(a->parm.attr_type() == 's');
- }
- void Alg_parameters::insert_integer(Alg_parameters **list, const char *name,
- long i)
- {
- Alg_parameters_ptr a = new Alg_parameters(*list);
- *list = a;
- a->parm.set_attr(symbol_table.insert_string(name));
- a->parm.i = i;
- assert(a->parm.attr_type() == 'i');
- }
- void Alg_parameters::insert_logical(Alg_parameters **list, const char *name,
- bool l)
- {
- Alg_parameters_ptr a = new Alg_parameters(*list);
- *list = a;
- a->parm.set_attr(symbol_table.insert_string(name));
- a->parm.l = l;
- assert(a->parm.attr_type() == 'l');
- }
- void Alg_parameters::insert_atom(Alg_parameters **list, const char *name,
- const char *s)
- {
- Alg_parameters_ptr a = new Alg_parameters(*list);
- *list = a;
- a->parm.set_attr(symbol_table.insert_string(name));
- a->parm.a = symbol_table.insert_string(s);
- assert(a->parm.attr_type() == 'a');
- }
- Alg_parameters *Alg_parameters::remove_key(Alg_parameters **list,
- const char *name)
- {
- while (*list) {
- if (STREQL((*list)->parm.attr_name(), name)) {
- Alg_parameters_ptr p = *list;
- *list = p->next;
- p->next = NULL;
- return p; // caller should free this pointer
- }
- list = &((*list)->next);
- }
- return NULL;
- }
- Alg_parameter_ptr Alg_parameters::find(Alg_attribute attr)
- {
- assert(attr);
- Alg_parameters_ptr temp = this;
- while (temp) {
- if (temp->parm.attr == attr) {
- return &(temp->parm);
- }
- }
- return NULL;
- }
- int Alg_event::get_type_code()
- {
- if (!is_note()) {
- const char* attr = get_attribute();
- if (STREQL(attr, "gater")) // volume change
- return ALG_GATE;
- if (STREQL(attr, "bendr")) // pitch bend
- return ALG_BEND;
- if (strncmp(attr, "control", 7) == 0) // control change
- // note that midi control changes have attributes of the form
- // "control<n>" where n is the decimal number (as a character string)
- // of the midi controller, e.g. control2 is the breath controller.
- // We don't check for decimal numbers in the range 0-127, so any
- // attribute that begins with "control" is an ALG_CONTROL:
- return ALG_CONTROL;
- if (STREQL(attr, "programi")) // program change
- return ALG_PROGRAM;
- if (STREQL(attr, "pressurer")) // pressure change
- return ALG_PRESSURE;
- if (STREQL(attr, "keysigi")) // key signature
- return ALG_KEYSIG;
- if (STREQL(attr, "timesig_numi")) // time signature numerator
- return ALG_TIMESIG_NUM;
- if (STREQL(attr, "timesig_deni")) // time signature denominator
- return ALG_TIMESIG_DEN;
- return ALG_OTHER;
- }
- return ALG_NOTE; // it is a note
- }
- void Alg_event::set_parameter(Alg_parameter_ptr new_parameter)
- {
- Alg_parameter_ptr parm;
- if (is_note()) {
- Alg_note_ptr note = (Alg_note_ptr) this;
- parm = note->parameters->find(new_parameter->attr);
- if (!parm) {
- note->parameters = new Alg_parameters(note->parameters);
- parm = &(note->parameters->parm);
- }
- } else { // update
- Alg_update_ptr update = (Alg_update_ptr) this;
- parm = &(update->parameter);
- }
- parm->copy(new_parameter); // copy entire parameter
- }
- void Alg_event::set_string_value(const char *a, const char *value)
- {
- assert(a); // must be non-null
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(attr[0] == 's');
- Alg_parameter parm;
- parm.set_attr(attr);
- parm.s = value;
- set_parameter(&parm);
- parm.s = NULL; // do this to prevent string from being freed
- }
- void Alg_event::set_real_value(const char *a, double value)
- {
- assert(a); // must be non-null
- // attr is like a, but it has the type code prefixed for
- // fast lookup, and it is a unique string in symbol_table
- // e.g. a="attackr" -> attr="rattackr"
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(attr[0] == 'r');
- Alg_parameter parm;
- parm.set_attr(attr);
- parm.r = value;
- set_parameter(&parm);
- // since type is 'r' we don't have to NULL the string
- }
- void Alg_event::set_logical_value(const char *a, bool value)
- {
- assert(a); // must be non-null
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(attr[0] == 'l');
- Alg_parameter parm;
- parm.set_attr(attr);
- parm.l = value;
- set_parameter(&parm);
- // since type is 'l' we don't have to NULL the string
- }
- void Alg_event::set_integer_value(const char *a, long value)
- {
- assert(a); // must be non-null
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(attr[0] == 'i');
- Alg_parameter parm;
- parm.set_attr(attr);
- parm.i = value;
- set_parameter(&parm);
- // since tpye is 'i' we don't have to NULL the string
- }
- void Alg_event::set_atom_value(const char *a, const char *value)
- {
- assert(a); // must be non-null
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(attr[0] == 'a');
- Alg_parameter parm;
- parm.set_attr(attr);
- parm.a = value;
- set_parameter(&parm);
- /* since type is 'a' we don't have to null the string */
- }
- float Alg_event::get_pitch()
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- return note->pitch;
- }
- float Alg_event::get_loud()
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- return note->loud;
- }
- double Alg_event::get_start_time()
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- return note->time;
- }
- double Alg_event::get_end_time()
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- return note->time + note->dur;
- }
- double Alg_event::get_duration()
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- return note->dur;
- }
- void Alg_event::set_pitch(float p)
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- note->pitch = p;
- }
- void Alg_event::set_loud(float l)
- {
- assert(is_note());
- Alg_note *note = (Alg_note *) this;
- note->loud = l;
- }
- void Alg_event::set_duration(double d)
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- note->dur = d;
- }
- bool Alg_event::has_attribute(const char *a)
- {
- assert(is_note());
- assert(a); // must be non-null
- Alg_note* note = (Alg_note *) this;
- Alg_attribute attr = symbol_table.insert_string(a);
- Alg_parameter_ptr parm = note->parameters->find(attr);
- return parm != NULL;
- }
- char Alg_event::get_attribute_type(const char *a)
- {
- assert(is_note());
- assert(a);
- return a[strlen(a) - 1];
- }
- const char *Alg_event::get_string_value(const char *a, const char *value)
- {
- assert(is_note());
- assert(a); // must be non-null
- Alg_note* note = (Alg_note *) this;
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(a[0] == 's'); // must be of type string
- Alg_parameter_ptr parm = note->parameters->find(attr);
- if (parm) return parm->s;
- return value;
- }
- double Alg_event::get_real_value(const char *a, double value)
- {
- assert(is_note());
- assert(a);
- Alg_note* note = (Alg_note *) this;
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(a[0] == 'r'); // must be of type real
- Alg_parameter_ptr parm = note->parameters->find(attr);
- if (parm) return parm->r;
- return value;
- }
- bool Alg_event::get_logical_value(const char *a, bool value)
- {
- assert(is_note());
- assert(a);
- Alg_note* note = (Alg_note *) this;
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(a[0] == 'l'); // must be of type logical
- Alg_parameter_ptr parm = note->parameters->find(attr);
- if (parm) return parm->l;
- return value;
- }
- long Alg_event::get_integer_value(const char *a, long value)
- {
- assert(is_note());
- assert(a);
- Alg_note* note = (Alg_note *) this;
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(a[0] == 'i'); // must be of type integer
- Alg_parameter_ptr parm = note->parameters->find(attr);
- if (parm) return parm->i;
- return value;
- }
- const char *Alg_event::get_atom_value(const char *a, const char *value)
- {
- assert(is_note());
- assert(a);
- Alg_note* note = (Alg_note *) this;
- Alg_attribute attr = symbol_table.insert_string(a);
- assert(a[0] == 'a'); // must be of type atom
- Alg_parameter_ptr parm = note->parameters->find(attr);
- if (parm) return parm->a;
- // if default is a string, convert to an atom (unique
- // string in symbol table) and return it
- return (value == NULL ? NULL :
- symbol_table.insert_string(value));
- }
- void Alg_event::delete_attribute(const char *a)
- {
- assert(is_note());
- Alg_note* note = (Alg_note *) this;
- Alg_parameters::remove_key(&(note->parameters), a);
- }
- const char *Alg_event::get_attribute()
- // Note: this returns a string, not an Alg_attribute
- {
- assert(is_update());
- Alg_update* update = (Alg_update *) this;
- return update->parameter.attr_name();
- }
- char Alg_event::get_update_type()
- {
- assert(is_update());
- Alg_update* update = (Alg_update *) this;
- return update->parameter.attr_type();
- }
- const char *Alg_event::get_string_value()
- {
- assert(is_update());
- Alg_update* update = (Alg_update *) this;
- assert(get_update_type() == 's');
- return update->parameter.s;
- }
- double Alg_event::get_real_value()
- {
- assert(is_update());
- Alg_update* update = (Alg_update *) this;
- assert(get_update_type() == 'r');
- return update->parameter.r;
- }
- bool Alg_event::get_logical_value()
- {
- assert(is_update());
- Alg_update* update = (Alg_update *) this;
- assert(get_update_type() == 'l');
- return update->parameter.l;
- }
- long Alg_event::get_integer_value()
- {
- assert(is_update());
- Alg_update* update = (Alg_update *) this;
- assert(get_update_type() == 'i');
- return update->parameter.i;
- }
- const char *Alg_event::get_atom_value()
- {
- assert(is_update());
- Alg_update* update = (Alg_update *) this;
- assert(get_update_type() == 'a');
- return update->parameter.a;
- }
- bool Alg_event::overlap(double t, double len, bool all)
- {
- // event starts within region
- if (time >= t && time <= t + len - ALG_EPS)
- return true;
- if (all && is_note()) {
- double dur = ((Alg_note_ptr) this)->dur;
- // note overlaps with region
- if (time < t && time + dur - ALG_EPS > t)
- return true;
- }
- // does not overlap
- return false;
- }
- Alg_note::Alg_note(Alg_note_ptr note)
- {
- *this = *note; // copy all fields
- // parameters is now a shared pointer. We need to copy the
- // parameters
- Alg_parameters_ptr next_param_ptr = parameters;
- while (next_param_ptr) {
- Alg_parameters_ptr new_params = new Alg_parameters(next_param_ptr->next);
- new_params->parm.copy(&(next_param_ptr->parm)); // copy the attribute and value
- next_param_ptr = new_params->next;
- }
- }
- Alg_note::~Alg_note()
- {
- while (parameters) {
- Alg_parameters_ptr to_delete = parameters;
- parameters = parameters->next;
- delete to_delete;
- }
- }
- void Alg_note::show()
- {
- printf("Alg_note: time %g, chan %ld, dur %g, key %ld, "
- "pitch %g, loud %g, attributes ",
- time, chan, dur, key, pitch, loud);
- Alg_parameters_ptr parms = parameters;
- while (parms) {
- parms->parm.show();
- printf(" ");
- parms = parms->next;
- }
- printf("\n");
- }
- Alg_update::Alg_update(Alg_update_ptr update)
- {
- *this = *update; // copy all fields
- // parameter requires careful copy to possibly duplicate string value:
- this->parameter.copy(&(update->parameter));
- }
- void Alg_update::show()
- {
- printf("Alg_update: ");
- parameter.show();
- printf("\n");
- }
- void Alg_events::expand()
- {
- maxlen = (maxlen + 5); // extra growth for small sizes
- maxlen += (maxlen >> 2); // add 25%
- Alg_event_ptr *new_events = new Alg_event_ptr[maxlen];
- // now do copy
- memcpy(new_events, events, len * sizeof(Alg_event_ptr));
- if (events) delete[] events;
- events = new_events;
- }
- void Alg_events::insert(Alg_event_ptr event)
- {
- if (maxlen <= len) {
- expand();
- }
- // Note: if the new event is the last one, the assignment
- // events[i] = event; (below) will never execute, so just
- // in case, we do the assignment here. events[len] will
- // be replaced during the memmove() operation below if
- // this is not the last event.
- events[len] = event;
- len++;
- // find insertion point: (this could be a binary search)
- for (int i = 0; i < len; i++) {
- if (events[i]->time > event->time) {
- // insert event at i
- memmove(&events[i + 1], &events[i],
- sizeof(Alg_event_ptr) * (len - i - 1));
- events[i] = event;
- return;
- }
- }
- }
- Alg_event_ptr Alg_events::uninsert(long index)
- {
- assert(0 <= index && index < len);
- Alg_event_ptr event = events[index];
- //printf("memmove: %x from %x (%d)\n", events + index, events + index + 1,
- // sizeof(Alg_event_ptr) * (len - index - 1));
- memmove(events + index, events + index + 1,
- sizeof(Alg_event_ptr) * (len - index - 1));
- len--;
- return event;
- }
- void Alg_events::append(Alg_event_ptr event)
- {
- if (maxlen <= len) {
- expand();
- }
- events[len++] = event;
- // keep track of last note_off time
- if (event->is_note()) {
- Alg_note_ptr note = (Alg_note_ptr) event;
- double note_off = note->time + note->dur;
- if (note_off > last_note_off)
- last_note_off = note_off;
- }
- }
- Alg_events::~Alg_events()
- {
- assert(!in_use);
- // individual events are not deleted, only the array
- if (events) {
- delete[] events;
- }
- }
- Alg_event_list::Alg_event_list(Alg_track *owner)
- {
- events_owner = owner;
- sequence_number = owner->sequence_number;
- beat_dur = 0.0; real_dur = 0.0; type = 'e';
- }
- Alg_event_ptr &Alg_event_list::operator [](int i)
- {
- assert(i >= 0 && i < len);
- return events[i];
- }
- Alg_event_list::~Alg_event_list()
- {
- // note that the events contained in the list are not destroyed
- }
- void Alg_event_list::set_start_time(Alg_event *event, double t)
- {
- // For Alg_event_list, find the owner and do the update there
- // For Alg_track, change the time and move the event to the right place
- // For Alg_seq, find the track and do the update there
- long index, i;
- Alg_track_ptr track_ptr;
- if (type == 'e') { // this is an Alg_event_list
- // make sure the owner has not changed its event set
- assert(events_owner &&
- sequence_number == events_owner->sequence_number);
- // do the update on the owner
- events_owner->set_start_time(event, t);
- return;
- } else if (type == 't') { // this is an Alg_track
- // find the event in the track
- track_ptr = (Alg_track_ptr) this;
- // this should be a binary search since events are in time order
- // probably there should be member function to do the search
- for (index = 0; index < length(); index++) {
- if ((*track_ptr)[index] == event) goto found_event;
- }
- } else { // type == 's', an Alg_seq
- Alg_seq_ptr seq = (Alg_seq_ptr) this;
- for (i = 0; i < seq->tracks(); i++) {
- track_ptr = seq->track(i);
- // if you implemented binary search, you could call it
- // instead of this loop too.
- for (index = 0; index < track_ptr->length(); index++) {
- if ((*track_ptr)[index] == event) goto found_event;
- }
- }
- }
- assert(false); // event not found seq or track!
- found_event:
- // at this point, track[index] == event
- // we could be clever and figure out exactly what notes to move
- // but it is simpler to just remove the event and reinsert it:
- track_ptr->uninsert(index);
- event->time = t;
- track_ptr->insert(event);
- }
- void Alg_beats::expand()
- {
- maxlen = (maxlen + 5); // extra growth for small sizes
- maxlen += (maxlen >> 2); // add 25%
- Alg_beat_ptr new_beats = new Alg_beat[maxlen];
- // now do copy
- memcpy(new_beats, beats, len * sizeof(Alg_beat));
- if (beats) delete[] beats;
- beats = new_beats;
- }
- void Alg_beats::insert(long i, Alg_beat_ptr beat)
- {
- assert(i >= 0 && i <= len);
- if (maxlen <= len) {
- expand();
- }
- memmove(&beats[i + 1], &beats[i], sizeof(Alg_beat) * (len - i));
- memcpy(&beats[i], beat, sizeof(Alg_beat));
- len++;
- }
- Alg_time_map::Alg_time_map(Alg_time_map *map)
- {
- refcount = 0;
- assert(map->beats[0].beat == 0 && map->beats[0].time == 0);
- assert(map->beats.len > 0);
- // new_beats[0] = map->beats[0];
- // this is commented because
- // both new_beats[0] and map->beats[0] should be (0, 0)
- for (int i = 1; i < map->beats.len; i++) {
- beats.insert(i, &map->beats[i]);
- }
- last_tempo = map->last_tempo;
- last_tempo_flag = map->last_tempo_flag;
- }
- void Alg_time_map::show()
- {
- printf("Alg_time_map: ");
- for (int i = 0; i < beats.len; i++) {
- Alg_beat &b = beats[i];
- printf("(%g, %g) ", b.time, b.beat);
- }
- printf("last tempo: %g\n", last_tempo);
- }
- long Alg_time_map::locate_time(double time)
- {
- int i = 0;
- while ((i < beats.len) && (time > beats[i].time)) {
- i++;
- }
- return i;
- }
- long Alg_time_map::locate_beat(double beat)
- {
- int i = 0;
- while ((i < beats.len) && (beat > beats[i].beat)) {
- i++;
- }
- return i;
- }
- double Alg_time_map::beat_to_time(double beat)
- {
- Alg_beat_ptr mbi;
- Alg_beat_ptr mbi1;
- if (beat <= 0) {
- return beat;
- }
- int i = locate_beat(beat);
- // case 1: beat is between two time/beat pairs
- if (0 < i && i < beats.len) {
- mbi = &beats[i - 1];
- mbi1 = &beats[i];
- // case 2: beat is beyond last time/beat pair
- } else if (i == beats.len) {
- if (last_tempo_flag) {
- return beats[i - 1].time +
- (beat - beats[i - 1].beat) / last_tempo;
- } else if (i == 1) {
- return beat * 60.0 / ALG_DEFAULT_BPM;
- // so we use that as default allegro tempo too
- } else {
- mbi = &beats[i - 2];
- mbi1 = &beats[i - 1];
- }
- // case 3: beat is at time 0
- } else /* if (i == 0) */ {
- return beats[0].time;
- }
- // whether we extrapolate or interpolate, the math is the same
- double time_dif = mbi1->time - mbi->time;
- double beat_dif = mbi1->beat - mbi->beat;
- return mbi->time + (beat - mbi->beat) * time_dif / beat_dif;
- }
- double Alg_time_map::time_to_beat(double time)
- {
- Alg_beat_ptr mbi;
- Alg_beat_ptr mbi1;
- if (time <= 0.0) return time;
- int i = locate_time(time);
- if (i == beats.len) {
- if (last_tempo_flag) {
- return beats[i - 1].beat +
- (time - beats[i - 1].time) * last_tempo;
- } else if (i == 1) {
- return time * (ALG_DEFAULT_BPM / 60.0);
- } else {
- mbi = &beats[i - 2];
- mbi1 = &beats[i - 1];
- }
- } else {
- mbi = &beats[i - 1];
- mbi1 = & beats[i];
- }
- double time_dif = mbi1->time - mbi->time;
- double beat_dif = mbi1->beat - mbi->beat;
- return mbi->beat + (time - mbi->time) * beat_dif / time_dif;
- }
- void Alg_time_map::insert_beat(double time, double beat)
- {
- int i = locate_time(time); // i is insertion point
- if (i < beats.len && within(beats[i].time, time, 0.000001)) {
- // replace beat if time is already in the map
- beats[i].beat = beat;
- } else {
- Alg_beat point;
- point.beat = beat;
- point.time = time;
- beats.insert(i, &point);
- }
- // beats[i] contains new beat
- // make sure we didn't generate a zero tempo.
- // if so, space beats by one microbeat as necessary
- long j = i;
- if (j == 0) j = 1; // do not adjust beats[0]
- while (j < beats.len &&
- beats[j - 1].beat + 0.000001 >= beats[j].beat) {
- beats[j].beat = beats[j - 1].beat + 0.000001;
- j++;
- }
- }
- bool Alg_time_map::insert_tempo(double tempo, double beat)
- {
- tempo = tempo / 60.0; // convert to beats per second
- // change the tempo at the given beat until the next beat event
- if (beat < 0) return false;
- double time = beat_to_time(beat);
- long i = locate_time(time);
- if (i >= beats.len || !within(beats[i].time, time, 0.000001)) {
- insert_beat(time, beat);
- }
- // now i is index of beat where tempo will change
- if (i == beats.len - 1) {
- last_tempo = tempo;
- // printf("last_tempo to %g\n", last_tempo);
- last_tempo_flag = true;
- } else { // adjust all future beats
- // compute the difference in beats
- double diff = beats[i + 1].beat - beats[i].beat;
- // convert beat difference to seconds at new tempo
- diff = diff / tempo;
- // figure out old time difference:
- double old_diff = beats[i + 1].time - time;
- // compute difference too
- diff = diff - old_diff;
- // apply new_diff to score and beats
- i++;
- while (i < beats.len) {
- beats[i].time = beats[i].time + diff;
- i++;
- }
- }
- return true;
- }
- double Alg_time_map::get_tempo(double beat)
- {
- Alg_beat_ptr mbi;
- Alg_beat_ptr mbi1;
- // if beat < 0, there is probably an error; return something nice anyway
- if (beat < 0) return ALG_DEFAULT_BPM / 60.0;
- long i = locate_beat(beat);
- // this code is similar to beat_to_time() so far, but we want to get
- // beyond beat if possible because we want the tempo FOLLOWING beat
- // (Consider the case beat == 0.0)
- if (i < beats.len && beat >= beats[i].beat) i++;
- // case 1: beat is between two time/beat pairs
- if (i < beats.len) {
- mbi = &beats[i - 1];
- mbi1 = &beats[i];
- // case 2: beat is beyond last time/beat pair
- } else /* if (i == beats.len) */ {
- if (last_tempo_flag) {
- return last_tempo;
- } else if (i == 1) {
- return ALG_DEFAULT_BPM / 60.0;
- } else {
- mbi = &beats[i - 2];
- mbi1 = &beats[i - 1];
- }
- }
- double time_dif = mbi1->time - mbi->time;
- double beat_dif = mbi1->beat - mbi->beat;
- return beat_dif / time_dif;
- }
- bool Alg_time_map::set_tempo(double tempo, double start_beat, double end_beat)
- {
- if (start_beat >= end_beat) return false;
- // algorithm: insert a beat event if necessary at start_beat
- // and at end_beat
- // delete intervening map elements
- // change the tempo
- insert_beat(beat_to_time(start_beat), start_beat);
- insert_beat(beat_to_time(end_beat), end_beat);
- long start_x = locate_beat(start_beat) + 1;
- long stop_x = locate_beat(end_beat);
- while (stop_x < beats.len) {
- beats[start_x] = beats[stop_x];
- start_x++;
- stop_x++;
- }
- beats.len = start_x; // truncate the map to new length
- return insert_tempo(tempo, start_beat);
- }
- bool Alg_time_map::stretch_region(double b0, double b1, double dur)
- {
- // find current duration
- double t0 = beat_to_time(b0);
- double t1 = beat_to_time(b1);
- double old_dur = t1 - t0;
- if (old_dur <= 0 || dur <= 0) return false;
- double scale = dur / old_dur; // larger scale => slower
- // insert a beat if necessary at b0 and b1
- insert_beat(t0, b0);
- insert_beat(t1, b1);
- long start_x = locate_beat(b0);
- long stop_x = locate_beat(b1);
- double orig_time = beats[start_x].time;
- double prev_time = orig_time;
- for (int i = start_x + 1; i < beats.len; i++) {
- double delta = beats[i].time - orig_time;
- if (i <= stop_x) { // change tempo to next Alg_beat
- delta *= scale;
- }
- orig_time = beats[i].time;
- prev_time += delta;
- beats[i].time = prev_time;
- }
- return true;
- }
- void Alg_time_map::trim(double start, double end, bool units_are_seconds)
- {
- // extract the time map from start to end and shift to time zero
- // start and end are time in seconds if units_are_seconds is true
- int i = 0; // index into beats
- int start_index; // index of first breakpoint after start
- int count = 1;
- double initial_beat = start;
- double final_beat = end;
- if (units_are_seconds) {
- initial_beat = time_to_beat(start);
- final_beat = time_to_beat(end);
- } else {
- start = beat_to_time(initial_beat);
- end = beat_to_time(final_beat);
- }
- while (i < length() && beats[i].time < start) i++;
- // now i is index into beats of the first breakpoint after start
- // beats[0] is (0,0) and remains that way
- // copy beats[start_index] to beats[1], etc.
- // skip any beats at or near (start,initial_beat), using count
- // to keep track of how many entries there are
- start_index = i;
- while (i < length() && beats[i].time < end) {
- if (beats[i].time - start > ALG_EPS &&
- beats[i].beat - initial_beat > ALG_EPS) {
- beats[i].time = beats[i].time - start;
- beats[i].beat = beats[i].beat - initial_beat;
- beats[i - start_index + 1] = beats[i];
- count = count + 1;
- } else {
- start_index = start_index + 1;
- }
- i = i + 1;
- }
- // set last tempo data
- // we last examined beats[i-1] and copied it to
- // beats[i - start_index]. Next tempo should come
- // from beats[i] and store in beats[i - start_index + 1]
- // case 1: there is at least one breakpoint beyond end
- // => interpolate to put a breakpoint at end
- // case 2: no more breakpoints => set last tempo data
- if (i < length()) {
- // we know beats[i].time >= end, so case 1 applies
- beats[i - start_index + 1].time = end - start;
- beats[i - start_index + 1].beat = final_beat - initial_beat;
- count = count + 1;
- }
- // else we'll just use stored last tempo (if any)
- beats.len = count;
- }
- void Alg_time_map::cut(double start, double len, bool units_are_seconds)
- {
- // remove portion of time map from start to start + len,
- // shifting the tail left by len. start and len are in whatever
- // units the score is in. If you cut the time_map as well as cut
- // the tracks of the sequence, then sequences will preserve the
- // association between tempo changes and events
- double end = start + len;
- double initial_beat = start;
- double final_beat = end;
- int i = 0;
- if (units_are_seconds) {
- initial_beat = time_to_beat(start);
- final_beat = time_to_beat(end);
- } else {
- start = beat_to_time(initial_beat);
- end = beat_to_time(final_beat);
- len = end - start;
- }
- double beat_len = final_beat - initial_beat;
- while (i < length() && beats[i].time < start - ALG_EPS) {
- i = i + 1;
- }
- // if no beats exist at or after start, just return; nothing to cut
- if (i == length()) return;
- // now i is index into beats of the first breakpoint on or
- // after start, insert (start, initial_beat) in map
- if (i < length() && within(beats[i].time, start, ALG_EPS)) {
- // perterb time map slightly (within alg_eps) to place
- // break point exactly at the start time
- beats[i].time = start;
- beats[i].beat = initial_beat;
- } else {
- Alg_beat point(start, initial_beat);
- beats.insert(i, &point);
- }
- // now, we're correct up to beats[i] and beats[i] happens at start.
- // find first beat after end so we can start shifting from there
- i = i + 1;
- int start_index = i;
- while (i < length() && beats[i].time < end + ALG_EPS) i++;
- // now beats[i] is the next point to be included in beats
- // but from i onward, we must shift by (-len, -beat_len)
- while (i < length()) {
- Alg_beat &b = beats[i];
- b.time = b.time - len;
- b.beat = b.beat - beat_len;
- beats[start_index] = b;
- i = i + 1;
- start_index = start_index + 1;
- }
- beats.len = start_index;
- }
- void Alg_time_map::paste(double beat, Alg_track *tr)
- {
- // insert a given time map at a given time and dur (in beats)
- Alg_time_map_ptr from_map = tr->get_time_map();
- // printf("time map paste\nfrom map\n");
- // from_map->show();
- // printf("to map\n");
- // show();
- Alg_beats &from = from_map->beats;
- double time = beat_to_time(beat);
- // Locate the point at which dur occurs
- double dur = tr->get_beat_dur();
- double tr_end_time = from_map->beat_to_time(dur);
- // add offset to make room for insert
- int i = locate_beat(beat);
- while (i < length()) {
- beats[i].beat += dur;
- beats[i].time += tr_end_time;
- i++;
- }
- // printf("after opening up\n");
- // show();
- // insert point at beginning and end of paste
- insert_beat(time, beat);
- // printf("after beginning point insert\n");
- // show();
- // insert_beat(time + tr_end_time, beat + dur);
- // printf("after ending point insert\n");
- // show();
- int j = from_map->locate_beat(dur);
- for (i = 0; i < j; i++) {
- insert_beat(from[i].time + time, // shift by time
- from[i].beat + beat); // and beat
- }
- // printf("after inserts\n");
- show();
- }
- void Alg_time_map::insert_time(double start, double len)
- {
- // find time,beat pair that determines tempo at start
- // compute beat offset = (delta beat / delta time) * len
- // add len,beat offset to each following Alg_beat
- // show();
- int i = locate_time(start); // start <= beats[i].time
- if (beats[i].time == start) i++; // start < beats[i].time
- // case 1: between beats
- if (i > 0 && i < length()) {
- double beat_offset = len * (beats[i].beat - beats[i-1].beat) /
- (beats[i].time - beats[i-1].time);
- while (i < length()) {
- beats[i].beat += beat_offset;
- beats[i].time += len;
- i++;
- }
- } // otherwise, last tempo is in effect; nothing to do
- // printf("time_map AFTER INSERT\n");
- // show();
- }
- void Alg_time_map::insert_beats(double start, double len)
- {
- int i = locate_beat(start); // start <= beats[i].beat
- if (beats[i].beat == start) i++;
- if (i > 0 && i < length()) {
- double time_offset = len * (beats[i].time - beats[i-1].time) /
- (beats[i].beat - beats[i-1].beat);
- while (i < length()) {
- beats[i].time += time_offset;
- beats[i].beat += len;
- i++;
- }
- } // otherwise, last tempo is in effect; nothing to do
- // printf("time_map AFTER INSERT\n");
- // show();
- }
- Alg_track::Alg_track(Alg_time_map *map, bool seconds)
- {
- type = 't';
- time_map = NULL;
- units_are_seconds = seconds;
- set_time_map(map);
- }
- Alg_event_ptr Alg_track::copy_event(Alg_event_ptr event)
- {
- Alg_event *new_event;
- if (event->is_note()) {
- new_event = new Alg_note((Alg_note_ptr) event);
- } else { // update
- new_event = new Alg_update((Alg_update_ptr) event);
- }
- return new_event;
- }
- Alg_track::Alg_track(Alg_track &track)
- {
- type = 't';
- time_map = NULL;
- for (int i = 0; i < track.length(); i++) {
- append(copy_event(track.events[i]));
- }
- set_time_map(track.time_map);
- units_are_seconds = track.units_are_seconds;
- }
- Alg_track::Alg_track(Alg_event_list_ref event_list, Alg_time_map_ptr map,
- bool units_are_seconds)
- {
- type = 't';
- time_map = NULL;
- for (int i = 0; i < event_list.length(); i++) {
- append(copy_event(event_list[i]));
- }
- set_time_map(map);
- this->units_are_seconds = units_are_seconds;
- }
- void Alg_track::serialize(void **buffer, long *bytes)
- {
- // first determine whether this is a seq or a track.
- // if it is a seq, then we will write the time map and a set of tracks
- // if it is a track, we just write the track data and not the time map
- //
- // The code will align doubles on ALIGN boundaries, and longs and
- // floats are aligned to multiples of 4 bytes.
- //
- // The format for a seq is:
- // 'ALGS' -- indicates that this is a sequence
- // long length of all seq data in bytes starting with 'ALGS'
- // long channel_offset_per_track
- // long units_are_seconds
- // time_map:
- // double last_tempo
- // long last_tempo_flag
- // long len -- number of tempo changes
- // for each tempo change (Alg_beat):
- // double time
- // double beat
- // time_sigs:
- // long len -- number of time_sigs
- // long pad
- // for each time signature:
- // double beat
- // double num
- // double den
- // tracks:
- // long len -- number of tracks
- // long pad
- // for each track:
- // 'ALGT' -- indicates this is a track
- // long length of all track data in bytes starting with 'ALGT'
- // long units_are_seconds
- // double beat_dur
- // double real_dur
- // long len -- number of events
- // for each event:
- // long selected
- // long type
- // long key
- // long channel
- // double time
- // if this is a note:
- // double pitch
- // double dur
- // double loud
- // long len -- number of parameters
- // for each parameter:
- // char attribute[] with zero pad to ALIGN
- // one of the following, depending on type:
- // double r
- // char s[] terminated by zero
- // long i
- // long l
- // char a[] terminated by zero
- // zero pad to ALIGN
- // else if this is an update
- // (same representation as parameter above)
- // zero pad to ALIGN
- //
- // The format for a track is given within the Seq format above
- assert(get_type() == 't');
- ser_write_buf.init_for_write();
- serialize_track();
- *buffer = ser_write_buf.to_heap(bytes);
- }
- void Alg_seq::serialize(void **buffer, long *bytes)
- {
- assert(get_type() == 's');
- ser_write_buf.init_for_write();
- serialize_seq();
- *buffer = ser_write_buf.to_heap(bytes);
- }
- void Serial_write_buffer::check_buffer(long needed)
- {
- if (len < (ptr - buffer) + needed) { // do we need more space?
- long new_len = len * 2; // exponential growth is important
- // initially, length is zero, so bump new_len to a starting value
- if (new_len == 0) new_len = 1024;
- // make sure new_len is as big as needed
- if (needed > new_len) new_len = needed;
- char *new_buffer = new char[new_len]; // allocate space
- ptr = new_buffer + (ptr - buffer); // relocate ptr to new buffer
- if (len > 0) { // we had a buffer already
- memcpy(new_buffer, buffer, len); // copy from old buffer
- delete buffer; // free old buffer
- }
- buffer = new_buffer; // update buffer information
- len = new_len;
- }
- }
- void Alg_seq::serialize_seq()
- {
- int i; // loop counters
- // we can easily compute how much buffer space we need until we
- // get to tracks, so expand at least that much
- long needed = 64 + 16 * time_map->beats.len + 24 * time_sig.length();
- ser_write_buf.check_buffer(needed);
- ser_write_buf.set_char('A');
- ser_write_buf.set_char('L');
- ser_write_buf.set_char('G');
- ser_write_buf.set_char('S');
- long length_offset = ser_write_buf.get_posn();
- ser_write_buf.set_int32(0); // leave room to come back and write length
- ser_write_buf.set_int32(channel_offset_per_track);
- ser_write_buf.set_int32(units_are_seconds);
- ser_write_buf.set_double(beat_dur);
- ser_write_buf.set_double(real_dur);
- ser_write_buf.set_double(time_map->last_tempo);
- ser_write_buf.set_int32(time_map->last_tempo_flag);
- ser_write_buf.set_int32(time_map->beats.len);
- for (i = 0; i < time_map->beats.len; i++) {
- ser_write_buf.set_double(time_map->beats[i].time);
- ser_write_buf.set_double(time_map->beats[i].beat);
- }
- ser_write_buf.set_int32(time_sig.length());
- ser_write_buf.pad();
- for (i = 0; i < time_sig.length(); i++) {
- ser_write_buf.set_double(time_sig[i].beat);
- ser_write_buf.set_double(time_sig[i].num);
- ser_write_buf.set_double(time_sig[i].den);
- }
- ser_write_buf.set_int32(tracks());
- ser_write_buf.pad();
- for (i = 0; i < tracks(); i++) {
- track(i)->serialize_track();
- }
- // do not include ALGS, include padding at end
- ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset);
- }
- void Alg_track::serialize_track()
- {
- // to simplify the code, copy from parameter addresses to locals
- int j;
- ser_write_buf.check_buffer(32);
- ser_write_buf.set_char('A');
- ser_write_buf.set_char('L');
- ser_write_buf.set_char('G');
- ser_write_buf.set_char('T');
- long length_offset = ser_write_buf.get_posn(); // save location for track length
- ser_write_buf.set_int32(0); // room to write track length
- ser_write_buf.set_int32(units_are_seconds);
- ser_write_buf.set_double(beat_dur);
- ser_write_buf.set_double(real_dur);
- ser_write_buf.set_int32(len);
- for (j = 0; j < len; j++) {
- ser_write_buf.check_buffer(24);
- Alg_event *event = (*this)[j];
- ser_write_buf.set_int32(event->get_selected());
- ser_write_buf.set_int32(event->get_type());
- ser_write_buf.set_int32(event->get_identifier());
- ser_write_buf.set_int32(event->chan);
- ser_write_buf.set_double(event->time);
- if (event->is_note()) {
- ser_write_buf.check_buffer(20);
- Alg_note *note = (Alg_note *) event;
- ser_write_buf.set_float(note->pitch);
- ser_write_buf.set_float(note->loud);
- ser_write_buf.set_double(note->dur);
- long parm_num_offset = ser_write_buf.get_posn();
- long parm_num = 0;
- ser_write_buf.set_int32(0); // placeholder for no. parameters
- Alg_parameters_ptr parms = note->parameters;
- while (parms) {
- serialize_parameter(&(parms->parm));
- parms = parms->next;
- parm_num++;
- }
- ser_write_buf.store_long(parm_num_offset, parm_num);
- } else {
- assert(event->is_update());
- Alg_update *update = (Alg_update *) event;
- serialize_parameter(&(update->parameter));
- }
- ser_write_buf.check_buffer(7); // maximum padding possible
- ser_write_buf.pad();
- }
- // write length, not including ALGT, including padding at end
- ser_write_buf.store_long(length_offset, ser_write_buf.get_posn() - length_offset);
- }
- void Alg_track::serialize_parameter(Alg_parameter *parm)
- {
- // add eight to account for name + zero end-of-string and the
- // possibility of adding 7 padding bytes
- long len = strlen(parm->attr_name()) + 8;
- ser_write_buf.check_buffer(len);
- ser_write_buf.set_string(parm->attr_name());
- ser_write_buf.pad();
- switch (parm->attr_type()) {
- case 'r':
- ser_write_buf.check_buffer(8);
- ser_write_buf.set_double(parm->r);
- break;
- case 's':
- ser_write_buf.check_buffer(strlen(parm->s) + 1);
- ser_write_buf.set_string(parm->s);
- break;
- case 'i':
- ser_write_buf.check_buffer(4);
- ser_write_buf.set_int32(parm->i);
- break;
- case 'l':
- ser_write_buf.check_buffer(4);
- ser_write_buf.set_int32(parm->l);
- break;
- case 'a':
- ser_write_buf.check_buffer(strlen(parm->a) + 1);
- ser_write_buf.set_string(parm->a);
- break;
- }
- }
- Alg_track *Alg_track::unserialize(void *buffer, long len)
- {
- assert(len > 8);
- ser_read_buf.init_for_read(buffer, len);
- bool alg = ser_read_buf.get_char() == 'A' &&
- ser_read_buf.get_char() == 'L' &&
- ser_read_buf.get_char() == 'G';
- assert(alg);
- char c = ser_read_buf.get_char();
- if (c == 'S') {
- Alg_seq *seq = new Alg_seq;
- ser_read_buf.unget_chars(4); // undo get_char() of A,L,G,S
- seq->unserialize_seq();
- return seq;
- } else {
- assert(c == 'T');
- Alg_track *track = new Alg_track;
- ser_read_buf.unget_chars(4); // undo get_char() of A,L,G,T
- track->unserialize_track();
- return track;
- }
- }
- #pragma warning(disable: 4800) // long to bool performance warning
- /* Note: this Alg_seq must have a default initialized Alg_time_map.
- * It will be filled in with data from the ser_read_buf buffer.
- */
- void Alg_seq::unserialize_seq()
- {
- ser_read_buf.check_input_buffer(48);
- bool algs = (ser_read_buf.get_char() == 'A') &&
- (ser_read_buf.get_char() == 'L') &&
- (ser_read_buf.get_char() == 'G') &&
- (ser_read_buf.get_char() == 'S');
- assert(algs);
- long len = ser_read_buf.get_int32();
- assert(ser_read_buf.get_len() >= len);
- channel_offset_per_track = ser_read_buf.get_int32();
- units_are_seconds = ser_read_buf.get_int32() != 0;
- beat_dur = ser_read_buf.get_double();
- real_dur = ser_read_buf.get_double();
- // no need to allocate an Alg_time_map since it's done during initialization
- time_map->last_tempo = ser_read_buf.get_double();
- time_map->last_tempo_flag = ser_read_buf.get_int32() != 0;
- long beats = ser_read_buf.get_int32();
- ser_read_buf.check_input_buffer(beats * 16 + 4);
- int i;
- for (i = 0; i < beats; i++) {
- double time = ser_read_buf.get_double();
- double beat = ser_read_buf.get_double();
- time_map->insert_beat(time, beat);
- // printf("time_map: %g, %g\n", time, beat);
- }
- long time_sig_len = ser_read_buf.get_int32();
- ser_read_buf.get_pad();
- ser_read_buf.check_input_buffer(time_sig_len * 24 + 8);
- for (i = 0; i < time_sig_len; i++) {
- double beat = ser_read_buf.get_double();
- double num = ser_read_buf.get_double();
- double den = ser_read_buf.get_double();
- time_sig.insert(beat, num, den);
- }
- long tracks_num = ser_read_buf.get_int32();
- ser_read_buf.get_pad();
- add_track(tracks_num - 1); // create tracks_num tracks
- for (i = 0; i < tracks_num; i++) {
- track(i)->unserialize_track();
- }
- // assume seq started at beginning of buffer. len measures
- // bytes after 'ALGS' header, so add 4 bytes and compare to
- // current buffer position -- they should agree
- assert(ser_read_buf.get_posn() == len + 4);
- }
- void Alg_track::unserialize_track()
- {
- ser_read_buf.check_input_buffer(32);
- bool algt = (ser_read_buf.get_char() == 'A') &&
- (ser_read_buf.get_char() == 'L') &&
- (ser_read_buf.get_char() == 'G') &&
- (ser_read_buf.get_char() == 'T');
- assert(algt);
- long offset = ser_read_buf.get_posn(); // stored length does not include 'ALGT'
- long bytes = ser_read_buf.get_int32();
- assert(bytes <= ser_read_buf.get_len() - offset);
- units_are_seconds = (bool) ser_read_buf.get_int32();
- beat_dur = ser_read_buf.get_double();
- real_dur = ser_read_buf.get_double();
- int event_count = ser_read_buf.get_int32();
- for (int i = 0; i < event_count; i++) {
- ser_read_buf.check_input_buffer(24);
- long selected = ser_read_buf.get_int32();
- char type = (char) ser_read_buf.get_int32();
- long key = ser_read_buf.get_int32();
- long channel = ser_read_buf.get_int32();
- double time = ser_read_buf.get_double();
- if (type == 'n') {
- ser_read_buf.check_input_buffer(20);
- float pitch = ser_read_buf.get_float();
- float loud = ser_read_buf.get_float();
- double dur = ser_read_buf.get_double();
- Alg_note *note =
- create_note(time, channel, key, pitch, loud, dur);
- note->set_selected(selected != 0);
- long param_num = ser_read_buf.get_int32();
- int j;
- // this builds a list of parameters in the correct order
- // (although order shouldn't matter)
- Alg_parameters_ptr *list = ¬e->parameters;
- for (j = 0; j < param_num; j++) {
- *list = new Alg_parameters(NULL);
- unserialize_parameter(&((*list)->parm));
- list = &((*list)->next);
- }
- append(note);
- } else {
- assert(type == 'u');
- Alg_update *update = create_update(time, channel, key);
- update->set_selected(selected != 0);
- unserialize_parameter(&(update->parameter));
- append(update);
- }
- ser_read_buf.get_pad();
- }
- assert(offset + bytes == ser_read_buf.get_posn());
- }
- void Alg_track::unserialize_parameter(Alg_parameter_ptr parm_ptr)
- {
- Alg_attribute attr = ser_read_buf.get_string();
- parm_ptr->attr = symbol_table.insert_string(attr);
- switch (parm_ptr->attr_type()) {
- case 'r':
- ser_read_buf.check_input_buffer(8);
- parm_ptr->r = ser_read_buf.get_double();
- break;
- case 's':
- parm_ptr->s = heapify(ser_read_buf.get_string());
- break;
- case 'i':
- ser_read_buf.check_input_buffer(4);
- parm_ptr->i = ser_read_buf.get_int32();
- break;
- case…
Large files files are truncated, but you can click here to view the full file