diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2008-01-19 21:13:45 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2008-01-19 21:13:45 +0000 |
commit | 89d564186d0b41469cf56ca3f400f98d3ddcfce8 (patch) | |
tree | 3824c6fb6d96a26a00346d848309ff982e852297 | |
parent | 95a24f9707c342ea1764eb8d1de0a9c73eda84df (diff) |
fixes and bindings for region gain control; set-tempo-from-region implementation : please test and look for tempo/meter related bugs
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2950 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | gtk2_ardour/ardour.bindings.in | 14 | ||||
-rw-r--r-- | gtk2_ardour/ardour.menus | 1 | ||||
-rw-r--r-- | gtk2_ardour/editor.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_actions.cc | 3 | ||||
-rw-r--r-- | gtk2_ardour/editor_ops.cc | 65 | ||||
-rw-r--r-- | libs/ardour/ardour/tempo.h | 20 | ||||
-rw-r--r-- | libs/ardour/tempo.cc | 289 |
7 files changed, 273 insertions, 121 deletions
diff --git a/gtk2_ardour/ardour.bindings.in b/gtk2_ardour/ardour.bindings.in index 1efdb1cdd4..9dbbd8deff 100644 --- a/gtk2_ardour/ardour.bindings.in +++ b/gtk2_ardour/ardour.bindings.in @@ -38,6 +38,10 @@ (gtk_accel_path "<Actions>/Editor/set-punch-from-edit-range" "bracketleft") (gtk_accel_path "<Actions>/Editor/set-punch-from-region" "<%SECONDARY%>bracketleft") +(gtk_accel_path "<Actions>/Editor/boost-region-gain" "asciicircum") +(gtk_accel_path "<Actions>/Editor/cut-region-gain" "ampersand") +(gtk_accel_path "<Actions>/Editor/set-tempo-from-region" "asterisk") + ;; letters ;; TOP ROW @@ -50,6 +54,7 @@ (gtk_accel_path "<Actions>/Editor/select-all-before-edit-cursor" "<%PRIMARY%>e") (gtk_accel_path "<Actions>/Editor/show-editor-mixer" "<%TERTIARY%>e") (gtk_accel_path "<Actions>/Common/goto-editor" "<%WINDOW%>e") +(gtk_accel_path "<Actions>/Editor/select-all-after-edit-cursor" "<%TERTIARY%><%PRIMARY%>e") (gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-range" "r") (gtk_accel_path "<Actions>/Editor/redo" "<%PRIMARY%>r") (gtk_accel_path "<Actions>/Transport/Record" "<%TERTIARY%>r") @@ -62,22 +67,19 @@ (gtk_accel_path "<Actions>/Common/ToggleOptionsEditor" "<%WINDOW%>o") (gtk_accel_path "<Actions>/Editor/set-playhead" "p") (gtk_accel_path "<Actions>/Editor/select-all-before-playhead" "<%PRIMARY%>p") +(gtk_accel_path "<Actions>/Editor/select-all-after-playhead" "<%TERTIARY%><%PRIMARY%>p") ;; MIDDLE ROW (gtk_accel_path "<Actions>/Editor/align-regions-sync-relative" "a") -(gtk_accel_path "<Actions>/Editor/align-regions-start-relative" "<%PRIMARY%>a") +(gtk_accel_path "<Actions>/Editor/select-all" "<%PRIMARY%>a") (gtk_accel_path "<Actions>/Editor/align-regions-end" "<%SECONDARY%>a") (gtk_accel_path "<Actions>/Editor/align-regions-sync" "<%TERTIARY%>a") +(gtk_accel_path "<Actions>/Editor/align-regions-start-relative" "<%LEVEL4%>a") (gtk_accel_path "<Actions>/Editor/split-region" "s") (gtk_accel_path "<Actions>/Common/Save" "<%PRIMARY%>s") (gtk_accel_path "<Actions>/Editor/duplicate-region" "d") (gtk_accel_path "<Actions>/Editor/select-all-in-punch-range" "<%PRIMARY%>d") - -(gtk_accel_path "<Actions>/Editor/select-all" "<%PRIMARY%>a") -(gtk_accel_path "<Actions>/Editor/select-all-after-playhead" "<%TERTIARY%><%PRIMARY%>p") -(gtk_accel_path "<Actions>/Editor/select-all-after-edit-cursor" "<%TERTIARY%><%PRIMARY%>e") - (gtk_accel_path "<Actions>/Editor/toggle-follow-playhead" "f") (gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-gain" "g") (gtk_accel_path "<Actions>/Editor/play-selected-regions" "h") diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus index 73768f3cf4..2237a30ea0 100644 --- a/gtk2_ardour/ardour.menus +++ b/gtk2_ardour/ardour.menus @@ -194,6 +194,7 @@ <menuitem action='trim-region-to-punch'/> <separator/> <menuitem action='pitch-shift-region'/> + <menuitem action='set-tempo-from-region'/> </menu> <menu name='View' action = 'View'> <menu name='ZoomFocus' action='ZoomFocus'> diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index ac67f9015f..ec7554bf3a 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -982,6 +982,8 @@ class Editor : public PublicEditor void denormalize_region (); void adjust_region_scale_amplitude (bool up); + void use_region_as_bar (); + void audition_region_from_region_list (); void hide_region_from_region_list (); void remove_region_from_region_list (); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index ce33a0177e..0b46253efb 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -359,6 +359,9 @@ Editor::register_actions () act = ActionManager::register_action (editor_actions, "cut-region-gain", _("Cut Region Gain"), bind (mem_fun(*this, &Editor::adjust_region_scale_amplitude), false)); ActionManager::session_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "set-tempo-from-region", _("Set Tempo from Region=Bar"), mem_fun(*this, &Editor::use_region_as_bar)); + ActionManager::session_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "crop", _("Crop"), mem_fun(*this, &Editor::crop_region_to_selection)); ActionManager::session_sensitive_actions.push_back (act); act = ActionManager::register_action (editor_actions, "insert-chunk", _("Insert Chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 51a6d294cd..11917851f7 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -4119,7 +4119,7 @@ Editor::adjust_region_scale_amplitude (bool up) return; } - ExclusiveRegionSelection (*this, entered_regionview); + ExclusiveRegionSelection esr (*this, entered_regionview); if (selection->regions.empty()) { return; @@ -4135,10 +4135,6 @@ Editor::adjust_region_scale_amplitude (bool up) double fraction = gain_to_slider_position (arv->audio_region()->scale_amplitude ()); - cerr << "slider pos for " << arv->audio_region()->scale_amplitude () - << " = " << fraction - << endl; - if (up) { fraction += 0.05; fraction = min (fraction, 1.0); @@ -4151,16 +4147,14 @@ Editor::adjust_region_scale_amplitude (bool up) continue; } - if (up && fraction >= 1.0) { - continue; - } - fraction = slider_position_to_gain (fraction); fraction = coefficient_to_dB (fraction); fraction = dB_to_coefficient (fraction); - - cerr << "set scale amp for " << arv->audio_region()->name() << " to " << fraction << endl; + if (up && fraction >= 2.0) { + continue; + } + arv->audio_region()->set_scale_amplitude (fraction); session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state())); } @@ -4953,3 +4947,52 @@ Editor::pitch_shift_regions () pitch_shift (selection->regions, 1.2); } +void +Editor::use_region_as_bar () +{ + if (!session) { + return; + } + + ExclusiveRegionSelection esr (*this, entered_regionview); + + if (selection->regions.empty()) { + return; + } + + RegionView* rv = selection->regions.front(); + + const Meter& m (session->tempo_map().meter_at (rv->region()->position())); + + /* region length = 1 bar */ + + /* 1 bar = how many beats per bar */ + + double beats_per_bar = m.beats_per_bar(); + + /* now we want frames per beat. + we have frames per bar, and beats per bar, so ... + */ + + double frames_per_beat = rv->region()->length() / beats_per_bar; + + /* beats per minute = */ + + double beats_per_minute = (session->frame_rate() * 60.0) / frames_per_beat; + + const TempoSection& t (session->tempo_map().tempo_section_at (rv->region()->position())); + + begin_reversible_command (_("set tempo from region")); + XMLNode& before (session->tempo_map().get_state()); + + if (t.frame() == rv->region()->position()) { + session->tempo_map().change_existing_tempo_at (rv->region()->position(), beats_per_minute, t.note_type()); + } else { + session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), rv->region()->position()); + } + + XMLNode& after (session->tempo_map().get_state()); + + session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after)); + commit_reversible_command (); +} diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index fcd42734b0..fa1d882ab3 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -109,6 +109,9 @@ class MetricSection { public: MetricSection (const BBT_Time& start) : _start (start), _frame (0), _movable (true) {} + MetricSection (nframes_t start) + : _frame (start), _movable (true) {} + virtual ~MetricSection() {} const BBT_Time& start() const { return _start; } @@ -142,6 +145,8 @@ class MeterSection : public MetricSection, public Meter { public: MeterSection (const BBT_Time& start, double bpb, double note_type) : MetricSection (start), Meter (bpb, note_type) {} + MeterSection (nframes_t start, double bpb, double note_type) + : MetricSection (start), Meter (bpb, note_type) {} MeterSection (const XMLNode&); static const string xml_state_node_name; @@ -153,6 +158,8 @@ class TempoSection : public MetricSection, public Tempo { public: TempoSection (const BBT_Time& start, double qpm, double note_type) : MetricSection (start), Tempo (qpm, note_type) {} + TempoSection (nframes_t start, double qpm, double note_type) + : MetricSection (start), Tempo (qpm, note_type) {} TempoSection (const XMLNode&); static const string xml_state_node_name; @@ -165,7 +172,6 @@ typedef list<MetricSection*> Metrics; class TempoMap : public PBD::StatefulDestructible { public: - TempoMap (nframes_t frame_rate); ~TempoMap(); @@ -207,9 +213,14 @@ class TempoMap : public PBD::StatefulDestructible const Tempo& tempo_at (nframes_t); const Meter& meter_at (nframes_t); + const TempoSection& tempo_section_at (nframes_t); + void add_tempo(const Tempo&, BBT_Time where); void add_meter(const Meter&, BBT_Time where); + void add_tempo(const Tempo&, nframes_t where); + void add_meter(const Meter&, nframes_t where); + void move_tempo (TempoSection&, const BBT_Time& to); void move_meter (MeterSection&, const BBT_Time& to); @@ -267,6 +278,8 @@ class TempoMap : public PBD::StatefulDestructible Metric metric_at (nframes_t) const; void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const; + void change_existing_tempo_at (nframes_t, double bpm, double note_type); + sigc::signal<void,ARDOUR::Change> StateChanged; private: @@ -280,8 +293,7 @@ class TempoMap : public PBD::StatefulDestructible BBT_Time last_bbt; mutable Glib::RWLock lock; - void timestamp_metrics (); - + void timestamp_metrics (bool use_bbt); nframes_t round_to_type (nframes_t fr, int dir, BBTPointType); @@ -298,7 +310,7 @@ class TempoMap : public PBD::StatefulDestructible nframes_t count_frames_between_metrics (const Meter&, const Tempo&, const BBT_Time&, const BBT_Time&) const; int move_metric_section (MetricSection&, const BBT_Time& to); - void do_insert (MetricSection* section); + void do_insert (MetricSection* section, bool with_bbt); }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 780f5c6a5d..6e74c49859 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -268,7 +268,7 @@ TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when) section.set_start (corrected); metrics->sort (cmp); - timestamp_metrics (); + timestamp_metrics (true); return 0; } @@ -345,16 +345,22 @@ TempoMap::remove_meter (const MeterSection& tempo) } void -TempoMap::do_insert (MetricSection* section) +TempoMap::do_insert (MetricSection* section, bool with_bbt) { Metrics::iterator i; for (i = metrics->begin(); i != metrics->end(); ++i) { - if ((*i)->start() < section->start()) { - continue; + if (with_bbt) { + if ((*i)->start() < section->start()) { + continue; + } + } else { + if ((*i)->frame() < section->frame()) { + continue; + } } - + metrics->insert (i, section); break; } @@ -363,7 +369,7 @@ TempoMap::do_insert (MetricSection* section) metrics->insert (metrics->end(), section); } - timestamp_metrics (); + timestamp_metrics (with_bbt); } void @@ -376,7 +382,18 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where) where.ticks = 0; - do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type())); + do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), true); + } + + StateChanged (Change (0)); +} + +void +TempoMap::add_tempo (const Tempo& tempo, nframes_t where) +{ + { + Glib::RWLock::WriterLock lm (lock); + do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), false); } StateChanged (Change (0)); @@ -399,7 +416,7 @@ TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement) *((Tempo *) ts) = replacement; replaced = true; - timestamp_metrics (); + timestamp_metrics (true); break; } } @@ -432,7 +449,18 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where) where.ticks = 0; - do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor())); + do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), false); + } + + StateChanged (Change (0)); +} + +void +TempoMap::add_meter (const Meter& meter, nframes_t where) +{ + { + Glib::RWLock::WriterLock lm (lock); + do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), true); } StateChanged (Change (0)); @@ -454,7 +482,7 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement) *((Meter*) ms) = replacement; replaced = true; - timestamp_metrics (); + timestamp_metrics (true); break; } } @@ -465,6 +493,49 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement) } } +void +TempoMap::change_existing_tempo_at (nframes_t where, double beats_per_minute, double note_type) +{ + Tempo newtempo (beats_per_minute, note_type); + + TempoSection* prev; + TempoSection* first; + Metrics::iterator i; + + /* find the TempoSection immediately preceding "where" + */ + + for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) { + + if ((*i)->frame() > where) { + break; + } + + TempoSection* t; + + if ((t = dynamic_cast<TempoSection*>(*i)) != 0) { + if (!first) { + first = t; + } + prev = t; + } + } + + if (!prev) { + if (!first) { + error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg; + return; + } + + prev = first; + } + + /* reset */ + + *((Tempo*)prev) = newtempo; + StateChanged (Change (0)); +} + const MeterSection& TempoMap::first_meter () const { @@ -498,43 +569,84 @@ TempoMap::first_tempo () const } void -TempoMap::timestamp_metrics () +TempoMap::timestamp_metrics (bool use_bbt) { Metrics::iterator i; const Meter* meter; const Tempo* tempo; Meter *m; Tempo *t; - nframes_t current; - nframes_t section_frames; - BBT_Time start; - BBT_Time end; meter = &first_meter (); tempo = &first_tempo (); - current = 0; - for (i = metrics->begin(); i != metrics->end(); ++i) { - - end = (*i)->start(); + if (use_bbt) { - section_frames = count_frames_between_metrics (*meter, *tempo, start, end); + nframes_t current = 0; + nframes_t section_frames; + BBT_Time start; + BBT_Time end; - current += section_frames; + for (i = metrics->begin(); i != metrics->end(); ++i) { + + end = (*i)->start(); + + section_frames = count_frames_between_metrics (*meter, *tempo, start, end); + + current += section_frames; + + start = end; + + (*i)->set_frame (current); + + if ((t = dynamic_cast<TempoSection*>(*i)) != 0) { + tempo = t; + } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) { + meter = m; + } else { + fatal << _("programming error: unhandled MetricSection type") << endmsg; + /*NOTREACHED*/ + } + } - start = end; + } else { - (*i)->set_frame (current); + bool first = true; - if ((t = dynamic_cast<TempoSection*>(*i)) != 0) { - tempo = t; - } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) { - meter = m; - } else { - fatal << _("programming error: unhandled MetricSection type") << endmsg; - /*NOTREACHED*/ + for (i = metrics->begin(); i != metrics->end(); ++i) { + + BBT_Time bbt; + + bbt_time_with_metric ((*i)->frame(), bbt, Metric (*meter, *tempo)); + + // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => "; + + if (first) { + first = false; + } else { + if (bbt.beats != 1 || bbt.ticks != 0) { + bbt.bars += 1; + bbt.beats = 1; + bbt.ticks = 0; + } + } + + // cerr << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << endl; + + (*i)->set_start (bbt); + + if ((t = dynamic_cast<TempoSection*>(*i)) != 0) { + tempo = t; + } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) { + meter = m; + } else { + fatal << _("programming error: unhandled MetricSection type") << endmsg; + /*NOTREACHED*/ + } } } + + // dump (cerr); } TempoMap::Metric @@ -666,17 +778,15 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me nframes_t TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) const { - - /* for this to work with fractional measure types, start and end have to "legal" BBT types, - that means that the beats and ticks should be inside a bar + /* for this to work with fractional measure types, start and end have to be "legal" BBT types, + that means that the beats and ticks should be inside a bar */ - nframes_t frames = 0; nframes_t start_frame = 0; nframes_t end_frame = 0; - Metric m = metric_at(start); + Metric m = metric_at (start); uint32_t bar_offset = start.bars - m.start().bars; @@ -939,67 +1049,6 @@ TempoMap::round_to_beat_subdivision (nframes_t fr, int sub_num) } return frame_time (the_beat); - - - - /***************************** - XXX just keeping this for reference - - TempoMap::BBTPointList::iterator i; - TempoMap::BBTPointList *more_zoomed_bbt_points; - nframes_t frame_one_beats_worth; - nframes_t pos = 0; - nframes_t next_pos = 0 ; - double tempo = 1; - double frames_one_subdivisions_worth; - bool fr_has_changed = false; - - int n; - - frame_one_beats_worth = (nframes_t) ::floor ((double) _frame_rate * 60 / 20 ); //one beat @ 20 bpm - { - Glib::RWLock::ReaderLock lm (lock); - more_zoomed_bbt_points = get_points((fr >= frame_one_beats_worth) ? - fr - frame_one_beats_worth : 0, fr+frame_one_beats_worth ); - } - if (more_zoomed_bbt_points == 0 || more_zoomed_bbt_points->empty()) { - return fr; - } - - for (i = more_zoomed_bbt_points->begin(); i != more_zoomed_bbt_points->end(); i++) { - if ((*i).frame <= fr) { - pos = (*i).frame; - tempo = (*i).tempo->beats_per_minute(); - - } else { - i++; - next_pos = (*i).frame; - break; - } - } - frames_one_subdivisions_worth = ((double) _frame_rate * 60 / (sub_num * tempo)); - - for (n = sub_num; n > 0; n--) { - if (fr >= (pos + ((n - 0.5) * frames_one_subdivisions_worth))) { - fr = (nframes_t) round(pos + (n * frames_one_subdivisions_worth)); - if (fr > next_pos) { - fr = next_pos; //take care of fractional beats that don't match the subdivision asked - } - fr_has_changed = true; - break; - } - } - - if (!fr_has_changed) { - fr = pos; - } - - delete more_zoomed_bbt_points; - return fr ; - - ******************************/ - - } nframes_t @@ -1051,6 +1100,12 @@ TempoMap::round_to_type (nframes_t frame, int dir, BBTPointType type) } + /* + cerr << "for " << frame << " round to " << bbt << " using " + << metric.start() + << endl; + */ + return metric.frame() + count_frames_between (metric.start(), bbt); } @@ -1148,6 +1203,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const if (beat == 1) { if (current >= lower) { + // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl; points->push_back (BBTPoint (*meter, *tempo,(nframes_t)rint(current), Bar, bar, 1)); } @@ -1159,6 +1215,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const while (beat <= ceil( beats_per_bar) && beat_frame < limit) { if (beat_frame >= lower) { + // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl; points->push_back (BBTPoint (*meter, *tempo, (nframes_t) rint(beat_frame), Beat, bar, beat)); } beat_frame += beat_frames; @@ -1167,7 +1224,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const beat++; } - if (beat > ceil(beats_per_bar) ) { + if (beat > ceil(beats_per_bar) || i != metrics->end()) { /* we walked an entire bar. its important to move `current' forward @@ -1185,10 +1242,15 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const so we subtract the possible extra fraction from the current */ - current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar); + if (beat > ceil (beats_per_bar)) { + /* next bar goes where the numbers suggest */ + current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar); + } else { + /* next bar goes where the next metric is */ + current = limit; + } bar++; beat = 1; - } } @@ -1225,6 +1287,33 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const return points; } +const TempoSection& +TempoMap::tempo_section_at (nframes_t frame) +{ + Glib::RWLock::ReaderLock lm (lock); + Metrics::iterator i; + TempoSection* prev = 0; + + for (i = metrics->begin(); i != metrics->end(); ++i) { + TempoSection* t; + + if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { + + if ((*i)->frame() > frame) { + break; + } + + prev = t; + } + } + + if (prev == 0) { + fatal << endmsg; + } + + return *prev; +} + const Tempo& TempoMap::tempo_at (nframes_t frame) { @@ -1303,7 +1392,7 @@ TempoMap::set_state (const XMLNode& node) MetricSectionSorter cmp; metrics->sort (cmp); - timestamp_metrics (); + timestamp_metrics (true); } } |