Tempo ramps - remove unused code, small meter dilation drag cleanup.
[ardour.git] / libs / ardour / tempo.cc
index 8af5ab3fbebe98621acafd6c896861de51943a11..8c710ad180896a95f7284e9ffb050f37540dc119 100644 (file)
@@ -879,7 +879,7 @@ TempoMap::do_insert (MetricSection* section)
                }
 
                _metrics.insert (i, section);
-               //dump (_metrics, std::cerr);
+               //dump (_metrics, std::cout);
        }
 }
 
@@ -1084,7 +1084,7 @@ TempoMap::add_meter (const Meter& meter, const framepos_t& frame, const double&
 }
 
 MeterSection*
-TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, bool recompute)
+TempoMap::add_meter_locked (const Meter& meter, double beat, const BBT_Time& where, bool recompute)
 {
        /* a new meter always starts a new bar on the first beat. so
           round the start time appropriately. remember that
@@ -1093,14 +1093,9 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
 
        */
 
-       if (where.beats != 1) {
-               where.beats = 1;
-               where.bars++;
-       }
-       /* new meters *always* start on a beat. */
-       where.ticks = 0;
        const double pulse = pulse_at_beat_locked (_metrics, beat);
        MeterSection* new_meter = new MeterSection (pulse, beat, where, meter.divisions_per_bar(), meter.note_divisor());
+
        do_insert (new_meter);
 
        if (recompute) {
@@ -1111,19 +1106,19 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
 }
 
 MeterSection*
-TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, double beat, Timecode::BBT_Time where, bool recompute)
+TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, double beat, const Timecode::BBT_Time& where, bool recompute)
 {
+       /* add meter-locked tempo */
+       TempoSection* t = add_tempo_locked (tempo_at_locked (_metrics, frame), frame, true, TempoSection::Ramp);
+       if (t) {
+               t->set_locked_to_meter (true);
+       }
+
        MeterSection* new_meter = new MeterSection (frame, beat, where, meter.divisions_per_bar(), meter.note_divisor());
-       TempoSection* t = 0;
-       double pulse = pulse_at_frame_locked (_metrics, frame);
-       new_meter->set_pulse (pulse);
+       new_meter->set_pulse (pulse_at_frame_locked (_metrics, frame));
 
        do_insert (new_meter);
 
-       /* add meter-locked tempo */
-       t = add_tempo_locked (tempo_at_locked (_metrics, frame), frame, true, TempoSection::Ramp);
-       t->set_locked_to_meter (true);
-
        if (recompute) {
                solve_map (_metrics, new_meter, frame);
        }
@@ -1365,7 +1360,6 @@ TempoMap::recompute_meters (Metrics& metrics)
                                }
                                if (meter_locked_tempo) {
                                        meter_locked_tempo->set_pulse (pulse);
-                                       recompute_tempos (metrics);
                                }
                                meter->set_beat (b_bbt);
                                meter->set_pulse (pulse);
@@ -1398,7 +1392,6 @@ TempoMap::recompute_meters (Metrics& metrics)
                        prev_m = meter;
                }
        }
-       //dump (_metrics, std::cerr;
 }
 
 void
@@ -2025,8 +2018,6 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const framepos_t
                return true;
        }
 
-       //dump (imaginary, std::cerr);
-
        return false;
 }
 
@@ -2100,8 +2091,6 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const double& pu
                return true;
        }
 
-       //dump (imaginary, std::cerr);
-
        return false;
 }
 
@@ -2261,7 +2250,7 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
        } else {
                recompute_meters (imaginary);
        }
-       //dump (imaginary, std::cerr);
+
        return true;
 }
 
@@ -2272,7 +2261,7 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const BBT_Time&
        for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
                MeterSection* m;
                if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
-                       if (m->bbt().bars == when.bars) {
+                       if (m != section && m->bbt().bars == when.bars) {
                                return false;
                        }
                }
@@ -2368,6 +2357,7 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const BBT_Time&
 
        MetricSectionSorter cmp;
        imaginary.sort (cmp);
+
        if (section->position_lock_style() == AudioTime) {
                /* we're setting the pulse */
                section->set_position_lock_style (MusicTime);
@@ -2563,28 +2553,6 @@ TempoMap::gui_move_tempo_beat (TempoSection* ts, const double& beat)
        MetricPositionChanged (); // Emit Signal
 }
 
