Alg_parameters_ptr Alg_reader::process_attributes( Alg_parameters_ptr attributes, double time) { // print "process_attributes:", attributes bool ts_flag = false; if (attributes) { Alg_parameters_ptr a; bool in_seconds = seq->get_units_are_seconds(); if (a = Alg_parameters::remove_key(&attributes, "tempor")) { double tempo = a->parm.r; seq->insert_tempo(tempo, seq->get_time_map()->time_to_beat(time)); } if (a = Alg_parameters::remove_key(&attributes, "beatr")) { double beat = a->parm.r; seq->insert_beat(time, beat); } if (a = Alg_parameters::remove_key(&attributes, "timesig_numr")) { tsnum = a->parm.r; ts_flag = true; } if (a = Alg_parameters::remove_key(&attributes, "timesig_denr")) { tsden = a->parm.r; ts_flag = true; } if (ts_flag) { seq->set_time_sig(seq->get_time_map()->time_to_beat(time), tsnum, tsden); } if (in_seconds) seq->convert_to_seconds(); } return attributes; // in case it was modified }
Alg_seq_ptr NoteTrack::MakeExportableSeq() { double offset = GetOffset(); if (offset == 0) return mSeq; // make a copy, deleting events that are shifted before time 0 double start = -offset; if (start < 0) start = 0; // notes that begin before "start" are not included even if they // extend past "start" (because "all" parameter is set to false) Alg_seq_ptr seq = mSeq->copy(start, mSeq->get_dur() - start, false); if (offset > 0) { // swap seq and mSeq so that Shift operates on the new copy Alg_seq_ptr old_seq = mSeq; mSeq = seq; Shift(offset); seq = mSeq; // undo the swap mSeq = old_seq; #ifdef OLD_CODE // now shift events by offset. This must be done with an integer // number of measures, so first, find the beats-per-measure double beats_per_measure = 4.0; Alg_time_sig_ptr tsp = NULL; if (seq->time_sig.length() > 0 && seq->time_sig[0].beat < ALG_EPS) { // there is an initial time signature tsp = &(seq->time_sig[0]); beats_per_measure = (tsp->num * 4) / tsp->den; } // also need the initial tempo double bps = ALG_DEFAULT_BPM / 60; Alg_time_map_ptr map = seq->get_time_map(); Alg_beat_ptr bp = &(map->beats[0]); if (bp->time < ALG_EPS) { // tempo change at time 0 if (map->beats.len > 1) { // compute slope to get tempo bps = (map->beats[1].beat - map->beats[0].beat) / (map->beats[1].time - map->beats[0].time); } else if (seq->get_time_map()->last_tempo_flag) { bps = seq->get_time_map()->last_tempo; } } // find closest number of measures to fit in the gap // number of measures is offset / measure_time double measure_time = beats_per_measure / bps; // seconds per measure int n = ROUND(offset / measure_time); if (n == 0) n = 1; // we will insert n measures. Compute the desired duration of each. measure_time = offset / n; bps = beats_per_measure / measure_time; // insert integer multiple of measures at beginning seq->convert_to_beats(); seq->insert_silence(0, beats_per_measure * n); // make sure time signature at 0 is correct if (tsp) { seq->set_time_sig(0, tsp->num, tsp->den); } // adjust tempo to match offset seq->set_tempo(bps * 60.0, 0, beats_per_measure * n); #endif } else { // if offset is negative, it might not be a multiple of beats, but // we want to preserve the relative positions of measures. I.e. we // should shift barlines and time signatures as well as notes. // Insert a time signature at the first bar-line if necessary. // Translate start from seconds to beats and call it beat: double beat = mSeq->get_time_map()->time_to_beat(start); // Find the time signature in mSeq in effect at start (beat): int i = mSeq->time_sig.find_beat(beat); // i is where you would insert a new time sig at beat, // Case 1: beat coincides with a time sig at i. Time signature // at beat means that there is a barline at beat, so when beat // is shifted to 0, the relative barline positions are preserved if (mSeq->time_sig.length() > 0 && within(beat, mSeq->time_sig[i].beat, ALG_EPS)) { // beat coincides with time signature change, so offset must // be a multiple of beats /* do nothing */ ; // Case 2: there is no time signature before beat. } else if (i == 0 && (mSeq->time_sig.length() == 0 || mSeq->time_sig[i].beat > beat)) { // If beat does not fall on an implied barline, we need to // insert a time signature. double measures = beat / 4.0; double imeasures = ROUND(measures); if (!within(measures, imeasures, ALG_EPS)) { double bar_offset = (int(measures) + 1) * 4.0 - beat; seq->set_time_sig(bar_offset, 4, 4); } // This case should never be true because if i == 0, either there // are no time signatures before beat (Case 2), // or there is one time signature at beat (Case 1) } else if (i == 0) { /* do nothing (might be good to assert(false)) */ ; // Case 3: i-1 must be the effective time sig position } else { i -= 1; // index the time signature in effect at beat Alg_time_sig_ptr tsp = &(mSeq->time_sig[i]); double beats_per_measure = (tsp->num * 4) / tsp->den; double measures = (beat - tsp->beat) / beats_per_measure; int imeasures = ROUND(measures); if (!within(measures, imeasures, ALG_EPS)) { // beat is not on a measure, so we need to insert a time sig // to force a bar line at the first measure location after // beat double bar = tsp->beat + beats_per_measure * (int(measures) + 1); double bar_offset = bar - beat; // insert new time signature at bar_offset in new sequence // It will have the same time signature, but the position will // force a barline to match the barlines in mSeq seq->set_time_sig(bar_offset, tsp->num, tsp->den); } // else beat coincides with a barline, so no need for an extra // time signature to force barline alignment } } return seq; }
void Alg_midifile_reader::Mf_timesig(int i1, int i2, int i3, int i4) { seq->set_time_sig(double(get_currtime()) / divisions, i1, 1 << i2); }