Rework duration clock and TempoMap::insert_time to include meter at offset.
authornick_m <mainsbridge@gmail.com>
Sat, 15 Oct 2016 15:33:49 +0000 (02:33 +1100)
committernick_m <mainsbridge@gmail.com>
Sat, 15 Oct 2016 15:33:49 +0000 (02:33 +1100)
- should fix 7072

- also fixes scroll behavior over multiple tempi.

gtk2_ardour/audio_clock.cc
gtk2_ardour/audio_clock.h
libs/ardour/tempo.cc

index ed81b6db2102d3cf40edd773c88a58a53cf09d89..7e490b4fdcec6f936a051a3f0d301d1b897e111d 100644 (file)
@@ -1003,7 +1003,7 @@ AudioClock::set (framepos_t when, bool force, framecnt_t offset)
                        break;
 
                case BBT:
-                       set_bbt (when, force);
+                       set_bbt (when, offset, force);
                        break;
 
                case MinSec:
@@ -1226,7 +1226,7 @@ AudioClock::set_timecode (framepos_t when, bool /*force*/)
 }
 
 void
-AudioClock::set_bbt (framepos_t when, bool /*force*/)
+AudioClock::set_bbt (framepos_t when, framecnt_t offset, bool /*force*/)
 {
        char buf[16];
        Timecode::BBT_Time BBT;
@@ -1253,9 +1253,58 @@ AudioClock::set_bbt (framepos_t when, bool /*force*/)
                        BBT.beats = 0;
                        BBT.ticks = 0;
                } else {
-                       BBT = _session->tempo_map().bbt_at_frame (when);
-                       BBT.bars--;
-                       BBT.beats--;
+                       TempoMap& tmap (_session->tempo_map());
+                       const double divisions = tmap.meter_section_at_frame (offset).divisions_per_bar();
+
+                       if (negative) {
+                               BBT = tmap.bbt_at_beat (tmap.beat_at_frame (offset));
+                               Timecode::BBT_Time when_bbt = tmap.bbt_at_frame (offset - when);
+
+                               BBT.bars -= when_bbt.bars;
+
+                               if (BBT.ticks < when_bbt.ticks) {
+                                       if (BBT.beats == 1) {
+                                               BBT.bars--;
+                                               BBT.beats = divisions;
+                                       } else {
+                                               BBT.beats--;
+                                       }
+                                       BBT.ticks = Timecode::BBT_Time::ticks_per_beat - (when_bbt.ticks - BBT.ticks);
+                               } else {
+                                       BBT.ticks -= when_bbt.ticks;
+                               }
+
+                               if (BBT.beats < when_bbt.beats) {
+                                       BBT.bars--;
+                                       BBT.beats = divisions - (when_bbt.beats - BBT.beats);
+                               } else {
+                                       BBT.beats -= when_bbt.beats;
+                               }
+                       } else {
+                               BBT = tmap.bbt_at_beat (tmap.beat_at_frame (when + offset));
+                               Timecode::BBT_Time when_bbt = tmap.bbt_at_frame (offset);
+
+                               BBT.bars -= when_bbt.bars;
+
+                               if (BBT.ticks < when_bbt.ticks) {
+                                       if (BBT.beats == 1) {
+                                               BBT.bars--;
+                                               BBT.beats = divisions;
+                                       } else {
+                                               BBT.beats--;
+                                       }
+                                       BBT.ticks = Timecode::BBT_Time::ticks_per_beat - (when_bbt.ticks - BBT.ticks);
+                               } else {
+                                       BBT.ticks -= when_bbt.ticks;
+                               }
+
+                               if (BBT.beats < when_bbt.beats) {
+                                       BBT.bars--;
+                                       BBT.beats = divisions - (when_bbt.beats - BBT.beats);
+                               } else {
+                                       BBT.beats -= when_bbt.beats;
+                               }
+                       }
                }
        } else {
                BBT = _session->tempo_map().bbt_at_frame (when);
@@ -1732,7 +1781,7 @@ AudioClock::on_scroll_event (GdkEventScroll *ev)
        switch (ev->direction) {
 
        case GDK_SCROLL_UP:
-               frames = get_frame_step (f);
+               frames = get_frame_step (f, current_time(), 1);
                if (frames != 0) {
                        if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
                                frames *= 10;
@@ -1743,7 +1792,7 @@ AudioClock::on_scroll_event (GdkEventScroll *ev)
                break;
 
        case GDK_SCROLL_DOWN:
-               frames = get_frame_step (f);
+               frames = get_frame_step (f, current_time(), -1);
                if (frames != 0) {
                        if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
                                frames *= 10;
index 51cac850a0199305f40296167eebb6fd0508eed4..79d05f62fead72d182abd5db80ba1edad3e792ac 100644 (file)
@@ -209,7 +209,7 @@ class AudioClock : public CairoWidget, public ARDOUR::SessionHandlePtr
 
        void set_slave_info ();
        void set_timecode (framepos_t, bool);
-       void set_bbt (framepos_t, bool);
+       void set_bbt (framepos_t, ARDOUR::framecnt_t, bool);
        void set_minsec (framepos_t, bool);
        void set_frames (framepos_t, bool);
 
index 27ba9f62232a31eebae054bfa1ea698438d5abd9..1d6f4eccf2404d67ead68ea1481bb4a943f26dc1 100644 (file)
@@ -3192,11 +3192,52 @@ TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
-       const double tick_at_time = max (0.0, beat_at_frame_locked (_metrics, pos)) * BBT_Time::ticks_per_beat;
-       const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
-       const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
+       BBT_Time pos_bbt = bbt_at_frame_locked (_metrics, pos);
+       const framecnt_t offset = frame_at_bbt_locked (_metrics, pos_bbt);
+       const double divisions = meter_section_at_frame_locked (_metrics, pos).divisions_per_bar();
 
-       return frame_at_beat_locked (_metrics, total_beats);
+       if (dir > 0) {
+               pos_bbt.bars += bbt.bars;
+
+               pos_bbt.ticks += bbt.ticks;
+               if ((double) pos_bbt.ticks > BBT_Time::ticks_per_beat) {
+                       pos_bbt.beats += 1;
+                       pos_bbt.ticks -= BBT_Time::ticks_per_beat;
+               }
+
+               pos_bbt.beats += bbt.beats;
+               if ((double) pos_bbt.beats > divisions) {
+                       pos_bbt.bars += 1;
+                       pos_bbt.beats -= divisions;
+               }
+
+               return frame_at_bbt_locked (_metrics, pos_bbt) - offset;
+       } else {
+               pos_bbt.bars -= bbt.bars;
+
+               if (pos_bbt.ticks < bbt.ticks) {
+                       if (pos_bbt.beats == 1) {
+                               pos_bbt.bars--;
+                               pos_bbt.beats = divisions;
+                       } else {
+                               pos_bbt.beats--;
+                       }
+                       pos_bbt.ticks = BBT_Time::ticks_per_beat - (bbt.ticks - pos_bbt.ticks);
+               } else {
+                       pos_bbt.ticks -= bbt.ticks;
+               }
+
+               if (pos_bbt.beats <= bbt.beats) {
+                       pos_bbt.bars--;
+                       pos_bbt.beats = divisions - (bbt.beats - pos_bbt.beats);
+               } else {
+                       pos_bbt.beats -= bbt.beats;
+               }
+
+               return offset - frame_at_bbt_locked (_metrics, pos_bbt);
+       }
+
+       return 0;
 }
 
 framepos_t
@@ -3890,129 +3931,24 @@ TempoMap::n_meters() const
 void
 TempoMap::insert_time (framepos_t where, framecnt_t amount)
 {
-       {
-               Glib::Threads::RWLock::WriterLock lm (lock);
-               for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
-                       if ((*i)->frame() >= where && (*i)->movable ()) {
-                               (*i)->set_frame ((*i)->frame() + amount);
-                       }
-               }
-
-               /* now reset the BBT time of all metrics, based on their new
-                * audio time. This is the only place where we do this reverse
-                * timestamp.
-                */
-
-               Metrics::iterator i;
-               const MeterSection* meter;
-               const TempoSection* tempo;
-               MeterSection *m;
-               TempoSection *t;
-
-               meter = &first_meter ();
-               tempo = &first_tempo ();
-
-               BBT_Time start;
-               BBT_Time end;
-
-               // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
-
-               bool first = true;
-               MetricSection* prev = 0;
+       for (Metrics::reverse_iterator i = _metrics.rbegin(); i != _metrics.rend(); ++i) {
+               if ((*i)->frame() >= where && (*i)->movable ()) {
+                       MeterSection* ms;
+                       TempoSection* ts;
 
-               for (i = _metrics.begin(); i != _metrics.end(); ++i) {
-
-                       BBT_Time bbt;
-                       //TempoMetric metric (*meter, *tempo);
-                       MeterSection* ms = const_cast<MeterSection*>(meter);
-                       TempoSection* ts = const_cast<TempoSection*>(tempo);
-                       if (prev) {
-                               if (ts){
-                                       if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
-                                               if (!t->active()) {
-                                                       continue;
-                                               }
-                                               ts->set_pulse (t->pulse());
-                                       }
-                                       if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
-                                               ts->set_pulse (m->pulse());
-                                       }
-                                       ts->set_frame (prev->frame());
-
-                               }
-                               if (ms) {
-                                       if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
-                                               pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
-                                               ms->set_beat (start);
-                                               ms->set_pulse (m->pulse());
-                                       }
-                                       if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
-                                               if (!t->active()) {
-                                                       continue;
-                                               }
-                                               const double beat = beat_at_pulse_locked (_metrics, t->pulse());
-                                               pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
-                                               ms->set_beat (start);
-                                               ms->set_pulse (t->pulse());
-                                       }
-                                       ms->set_frame (prev->frame());
-                               }
-
-                       } else {
-                               // metric will be at frames=0 bbt=1|1|0 by default
-                               // which is correct for our purpose
+                       if ((ms = dynamic_cast <MeterSection*>(*i)) != 0) {
+                               gui_move_meter (ms, (*i)->frame() + amount);
                        }
 
-                       // cerr << bbt << endl;
-
-                       if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
-                               if (!t->active()) {
-                                       continue;
-                               }
-                               t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
-                               tempo = t;
-                               // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
-                       } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
-                               bbt = bbt_at_frame_locked (_metrics, m->frame());
-
-                               // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
-
-                               if (first) {
-                                       first = false;
-                               } else {
-
-                                       if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
-                                               /* round up to next beat */
-                                               bbt.beats += 1;
-                                       }
-
-                                       bbt.ticks = 0;
-
-                                       if (bbt.beats != 1) {
-                                               /* round up to next bar */
-                                               bbt.bars += 1;
-                                               bbt.beats = 1;
-                                       }
-                               }
-                               pair<double, BBT_Time> start = make_pair (max (0.0, beat_at_frame_locked (_metrics, m->frame())), bbt);
-                               m->set_beat (start);
-                               m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
-                               meter = m;
-                               // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
-                       } else {
-                               fatal << _("programming error: unhandled MetricSection type") << endmsg;
-                               abort(); /*NOTREACHED*/
+                       if ((ts = dynamic_cast <TempoSection*>(*i)) != 0) {
+                               gui_move_tempo (ts, (*i)->frame() + amount, 0);
                        }
-
-                       prev = (*i);
                }
-
-               recompute_map (_metrics);
        }
 
-
        PropertyChanged (PropertyChange ());
 }
+
 bool
 TempoMap::remove_time (framepos_t where, framecnt_t amount)
 {