-void
-TempoMap::gui_move_tempo_pulse (TempoSection* ts, const double& pulse)
-{
-       Metrics future_map;
-       {
-               Glib::Threads::RWLock::WriterLock lm (lock);
-               TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
-               if (solve_map (future_map, tempo_copy, pulse)) {
-                       solve_map (_metrics, ts, pulse);
-                       recompute_meters (_metrics);
-               }
-       }
-
-       Metrics::const_iterator d = future_map.begin();
-       while (d != future_map.end()) {
-               delete (*d);
-               ++d;
-       }
-
-       MetricPositionChanged (); // Emit Signal
-}
-
 void
 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t&  frame)
 {
@@ -2664,6 +2632,10 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
        Metrics future_map;
        TempoSection* ts = 0;
 
+       if (frame <= first_meter().frame()) {
+               return;
+       }
+
        if (ms->position_lock_style() == AudioTime) {
                /* disabled for now due to faked tempo locked to meter pulse */
                return;
@@ -2688,8 +2660,8 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
                   constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
                */
                double contribution = 0.0;
-               frameoffset_t frame_contribution = 0.0;
-               frameoffset_t prev_t_frame_contribution = 0.0;
+               frameoffset_t frame_contribution = 0;
+               frameoffset_t prev_t_frame_contribution = fr_off;
 
                if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
                        /* prev to prev_t's position will remain constant in terms of frame and pulse. lets use frames. */
@@ -2739,12 +2711,6 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
                                new_bpm = prev_t->tempo_at_frame (prev_t->frame() + fr_off, _frame_rate) * (double) prev_t->note_type();
                        }
 
-                       const double diff = (prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type()) - prev_t->beats_per_minute();
-                       if (diff > -0.1 && diff  < 0.1) {
-                               new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
-                                                                       / (double) ((ms->frame() + prev_t_frame_contribution) - prev_t->frame()));
-                       }
-
                } else if (prev_t->c_func() > 0.0) {
                        if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
                                new_bpm = prev_t->tempo_at_frame (prev_t->frame() - frame_contribution, _frame_rate) * (double) prev_t->note_type();
@@ -2752,13 +2718,13 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
                                /* prev_to_prev_t is irrelevant */
                                new_bpm = prev_t->tempo_at_frame (prev_t->frame() - fr_off, _frame_rate) * (double) prev_t->note_type();
                        }
+               }
 
-                       /* limits - a bit clunky, but meh */
-                       const double diff = (prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type()) - prev_t->beats_per_minute();
-                       if (diff > -0.1 && diff  < 0.1) {
-                               new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
-                                                                       / (double) ((ms->frame() + prev_t_frame_contribution) - prev_t->frame()));
-                       }
+               /* limits - a bit clunky, but meh */
+               const double diff = (prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type()) - prev_t->beats_per_minute();
+               if (diff > -1.0 && diff  < 1.0) {
+                       new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
+                                                               / (double) ((ms->frame() + prev_t_frame_contribution) - prev_t->frame()));
                }
 
                prev_t->set_beats_per_minute (new_bpm);
@@ -2788,6 +2754,129 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
        MetricPositionChanged (); // Emit Signal
 }
 
+void
+TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
+{
+       /*
+         Ts (future prev_t)   Tnext
+         |                    |
+         |     [drag^]        |
+         |----------|----------
+               e_f  pulse(frame)
+       */
+
+       Metrics future_map;
+
+       {
+               Glib::Threads::RWLock::WriterLock lm (lock);
+
+               if (!ts) {
+                       return;
+               }
+
+               TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
+               TempoSection* prev_to_prev_t = 0;
+               const frameoffset_t fr_off = end_frame - frame;
+
+               if (prev_t && prev_t->pulse() > 0.0) {
+                       prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, prev_t->frame() - 1));
+               }
+
+               TempoSection* next_t = 0;
+               for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
+                       TempoSection* t = 0;
+                       if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+                               if (t->frame() > ts->frame()) {
+                                       next_t = t;
+                                       break;
+                               }
+                       }
+               }
+
+               /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
+                  constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
+               */
+               double contribution = 0.0;
+               double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
+
+               if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+                       contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
+               }
+
+               frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
+               double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
+               double new_bpm;
+
+               if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
+
+                       if (prev_t->position_lock_style() == MusicTime) {
+                               if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+
+                                       new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
+                                                                               / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
+
+                               } else {
+                                       /* prev to prev is irrelevant */
+
+                                       if (start_pulse != prev_t->pulse()) {
+                                               new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
+                                       } else {
+                                               new_bpm = prev_t->beats_per_minute();
+                                       }
+                               }
+                       } else {
+                               /* AudioTime */
+                               if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+                                       new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
+                                                                               / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
+                               } else {
+                                       /* prev_to_prev_t is irrelevant */
+
+                                       if (end_frame != prev_t->frame()) {
+                                               new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
+                                       } else {
+                                               new_bpm = prev_t->beats_per_minute();
+                                       }
+                               }
+                       }
+               } else {
+
+                       double frame_ratio;
+                       double pulse_ratio;
+                       const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
+
+                       if (prev_to_prev_t) {
+
+                               frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
+                               pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
+                       } else {
+
+                               frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
+                               pulse_ratio = (start_pulse / end_pulse);
+                       }
+                       new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
+               }
+
+               prev_t->set_beats_per_minute (new_bpm);
+               recompute_tempos (future_map);
+               recompute_meters (future_map);
+
+               if (check_solved (future_map, true)) {
+                       ts->set_beats_per_minute (new_bpm);
+                       recompute_tempos (_metrics);
+                       recompute_meters (_metrics);
+               }
+       }
+
+       Metrics::const_iterator d = future_map.begin();
+       while (d != future_map.end()) {
+               delete (*d);
+               ++d;
+       }
+
+       MetricPositionChanged (); // Emit Signal
+}
+
 framecnt_t
 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
 {