⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 allegro.cpp

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 CPP
字号:
// 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#include "assert.h"#include "stdlib.h"#include "allegro.h"#include "string.h"//#include "memory.h"#include "trace.h"Atoms symbol_table;bool within(double d1, double d2, double epsilon){    d1 -= d2;    return d1 < epsilon && d1 > -epsilon;}void Events::expand(){    max = (max + 5); // extra growth for small sizes    max += (max >> 2); // add 25%    Allegro_event_ptr *new_events = new Allegro_event_ptr[max];    // now do copy    memcpy(new_events, events, len * sizeof(Allegro_event_ptr));    if (events) delete[] events;    events = new_events;}Events::~Events(){    if (events) {        delete[] events;    }}void Events::insert(Allegro_event_ptr event){    if (max <= len) {        expand();    }    events[len] = event;    len++;    // find insertion point:    for (int i = 0; i < len; i++) {        if (events[i]->time > event->time) {            // insert event at i            memmove(&events[i + 1], &events[i],                     sizeof(Allegro_event_ptr) * (len - i - 1));            events[i] = event;            return;        }    }}void Events::append(Allegro_event_ptr event){    if (max <= len) {        expand();    }    events[len++] = event;}void Atoms::expand(){    max = (max + 5); // extra growth for small sizes    max += (max >> 2); // add 25%    char **new_atoms = new Attribute[max];    // now do copy    memcpy(new_atoms, atoms, len * sizeof(Attribute));    if (atoms) delete[] atoms;    atoms = new_atoms;}char *heapify(char *s){    char *h = new char[strlen(s) + 1];    strcpy(h, s);    return h;}Attribute Atoms::insert_new(const char *name, char attr_type){    if (len == max) expand();    char *h = new char[strlen(name) + 2];    strcpy(h + 1, name);    *h = attr_type;    atoms[len++] = h;    return h;}Attribute Atoms::insert_attribute(Attribute attr){    for (int i = 0; i < len; i++) {        if (strcmp(attr, atoms[i]) == 0) {            return atoms[i];        }    }    return insert_new(attr + 1, attr[0]);}Attribute 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] &&            strcmp(name, atoms[i] + 1) == 0) {            return atoms[i];        }    }    return insert_new(name, attr_type);}void Parameters::insert_real(Parameters **list, char *name, double r){    Parameters_ptr a = new Parameters(*list);    *list = a;    a->parm.set_attr(symbol_table.insert_string(name));    a->parm.r = r;    assert(a->parm.attr_type() == 'r');}void Parameters::insert_string(Parameters **list, char *name, char *s){    Parameters_ptr a = new 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 Parameters::insert_integer(Parameters **list, char *name, long i){    Parameters_ptr a = new Parameters(*list);    *list = a;    a->parm.set_attr(symbol_table.insert_string(name));    a->parm.i = i;    assert(a->parm.attr_type() == 'i');}void Parameters::insert_logical(Parameters **list, char *name, bool l){    Parameters_ptr a = new Parameters(*list);    *list = a;    a->parm.set_attr(symbol_table.insert_string(name));    a->parm.l = l;    assert(a->parm.attr_type() == 'l');}void Parameters::insert_atom(Parameters **list, char *name, char *s){    Parameters_ptr a = new 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');}Parameters *Parameters::remove_key(Parameters **list, char *name){    while (*list) {        if (strcmp((*list)->parm.attr_name(), name) == 0) {            Parameters_ptr p = *list;            *list = p->next;            p->next = NULL;            return p; // caller should free this pointer        }        *list = (*list)->next;    }    return NULL;}Parameter::~Parameter(){    if (attr_type() == 's' && s) delete[] s;}Allegro_note::~Allegro_note(){    while (parameters) {        Parameters_ptr to_delete = parameters;        parameters = parameters->next;        delete to_delete;    }}void Beats::expand(){    max = (max + 5); // extra growth for small sizes    max += (max >> 2); // add 25%    Beat_ptr new_beats = new Beat[max];    // now do copy    memcpy(new_beats, beats, len * sizeof(Beat));    if (beats) delete[] beats;    beats = new_beats;}void Beats::insert(long i, Beat_ptr beat){    assert(i >= 0 && i <= len);    if (max <= len) {        expand();    }    memmove(&beats[i], &beats[i + 1], sizeof(Beat) * (len - i));    memcpy(&beats[i], beat, sizeof(Beat));    len++;}long Time_map::locate_time(double time){    int i = 0;    while ((i < beats.len) && (time > beats[i].time)) {        i++;    }    return i;}long Time_map::locate_beat(double beat){    int i = 0;    while (( i < beats.len) && (beat > beats[i].beat)) {        i++;    }    return i;}double Time_map::beat_to_time(double beat){    Beat_ptr mbi;    Beat_ptr mbi1;    if (beat <= 0) {        return beat;    }    int i = locate_beat(beat);    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 * 0.6;        } else {            mbi = &beats[i - 2];            mbi1 = &beats[i - 1];        }    } else {        mbi = &beats[i - 1];        mbi1 = &beats[i];    }    // whether w 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 Time_map::time_to_beat(double time){    Beat_ptr mbi;    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 / 0.6;        } 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 Time_sigs::expand(){    max = (max + 5); // extra growth for small sizes    max += (max >> 2); // add 25%    Time_sig_ptr new_time_sigs = new Time_sig[max];    // now do copy    memcpy(new_time_sigs, time_sigs, len * sizeof(Time_sig));    if (time_sigs) delete[] time_sigs;    time_sigs = new_time_sigs;}void Time_sigs::insert(double beat, double num, double den){    if (max <= len) {        expand();    }    time_sigs[len].beat = beat;    time_sigs[len].num = num;    time_sigs[len].den = den;    len++;    // find insertion point:    for (int i = 0; i < len; i++) {        if (time_sigs[i].beat > beat) {            // insert event at i            memmove(&time_sigs[i], &time_sigs[i + 1],                     sizeof(Time_sig) * (len - i));            time_sigs[i].beat = beat;            time_sigs[i].num = num;            time_sigs[i].den = den;        }        return;    }}Seq::~Seq(){    for (int i = 0; i < notes.len; i++)        delete notes.events[i];}long Seq::seek_time(double time)// find index of first score event after time{    long i;    for (i = 0; i < notes.len; i++) {        if (notes[i]->time > time) {            break;        }    }    return i;}void Seq::convert_to_beats()// modify all times and durations in notes to beats{    if (units_are_seconds) {        units_are_seconds = false;        for (long i = 0; i < notes.len; i++) {            Allegro_event_ptr e = notes[i];            double beat = map.time_to_beat(e->time);            if (e->type == 'n') {                Allegro_note_ptr n = (Allegro_note_ptr) e;                n->dur = map.time_to_beat(n->time + n->dur) - beat;                n->time = beat;            }        }    }}void Seq::convert_to_seconds()// modify all times and durations in notes to seconds{    if (!units_are_seconds) {        units_are_seconds = true;        for (long i = 0; i < notes.len; i++) {            Allegro_event_ptr e = notes[i];            double time = map.beat_to_time(e->time);            if (e->type == 'n') {                Allegro_note_ptr n = (Allegro_note_ptr) e;                n->dur = map.beat_to_time(n->time + n->dur) - time;                n->time = time;            }        }    }}bool Seq::insert_beat(double time, double beat)// insert a time,beat pair// return true or false (false indicates an error, no update)// it is an error to imply a negative tempo or to insert at// a negative time{    if (time < 0 || beat < 0) return false;    if (time == 0.0 && beat > 0)        time = 0.000001; // avoid infinite tempo, offset time by 1us    if (time == 0.0 && beat == 0.0)        return true; // (0,0) is already in the map!    convert_to_beats(); // beats are invariant when changing tempo    int i = map.locate_time(time); // i is insertion point    if (i < map.beats.len && within(map.beats[i].time, time, 0.000001)) {        // replace beat if time is already in the map        map.beats[i].beat = beat;    } else {        Beat point;        point.beat = beat;        point.time = time;        map.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;    while (j < map.beats.len &&        map.beats[j - 1].beat + 0.000001 >= map.beats[j].beat) {        map.beats[j].beat = map.beats[j - 1].beat + 0.000001;        j++;    }    return true;}bool Seq::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;    convert_to_beats(); // beats are invariant when changing tempo    double time = map.beat_to_time(beat);    long i = map.locate_time(time);    if (i >= map.beats.len || !within(map.beats[i].time, time, 0.000001)) {        insert_beat(time, beat);    }    // now i is index of beat where tempo will change    if (i == map.beats.len - 1) {        map.last_tempo = tempo;        map.last_tempo_flag = true;    } else { // adjust all future beats        // compute the difference in beats        double diff = map.beats[i + 1].beat - map.beats[i].beat;        // convert beat difference to seconds at new tempo        diff = diff /tempo;        // figure out old time difference:        double old_diff = map.beats[i + 1].time - time;        // compute difference too        diff = diff - old_diff;        // apply new_diff to score and beats        while (i < map.beats.len) {            map.beats[i].time = map.beats[i].time + diff;            i++;        }    }    return true;}void Seq::add_event(Allegro_event_ptr event){    convert_to_seconds();    notes.insert(event);/*    if (event->type == 'n') {        Allegro_note_ptr n = (Allegro_note_ptr) event;        trace("note %d at %g for %g\n", n->key, n->time, n->dur);    } */}bool Seq::set_tempo(double tempo, double start_beat, double end_beat)// set tempo from start_beat to end_beat{    if (start_beat >= end_beat) return false;    convert_to_beats();    // algorithm: insert a beat event if necessary at start_beat    //    and at end_beat    // delete intervening map elements    // change the tempo    insert_beat(map.beat_to_time(start_beat), start_beat);    insert_beat(map.beat_to_time(end_beat), end_beat);    long start_x = map.locate_beat(start_beat) + 1;    long stop_x = map.locate_beat(end_beat) + 1;    while (stop_x < map.beats.len) {        map.beats[start_x] = map.beats[stop_x];        start_x++;        stop_x++;    }    map.beats.len = start_x; // truncate the map to new length    return insert_tempo(tempo, start_beat);}void Seq::set_time_sig(double beat, double num, double den){    time_sig.insert(beat, num, den);}void Seq::beat_to_measure(double beat, long *measure, double *m_beat,                          double *num, double *den){    // return [measure, beat, num, den]    double m = 0; // measure number    double bpm;    int tsx;    for (tsx = 0; tsx < time_sig.len; tsx++) {        bpm = 4;        // assume 4/4 if no time signature        double prev_beat = 0;        double prev_num = 4;        double prev_den = 4;        if (tsx > 0) {            bpm = time_sig[tsx].num * 4 / time_sig[tsx].den;            prev_beat = time_sig[tsx].beat;            prev_num = time_sig[tsx].num;            prev_den = time_sig[tsx].den;        }        if (time_sig[tsx].beat > beat) {            m = m + (beat - prev_beat) / bpm;            *measure = (long) m;            *m_beat = (m - *measure) * bpm * prev_den * 0.25;            *num = prev_num;            *den = prev_den;            return;        }        // round m up to an integer (but allow for a small        // numerical inaccuracy)        m = m + (long) (0.99 + (time_sig[tsx].beat - prev_beat) / bpm);    }    // if we didn't return yet, compute after last time signature    Time_sig initial(0, 4, 4);    Time_sig_ptr prev = &initial;    if (tsx > 0) { // use last time signature        prev = &time_sig[time_sig.len - 1];    }    bpm = prev->num * 4 / prev->den;    m = m + (beat - prev->beat) / bpm;    *measure = (long) m;    *m_beat = (m - *measure) * bpm * prev->den * 0.25;    *num = prev->num;    *den = prev->den;}void Seq::set_events(Allegro_event_ptr *events, long len, long max){    convert_to_seconds(); // because notes are in seconds    notes.set_events(events, len, max);}// sr_letter_to_type = {"i": 'Integer', "r": 'Real', "s": 'String',//                     "l": 'Logical', "a": 'Symbol'}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -