rename MetricSection movable -> initial, but of course initial is !movable..
[ardour.git] / libs / ardour / tempo.cc
index d8cb26d53a3a61f58ef9d56c7dfdb23ec25ac2c4..01f17cf5d0b1bde979f7bd0d46ad67cbc35c625e 100644 (file)
@@ -131,7 +131,7 @@ TempoSection::TempoSection (const XMLNode& node, framecnt_t sample_rate)
        /* XX replace old beats-per-minute name with note-types-per-minute */
        if ((prop = node.property ("beats-per-minute")) != 0) {
                if (sscanf (prop->value().c_str(), "%lf", &_note_types_per_minute) != 1 || _note_types_per_minute < 0.0) {
-                       error << _("TempoSection XML node has an illegal \"beats-per-minutee\" value") << endmsg;
+                       error << _("TempoSection XML node has an illegal \"beats-per-minute\" value") << endmsg;
                        throw failed_constructor();
                }
        }
@@ -151,7 +151,7 @@ TempoSection::TempoSection (const XMLNode& node, framecnt_t sample_rate)
                throw failed_constructor();
        }
 
-       set_movable (string_is_affirmative (prop->value()));
+       set_initial (!string_is_affirmative (prop->value()));
 
        if ((prop = node.property ("active")) == 0) {
                warning << _("TempoSection XML node has no \"active\" property") << endmsg;
@@ -167,7 +167,7 @@ TempoSection::TempoSection (const XMLNode& node, framecnt_t sample_rate)
        }
 
        if ((prop = node.property ("lock-style")) == 0) {
-               if (movable()) {
+               if (!initial()) {
                        set_position_lock_style (MusicTime);
                } else {
                        set_position_lock_style (AudioTime);
@@ -198,7 +198,7 @@ TempoSection::get_state() const
        root->add_property ("beats-per-minute", buf);
        snprintf (buf, sizeof (buf), "%lf", _note_type);
        root->add_property ("note-type", buf);
-       snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
+       snprintf (buf, sizeof (buf), "%s", !initial()?"yes":"no");
        root->add_property ("movable", buf);
        snprintf (buf, sizeof (buf), "%s", active()?"yes":"no");
        root->add_property ("active", buf);
@@ -237,12 +237,11 @@ TempoSection::tempo_at_minute (const double& m) const
  *
 */
 
-/** user feedback dictates that if tempoA (120, 4.0) precedes tempoB (120, 8.0),
- *  there will be no ramp between the two even if set to ramped.
+/** if tempoA (120, 4.0) precedes tempoB (120, 8.0),
+ *  there should be no ramp between the two even if we are ramped.
  *  in other words a ramp should only place a curve on note_types_per_minute.
  *  we should be able to use Tempo note type here, but the above
  *  complicates things a bit.
- *  we would ideally like to use arbitrary Tempo structs here.
 */
 double
 TempoSection::minute_at_ntpm (const double& ntpm, const double& p) const
@@ -311,6 +310,12 @@ TempoSection::minute_at_pulse (const double& p) const
        return _time_at_pulse (p - pulse()) + minute();
 }
 
+/** returns thw whole-note pulse at session frame position f.
+ *  @param f the frame position.
+ *  @return the position in whole-note pulses corresponding to f
+ *
+ *  for use with musical units whose granularity is coarser than frames (e.g. ticks)
+*/
 double
 TempoSection::pulse_at_frame (const framepos_t& f) const
 {
@@ -577,11 +582,11 @@ MeterSection::MeterSection (const XMLNode& node, const framecnt_t sample_rate)
                throw failed_constructor();
        }
 
-       set_movable (string_is_affirmative (prop->value()));
+       set_initial (!string_is_affirmative (prop->value()));
 
        if ((prop = node.property ("lock-style")) == 0) {
                warning << _("MeterSection XML node has no \"lock-style\" property") << endmsg;
-               if (movable()) {
+               if (!initial()) {
                        set_position_lock_style (MusicTime);
                } else {
                        set_position_lock_style (AudioTime);
@@ -614,7 +619,7 @@ MeterSection::get_state() const
        root->add_property ("lock-style", enum_2_string (position_lock_style()));
        snprintf (buf, sizeof (buf), "%lf", _divisions_per_bar);
        root->add_property ("divisions-per-bar", buf);
-       snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
+       snprintf (buf, sizeof (buf), "%s", !initial()?"yes":"no");
        root->add_property ("movable", buf);
 
        return *root;
@@ -722,8 +727,8 @@ TempoMap::TempoMap (framecnt_t fr)
        TempoSection *t = new TempoSection (0.0, 0.0, _default_tempo.note_types_per_minute(), _default_tempo.note_type(), TempoSection::Ramp, AudioTime, fr);
        MeterSection *m = new MeterSection (0.0, 0.0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime, fr);
 
-       t->set_movable (false);
-       m->set_movable (false);
+       t->set_initial (true);
+       m->set_initial (true);
 
        /* note: frame time is correct (zero) for both of these */
 
@@ -781,7 +786,7 @@ TempoMap::remove_tempo_locked (const TempoSection& tempo)
        for (i = _metrics.begin(); i != _metrics.end(); ++i) {
                if (dynamic_cast<TempoSection*> (*i) != 0) {
                        if (tempo.frame() == (*i)->frame()) {
-                               if ((*i)->movable()) {
+                               if (!(*i)->initial()) {
                                        delete (*i);
                                        _metrics.erase (i);
                                        return true;
@@ -833,7 +838,7 @@ TempoMap::remove_meter_locked (const MeterSection& meter)
        for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
                if (dynamic_cast<MeterSection*> (*i) != 0) {
                        if (meter.frame() == (*i)->frame()) {
-                               if ((*i)->movable()) {
+                               if (!(*i)->initial()) {
                                        delete (*i);
                                        _metrics.erase (i);
                                        return true;
@@ -887,7 +892,7 @@ TempoMap::do_insert (MetricSection* section)
                        bool const ipm = insert_tempo->position_lock_style() == MusicTime;
                        if ((ipm && tempo->pulse() == insert_tempo->pulse()) || (!ipm && tempo->frame() == insert_tempo->frame())) {
 
-                               if (!tempo->movable()) {
+                               if (tempo->initial()) {
 
                                        /* can't (re)move this section, so overwrite
                                         * its data content (but not its properties as
@@ -916,7 +921,7 @@ TempoMap::do_insert (MetricSection* section)
 
                        if ((ipm && meter->beat() == insert_meter->beat()) || (!ipm && meter->frame() == insert_meter->frame())) {
 
-                               if (!meter->movable()) {
+                               if (meter->initial()) {
 
                                        /* can't (re)move this section, so overwrite
                                         * its data content (but not its properties as
@@ -1070,7 +1075,7 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T
                Glib::Threads::RWLock::WriterLock lm (lock);
                const double beat = beat_at_bbt_locked (_metrics, where);
 
-               if (ms.movable()) {
+               if (!ms.initial()) {
                        remove_meter_locked (ms);
                        add_meter_locked (meter, beat, where, pls, true);
                } else {
@@ -1261,7 +1266,7 @@ TempoMap::first_tempo () const
                        if (!t->active()) {
                                continue;
                        }
-                       if (!t->movable()) {
+                       if (t->initial()) {
                                return *t;
                        }
                }
@@ -1282,7 +1287,7 @@ TempoMap::first_tempo ()
                        if (!t->active()) {
                                continue;
                        }
-                       if (!t->movable()) {
+                       if (t->initial()) {
                                return *t;
                        }
                }
@@ -1305,7 +1310,7 @@ TempoMap::recompute_tempi (Metrics& metrics)
                        if (!t->active()) {
                                continue;
                        }
-                       if (!t->movable()) {
+                       if (t->initial()) {
                                if (!prev_t) {
                                        t->set_pulse (0.0);
                                        prev_t = t;
@@ -1328,6 +1333,7 @@ TempoMap::recompute_tempi (Metrics& metrics)
                        prev_t = t;
                }
        }
+       assert (prev_t);
        prev_t->set_c_func (0.0);
 }
 
@@ -1353,7 +1359,7 @@ TempoMap::recompute_meters (Metrics& metrics)
                                        TempoSection* t;
                                        if ((*ii)->is_tempo()) {
                                                t = static_cast<TempoSection*> (*ii);
-                                               if ((t->locked_to_meter() || !t->movable()) && t->frame() == meter->frame()) {
+                                               if ((t->locked_to_meter() || t->initial()) && t->frame() == meter->frame()) {
                                                        meter_locked_tempo = t;
                                                        break;
                                                }
@@ -1361,14 +1367,16 @@ TempoMap::recompute_meters (Metrics& metrics)
                                }
 
                                if (prev_m) {
-                                       const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
+                                       double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
                                        if (beats + prev_m->beat() != meter->beat()) {
                                                /* reordering caused a bbt change */
+
+                                               beats = meter->beat() - prev_m->beat();
                                                b_bbt = make_pair (beats + prev_m->beat()
                                                                   , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
                                                pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
 
-                                       } else if (meter->movable()) {
+                                       } else if (!meter->initial()) {
                                                b_bbt = make_pair (meter->beat(), meter->bbt());
                                                pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
                                        }
@@ -1565,6 +1573,7 @@ TempoMap::minute_at_beat_locked (const Metrics& metrics, const double& beat) con
                        prev_m = m;
                }
        }
+       assert (prev_m);
 
        TempoSection* t;
 
@@ -1578,6 +1587,7 @@ TempoMap::minute_at_beat_locked (const Metrics& metrics, const double& beat) con
                }
 
        }
+       assert (prev_t);
 
        return prev_t->minute_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse());
 }
@@ -1795,6 +1805,7 @@ TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) con
                        prev_m = m;
                }
        }
+       assert (prev_m);
 
        double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
        return ret;
@@ -1941,6 +1952,7 @@ TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
                        prev_m = m;
                }
        }
+       assert (prev_m);
 
        const double beats_in_ms = beats - prev_m->beat();
        const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
@@ -2078,6 +2090,8 @@ TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) cons
                }
        }
 
+       assert (prev_m);
+
        const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
        const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
        const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
@@ -2314,7 +2328,7 @@ TempoMap::minute_at_quarter_note_locked (const Metrics& metrics, const double qu
  *
  */
 double
-TempoMap::quarter_note_at_beat (const double beat)
+TempoMap::quarter_note_at_beat (const double beat) const
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
@@ -2339,7 +2353,7 @@ TempoMap::quarter_note_at_beat_locked (const Metrics& metrics, const double beat
  *
  */
 double
-TempoMap::beat_at_quarter_note (const double quarter_note)
+TempoMap::beat_at_quarter_note (const double quarter_note) const
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
@@ -2407,6 +2421,7 @@ TempoMap::quarter_notes_between_frames_locked (const Metrics& metrics, const fra
                        prev_t = t;
                }
        }
+       assert (prev_t);
        const double start_qn = prev_t->pulse_at_frame (start);
 
        for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
@@ -2493,16 +2508,16 @@ TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
                TempoSection* t;
                if ((*i)->is_tempo()) {
                        t = static_cast<TempoSection*> (*i);
-                       if (!t->movable()) {
+                       if (t->initial()) {
                                t->set_active (true);
                                continue;
                        }
-                       if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
+                       if (!t->initial() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
                                t->set_active (false);
                                t->set_pulse (0.0);
-                       } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
+                       } else if (!t->initial() && t->position_lock_style() == AudioTime && t->frame() > frame) {
                                t->set_active (true);
-                       } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
+                       } else if (!t->initial() && t->position_lock_style() == AudioTime && t->frame() == frame) {
                                return false;
                        }
                }
@@ -2522,13 +2537,13 @@ TempoMap::solve_map_minute (Metrics& imaginary, TempoSection* section, const dou
                MeterSection* m;
                if (!(*i)->is_tempo()) {
                        m = static_cast<MeterSection*> (*i);
-                       if (!m->movable()) {
+                       if (m->initial()) {
                                first_m_minute = m->minute();
                                break;
                        }
                }
        }
-       if (section->movable() && minute <= first_m_minute) {
+       if (!section->initial() && minute <= first_m_minute) {
                return false;
        }
 
@@ -2609,7 +2624,7 @@ TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const doub
                        if (!t->active()) {
                                continue;
                        }
-                       if (!t->movable()) {
+                       if (t->initial()) {
                                t->set_pulse (0.0);
                                prev_t = t;
                                continue;
@@ -2672,13 +2687,13 @@ TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const doub
 bool
 TempoMap::solve_map_minute (Metrics& imaginary, MeterSection* section, const double& minute)
 {
-       /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
+       /* disallow moving first meter past any subsequent one, and any initial meter before the first one */
        const MeterSection* other =  &meter_section_at_minute_locked (imaginary, minute);
-       if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->minute() >= minute)) {
+       if ((section->initial() && !other->initial()) || (other->initial() && !section->initial() && other->minute() >= minute)) {
                return false;
        }
 
-       if (!section->movable()) {
+       if (section->initial()) {
                /* lock the first tempo to our first meter */
                if (!set_active_tempos (imaginary, section->frame_at_minute (minute))) {
                        return false;
@@ -2691,7 +2706,7 @@ TempoMap::solve_map_minute (Metrics& imaginary, MeterSection* section, const dou
                TempoSection* t;
                if ((*ii)->is_tempo()) {
                        t = static_cast<TempoSection*> (*ii);
-                       if ((t->locked_to_meter() || !t->movable()) && t->minute() == section->minute()) {
+                       if ((t->locked_to_meter() || t->initial()) && t->minute() == section->minute()) {
                                meter_locked_tempo = t;
                                break;
                        }
@@ -2712,7 +2727,7 @@ TempoMap::solve_map_minute (Metrics& imaginary, MeterSection* section, const dou
                if (!(*i)->is_tempo()) {
                        m = static_cast<MeterSection*> (*i);
                        if (m == section){
-                               if (prev_m && section->movable()) {
+                               if (prev_m && !section->initial()) {
                                        const double beats = (pulse_at_minute_locked (imaginary, minute) - prev_m->pulse()) * prev_m->note_divisor();
                                        if (beats + prev_m->beat() < section->beat()) {
                                                /* set the section pulse according to its musical position,
@@ -2774,7 +2789,7 @@ TempoMap::solve_map_minute (Metrics& imaginary, MeterSection* section, const dou
                                                }
                                        }
                                } else {
-                                       /* not movable (first meter atm) */
+                                       /* initial (first meter atm) */
 
                                        tempo_copy->set_minute (minute);
                                        tempo_copy->set_pulse (0.0);
@@ -2839,11 +2854,17 @@ TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Ti
                MeterSection* m;
                if (!(*i)->is_tempo()) {
                        m = static_cast<MeterSection*> (*i);
+
+                       if (m == section) {
+                               continue;
+                       }
+
                        pair<double, BBT_Time> b_bbt;
                        double new_pulse = 0.0;
 
                        if (prev_m && m->bbt().bars > when.bars && !section_prev){
                                section_prev = prev_m;
+
                                const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
                                const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
                                pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
@@ -2852,7 +2873,6 @@ TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Ti
                                section->set_pulse (pulse);
                                section->set_minute (minute_at_pulse_locked (imaginary, pulse));
                                prev_m = section;
-                               continue;
                        }
 
                        if (m->position_lock_style() == AudioTime) {
@@ -2862,7 +2882,7 @@ TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Ti
                                        TempoSection* t;
                                        if ((*ii)->is_tempo()) {
                                                t = static_cast<TempoSection*> (*ii);
-                                               if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
+                                               if ((t->locked_to_meter() || t->initial()) && t->frame() == m->frame()) {
                                                        meter_locked_tempo = t;
                                                        break;
                                                }
@@ -2874,14 +2894,21 @@ TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Ti
                                }
 
                                if (prev_m) {
-                                       const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
+                                       double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
 
                                        if (beats + prev_m->beat() != m->beat()) {
                                                /* tempo/ meter change caused a change in beat (bar). */
+
+                                               /* the user has requested that the previous section of music overlaps this one.
+                                                  we have no choice but to change the bar number here, as being locked to audio means
+                                                  we must stay where we are on the timeline.
+                                               */
+                                               beats = m->beat() - prev_m->beat();
                                                b_bbt = make_pair (beats + prev_m->beat()
                                                                   , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
                                                new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
-                                       } else if (m->movable()) {
+
+                                       } else if (!m->initial()) {
                                                b_bbt = make_pair (m->beat(), m->bbt());
                                                new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
                                        }
@@ -3045,6 +3072,10 @@ TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
 
        const double beat = beat_at_bbt_locked (future_map, bbt);
 
+       if (section->position_lock_style() == AudioTime) {
+               tempo_copy->set_position_lock_style (MusicTime);
+       }
+
        if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
                ret.first = tempo_copy->pulse();
                ret.second = tempo_copy->frame();
@@ -3247,7 +3278,9 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
                TempoSection* prev_to_prev_t = 0;
                const frameoffset_t fr_off = end_frame - frame;
 
-               if (prev_t && prev_t->pulse() > 0.0) {
+               assert (prev_t);
+
+               if (prev_t->pulse() > 0.0) {
                        prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_minute_locked (future_map, minute_at_frame (prev_t->frame() - 1)));
                }
 
@@ -3394,7 +3427,7 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
  * This function is sensitive to tempo and meter.
  */
 double
-TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
+TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num) const
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
@@ -3402,7 +3435,7 @@ TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
 }
 
 double
-TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions)
+TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions) const
 {
        return beat_at_pulse_locked (_metrics, exact_qn_at_frame_locked (metrics, frame, divisions) / 4.0);
 }
@@ -3430,7 +3463,7 @@ TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t&
  * This function is tempo-sensitive.
  */
 double
-TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)
+TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num) const
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
@@ -3438,7 +3471,7 @@ TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)
 }
 
 double
-TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num)
+TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num) const
 {
        double qn = quarter_note_at_minute_locked (metrics, minute_at_frame (frame));
 
@@ -3479,7 +3512,7 @@ TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
        BBT_Time pos_bbt = bbt_at_minute_locked (_metrics, minute_at_frame (pos));
-       const framecnt_t offset = frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
+
        const double divisions = meter_section_at_minute_locked (_metrics, minute_at_frame (pos)).divisions_per_bar();
 
        if (dir > 0) {
@@ -3496,31 +3529,47 @@ TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
                        pos_bbt.bars += 1;
                        pos_bbt.beats -= divisions;
                }
+               const framecnt_t pos_bbt_frame = frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
+
+               return pos_bbt_frame - pos;
 
-               return frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt)) - offset;
        } else {
-               pos_bbt.bars -= bbt.bars;
+
+               if (pos_bbt.bars <= bbt.bars) {
+                       pos_bbt.bars = 1;
+               } else {
+                       pos_bbt.bars -= bbt.bars;
+               }
 
                if (pos_bbt.ticks < bbt.ticks) {
-                       if (pos_bbt.beats == 1) {
-                               pos_bbt.bars--;
-                               pos_bbt.beats = divisions;
+                       if (pos_bbt.bars > 1) {
+                               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.beats--;
+                               pos_bbt.beats = 1;
+                               pos_bbt.ticks = 0;
                        }
-                       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);
+                       if (pos_bbt.bars > 1) {
+                               pos_bbt.bars--;
+                               pos_bbt.beats = divisions - (bbt.beats - pos_bbt.beats);
+                       } else {
+                               pos_bbt.beats = 1;
+                       }
                } else {
                        pos_bbt.beats -= bbt.beats;
                }
 
-               return offset - frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
+               return pos - frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
        }
 
        return 0;
@@ -3914,6 +3963,7 @@ TempoMap::frames_per_quarter_note_at (const framepos_t& frame, const framecnt_t&
                        ts_at = t;
                }
        }
+       assert (ts_at);
 
        if (ts_after) {
                return  (60.0 * _frame_rate) / ts_at->tempo_at_minute (minute_at_frame (frame)).quarter_notes_per_minute();
@@ -4002,7 +4052,7 @@ TempoMap::fix_legacy_session ()
                TempoSection* t;
 
                if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
-                       if (!m->movable()) {
+                       if (m->initial()) {
                                pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
                                m->set_beat (bbt);
                                m->set_pulse (0.0);
@@ -4029,7 +4079,7 @@ TempoMap::fix_legacy_session ()
                                continue;
                        }
 
-                       if (!t->movable()) {
+                       if (t->initial()) {
                                t->set_pulse (0.0);
                                t->set_minute (0.0);
                                t->set_position_lock_style (AudioTime);
@@ -4188,10 +4238,10 @@ TempoMap::dump (const Metrics& metrics, std::ostream& o) const
                if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
                        o << "Tempo @ " << *i << t->note_types_per_minute() << " BPM (pulse = 1/" << t->note_type()
                          << " type= " << enum_2_string (t->type()) << ") "  << " at pulse= " << t->pulse()
-                         << " minute= " << t->minute() << " frame= " << t->frame() << " (movable? " << t->movable() << ')'
+                         << " minute= " << t->minute() << " frame= " << t->frame() << " (initial? " << t->initial() << ')'
                          << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
                        if (prev_t) {
-                               o << std::setprecision (17) << "  current      : " << t->note_types_per_minute()
+                               o <<  "  current      : " << t->note_types_per_minute()
                                  << " | " << t->pulse() << " | " << t->frame() << " | " << t->minute() << std::endl;
                                o << "  previous     : " << prev_t->note_types_per_minute()
                                  << " | " << prev_t->pulse() << " | " << prev_t->frame() << " | " << prev_t->minute() << std::endl;
@@ -4204,7 +4254,7 @@ TempoMap::dump (const Metrics& metrics, std::ostream& o) const
                } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
                        o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt()
                          << " frame= " << m->frame() << " pulse: " << m->pulse() <<  " beat : " << m->beat()
-                         << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
+                         << " pos lock: " << enum_2_string (m->position_lock_style()) << " (initial? " << m->initial() << ')' << endl;
                }
        }
        o << "------" << std::endl;
@@ -4244,7 +4294,7 @@ void
 TempoMap::insert_time (framepos_t where, framecnt_t amount)
 {
        for (Metrics::reverse_iterator i = _metrics.rbegin(); i != _metrics.rend(); ++i) {
-               if ((*i)->frame() >= where && (*i)->movable ()) {
+               if ((*i)->frame() >= where && !(*i)->initial ()) {
                        MeterSection* ms;
                        TempoSection* ts;