Tempo ramps - change some prototypes, rename some methods.
[ardour.git] / libs / ardour / tempo.cc
index d03a1721e942338bbf24c89792fd29681555154f..5463d8539b2064565b728a4c1707f1ddb11f4570 100644 (file)
 #include <unistd.h>
 
 #include <glibmm/threads.h>
+
+#include "pbd/enumwriter.h"
 #include "pbd/xml++.h"
 #include "evoral/Beats.hpp"
+
 #include "ardour/debug.h"
 #include "ardour/lmath.h"
 #include "ardour/tempo.h"
@@ -71,26 +74,43 @@ Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
 const string TempoSection::xml_state_node_name = "Tempo";
 
 TempoSection::TempoSection (const XMLNode& node)
-       : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo())
+       : MetricSection (0.0), Tempo (TempoMap::default_tempo())
 {
        const XMLProperty *prop;
-       BBT_Time start;
        LocaleGuard lg;
-
-       if ((prop = node.property ("start")) == 0) {
-               error << _("TempoSection XML node has no \"start\" property") << endmsg;
-               throw failed_constructor();
+       BBT_Time bbt;
+       double beat;
+       uint32_t frame;
+
+       if ((prop = node.property ("start")) != 0) {
+               if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
+                           &bbt.bars,
+                           &bbt.beats,
+                           &bbt.ticks) == 3) {
+                       /* legacy session - start used to be in bbt*/
+                       _legacy_bbt = bbt;
+                       beat = -1.0;
+                       set_beat (beat);
+               }
+       } else {
+               warning << _("TempoSection XML node has no \"start\" property") << endmsg;
        }
 
-       if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
-                   &start.bars,
-                   &start.beats,
-                   &start.ticks) < 3) {
-               error << _("TempoSection XML node has an illegal \"start\" value") << endmsg;
-               throw failed_constructor();
-       }
 
-       set_start (start);
+       if ((prop = node.property ("beat")) != 0) {
+               if (sscanf (prop->value().c_str(), "%lf", &beat) != 1 || beat < 0.0) {
+                       error << _("TempoSection XML node has an illegal \"beat\" value") << endmsg;
+               } else {
+                       set_beat (beat);
+               }
+       }
+       if ((prop = node.property ("frame")) != 0) {
+               if (sscanf (prop->value().c_str(), "%" PRIu32, &frame) != 1) {
+                       error << _("TempoSection XML node has an illegal \"frame\" value") << endmsg;
+               } else {
+                       set_frame (frame);
+               }
+       }
 
        if ((prop = node.property ("beats-per-minute")) == 0) {
                error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
@@ -129,13 +149,15 @@ TempoSection::TempoSection (const XMLNode& node)
        }
 
        if ((prop = node.property ("tempo-type")) == 0) {
-               _type = Type::Constant;
+               _type = Constant;
        } else {
-               if (strstr(prop->value().c_str(),"Constant")) {
-                       _type = Type::Constant;
-               } else {
-                       _type = Type::Ramp;
-               }
+               _type = Type (string_2_enum (prop->value(), _type));
+       }
+
+       if ((prop = node.property ("lock-style")) == 0) {
+               set_position_lock_style (MusicTime);
+       } else {
+               set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
        }
 }
 
@@ -146,11 +168,10 @@ TempoSection::get_state() const
        char buf[256];
        LocaleGuard lg;
 
-       snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
-                 start().bars,
-                 start().beats,
-                 start().ticks);
-       root->add_property ("start", buf);
+       snprintf (buf, sizeof (buf), "%f", beat());
+       root->add_property ("beat", buf);
+       snprintf (buf, sizeof (buf), "%li", frame());
+       root->add_property ("frame", buf);
        snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
        root->add_property ("beats-per-minute", buf);
        snprintf (buf, sizeof (buf), "%f", _note_type);
@@ -159,9 +180,8 @@ TempoSection::get_state() const
        // root->add_property ("bar-offset", buf);
        snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
        root->add_property ("movable", buf);
-
-       snprintf (buf, sizeof (buf), "%s", _type == Constant?"Constant":"Ramp");
-       root->add_property ("tempo-type", buf);
+       root->add_property ("tempo-type", enum_2_string (_type));
+       root->add_property ("lock-style", enum_2_string (position_lock_style()));
 
        return *root;
 }
@@ -170,10 +190,10 @@ void
 
 TempoSection::update_bar_offset_from_bbt (const Meter& m)
 {
-       _bar_offset = ((start().beats - 1) * BBT_Time::ticks_per_beat + start().ticks) /
+       _bar_offset = (beat() * BBT_Time::ticks_per_beat) /
                (m.divisions_per_bar() * BBT_Time::ticks_per_beat);
 
-       DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, start(), m.divisions_per_bar()));
+       DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, beat(), m.divisions_per_bar()));
 }
 
 void
@@ -182,61 +202,197 @@ TempoSection::set_type (Type type)
        _type = type;
 }
 
+/** returns the tempo at the zero-based (relative to session) frame.
+*/
 double
-TempoSection::tempo_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
+TempoSection::tempo_at_frame (framepos_t f, framecnt_t frame_rate) const
 {
 
        if (_type == Constant) {
                return beats_per_minute();
        }
 
-       return tick_tempo_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)) / BBT_Time::ticks_per_beat;
+       return tick_tempo_at_time (frame_to_minute (f - frame(), frame_rate)) / BBT_Time::ticks_per_beat;
 }
 
+/** returns the zero-based frame (relative to session)
+   where the tempo occurs in this section.
+   beat b is only used for constant tempos.
+   note that the tempo map may have multiple such values.
+*/
 framepos_t
-TempoSection::frame_at_tempo (double tempo, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
+TempoSection::frame_at_tempo (double bpm, double b, framecnt_t frame_rate) const
 {
        if (_type == Constant) {
-               return 0;
+               return ((b - beat())  * frames_per_beat (frame_rate))  + frame();
+       }
+
+       return minute_to_frame (time_at_tick_tempo (bpm *  BBT_Time::ticks_per_beat), frame_rate) + frame();
+}
+/** returns the tempo at the zero-based (relative to session) beat.
+*/
+double
+TempoSection::tempo_at_beat (double b) const
+{
+
+       if (_type == Constant) {
+               return beats_per_minute();
        }
 
-       return minute_to_frame (time_at_tick_tempo (tempo *  BBT_Time::ticks_per_beat,  end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
+       return tick_tempo_at_tick ((b - beat()) * BBT_Time::ticks_per_beat) / BBT_Time::ticks_per_beat;
+}
+
+/** returns the zero-based beat (relative to session)
+   where the tempo occurs given frame f. frame f is only used for constant tempos.
+   note that the session tempo map may have multiple beats at a given tempo.
+*/
+double
+TempoSection::beat_at_tempo (double bpm, framepos_t f, framecnt_t frame_rate) const
+{
+       if (_type == Constant) {
+               double const ticks = (((f - frame()) / frames_per_beat (frame_rate)) * BBT_Time::ticks_per_beat) + tick();
+               return ticks / BBT_Time::ticks_per_beat;
+       }
+
+       return (tick_at_tick_tempo (bpm *  BBT_Time::ticks_per_beat) + tick()) / BBT_Time::ticks_per_beat;
+}
+
+/** returns the zero-based beat (relative to session origin)
+   where the zero-based frame (relative to session)
+   lies.
+*/
+double
+TempoSection::beat_at_frame (framepos_t frame, framecnt_t frame_rate) const
+{
+       return tick_at_frame (frame, frame_rate) / BBT_Time::ticks_per_beat;
 }
 
+/** returns the zero-based frame (relative to session start frame)
+   where the zero-based beat (relative to session start)
+   falls.
+*/
+
+framepos_t
+TempoSection::frame_at_beat (double beat, framecnt_t frame_rate) const
+{
+       return frame_at_tick (beat * BBT_Time::ticks_per_beat, frame_rate);
+}
+
+/** returns the zero-based tick (relative to session origin)
+   where the zero-based frame (relative to tempo section)
+   lies.
+*/
 double
-TempoSection::tick_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
+TempoSection::tick_at_frame (framepos_t f, framecnt_t frame_rate) const
 {
        if (_type == Constant) {
-               return (frame / frames_per_beat (frame_rate)) * BBT_Time::ticks_per_beat;
+               return (((f - frame()) / frames_per_beat (frame_rate)) * BBT_Time::ticks_per_beat) + tick();
        }
 
-       return tick_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate));
+       return tick_at_time (frame_to_minute (f - frame(), frame_rate)) + tick();
 }
 
+/** returns the zero-based frame (relative to session origin)
+   where the zero-based tick (relative to session)
+   falls.
+*/
 framepos_t
-TempoSection::frame_at_tick (double tick, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
+TempoSection::frame_at_tick (double t, framecnt_t frame_rate) const
 {
        if (_type == Constant) {
-               return (framepos_t) floor ((tick  / BBT_Time::ticks_per_beat) * frames_per_beat (frame_rate));
+               return (framepos_t) floor (((t - tick()) / BBT_Time::ticks_per_beat) * frames_per_beat (frame_rate)) + frame();
        }
 
-       return minute_to_frame (time_at_tick (tick, end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
+       return minute_to_frame (time_at_tick (t - tick()), frame_rate) + frame();
 }
 
-double TempoSection::beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
+/*
+Ramp Overview
+
+      |                     *
+Tempo |                   *
+Tt----|-----------------*|
+Ta----|--------------|*  |
+      |            * |   |
+      |         *    |   |
+      |     *        |   |
+T0----|*             |   |
+  *   |              |   |
+      _______________|___|____
+      time           a   t (next tempo)
+      [        c         ] defines c
+
+Duration in beats at time a is the integral of some Tempo function.
+In our case, the Tempo function (Tempo at time t) is
+T(t) = T0(e^(ct))
+
+with function constant
+c = log(Ta/T0)/a
+so
+a = log(Ta/T0)/c
+
+The integral over t of our Tempo function (the beat function, which is the duration in beats at some time t) is:
+b(t) = T0(e^(ct) - 1) / c
+
+To find the time t at beat duration b, we use the inverse function of the beat function (the time function) which can be shown to be:
+t(b) = log((cb / T0) + 1) / c
+
+The time t at which Tempo T occurs is a as above:
+t(T) = log(T / T0) / c
+
+The beat at which a Tempo T occurs is:
+b(T) = (T - T0) / c
+
+The Tempo at which beat b occurs is:
+T(b) = b.c + T0
+
+We define c for this tempo ramp by placing a new tempo section at some time t after this one.
+Our problem is that we usually don't know t.
+We almost always know the duration in beats between this and the new section, so we need to find c in terms of the beat function.
+Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
+t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
+
+By substituting our expanded t as a in the c function above, our problem is reduced to:
+c = T0 (e^(log (Ta / T0)) - 1) / b
+
+We can now store c for future time calculations.
+If the following tempo section (the one that defines c in conjunction with this one)
+is changed or moved, c is no longer valid.
+
+The public methods are session-relative.
+
+Most of this stuff is taken from this paper:
+
+WHERE’S THE BEAT?
+TOOLS FOR DYNAMIC TEMPO CALCULATIONS
+Jan C. Schacher
+Martin Neukom
+Zurich University of Arts
+Institute for Computer Music and Sound Technology
+
+https://www.zhdk.ch/fileadmin/data_subsites/data_icst/Downloads/Timegrid/ICST_Tempopolyphony_ICMC07.pdf
+
+*/
+
+/* set this ramp's function constant using the end tempo and duration (beats into global start) of some later tempo section*/
+void
+TempoSection::set_c_func_from_tempo_and_beat (double end_bpm, double end_beat, framecnt_t frame_rate)
 {
-       return tick_at_frame (frame, end_bpm, end_frame, frame_rate) / BBT_Time::ticks_per_beat;
+       double const log_tempo_ratio = log ((end_bpm * BBT_Time::ticks_per_beat) / ticks_per_minute());
+       _c_func = ticks_per_minute() *  (exp (log_tempo_ratio) - 1) / ((end_beat - beat()) * BBT_Time::ticks_per_beat);
 }
 
-framepos_t TempoSection::frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
+/* compute the function constant from some later tempo section, given tempo (beats/min.) and distance (in frames) from session origin */
+double
+TempoSection::compute_c_func (double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
 {
-       return frame_at_tick (beat * BBT_Time::ticks_per_beat, end_bpm, end_frame, frame_rate);
+       return c_func (end_bpm * BBT_Time::ticks_per_beat, frame_to_minute (end_frame - frame(), frame_rate));
 }
 
 framecnt_t
 TempoSection::minute_to_frame (double time, framecnt_t frame_rate) const
 {
-       return time * 60.0 * frame_rate;
+       return (framecnt_t) floor ((time * 60.0 * frame_rate));
 }
 
 double
@@ -245,12 +401,14 @@ TempoSection::frame_to_minute (framecnt_t frame, framecnt_t frame_rate) const
        return (frame / (double) frame_rate) / 60.0;
 }
 
-/* constant for exp */
+/* position function */
 double
-TempoSection::a_func (double begin_tpm, double end_tpm, double end_time) const
+TempoSection::a_func (double end_tpm, double c_func) const
 {
-       return log (end_tpm / ticks_per_minute()) /  c_func (end_tpm, end_time);
+       return log (end_tpm / ticks_per_minute()) /  c_func;
 }
+
+/*function constant*/
 double
 TempoSection::c_func (double end_tpm, double end_time) const
 {
@@ -259,110 +417,154 @@ TempoSection::c_func (double end_tpm, double end_time) const
 
 /* tempo in tpm at time in minutes */
 double
-TempoSection::tick_tempo_at_time (double time, double end_tpm, double end_time) const
+TempoSection::tick_tempo_at_time (double time) const
 {
-       return exp (c_func (end_tpm, end_time) * time) * ticks_per_minute();
+       return exp (_c_func * time) * ticks_per_minute();
 }
 
 /* time in minutes at tempo in tpm */
 double
-TempoSection::time_at_tick_tempo (double tick_tempo, double end_tpm, double end_time) const
+TempoSection::time_at_tick_tempo (double tick_tempo) const
 {
-       return log (tick_tempo / ticks_per_minute()) / c_func (end_tpm, end_time);
+       return log (tick_tempo / ticks_per_minute()) / _c_func;
 }
 
-/* tempo in bpm at time in minutes */
+/* tick at tempo in tpm */
 double
-TempoSection::tempo_at_time (double time, double end_bpm, double end_time) const
+TempoSection::tick_at_tick_tempo (double tick_tempo) const
 {
-       return tick_tempo_at_time (time, end_bpm *  BBT_Time::ticks_per_beat, end_time) / BBT_Time::ticks_per_beat;
+       return (tick_tempo - ticks_per_minute()) / _c_func;
 }
 
-/* time in minutes at tempo in bpm */
+/* tempo in tpm at tick */
 double
-TempoSection::time_at_tempo (double tempo, double end_bpm, double end_time) const
+TempoSection::tick_tempo_at_tick (double tick) const
 {
-       return time_at_tick_tempo (tempo * BBT_Time::ticks_per_beat, end_bpm * BBT_Time::ticks_per_beat, end_time);
+       return (tick * _c_func) + ticks_per_minute();
 }
 
 /* tick at time in minutes */
 double
-TempoSection::tick_at_time (double time, double end_tpm, double end_time) const
+TempoSection::tick_at_time (double time) const
 {
-       return ((exp (c_func (end_tpm, end_time) * time)) - 1) * ticks_per_minute() / c_func (end_tpm, end_time);
+       return ((exp (_c_func * time)) - 1) * ticks_per_minute() / _c_func;
 }
 
 /* time in minutes at tick */
 double
-TempoSection::time_at_tick (double tick, double end_tpm, double end_time) const
+TempoSection::time_at_tick (double tick) const
 {
-       return log (((c_func (end_tpm, end_time) * tick) / ticks_per_minute()) + 1) / c_func (end_tpm, end_time);
+       return log (((_c_func * tick) / ticks_per_minute()) + 1) / _c_func;
 }
 
 /* beat at time in minutes */
 double
-TempoSection::beat_at_time (double time, double end_tpm, double end_time) const
+TempoSection::beat_at_time (double time) const
 {
-       return tick_at_time (time, end_tpm, end_time) / BBT_Time::ticks_per_beat;
+       return tick_at_time (time) / BBT_Time::ticks_per_beat;
 }
 
 /* time in munutes at beat */
 double
-TempoSection::time_at_beat (double beat, double end_tpm, double end_time) const
+TempoSection::time_at_beat (double beat) const
 {
-       return time_at_tick (beat * BBT_Time::ticks_per_beat, end_tpm, end_time);
+       return time_at_tick (beat * BBT_Time::ticks_per_beat);
 }
 
 void
 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
 {
-       BBT_Time new_start;
+       double new_beat;
 
        if (_bar_offset < 0.0) {
                /* not set yet */
                return;
        }
 
-       new_start.bars = start().bars;
+       new_beat = beat();
 
        double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
-       new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat);
-       //new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */
-       new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat);
+       new_beat = ticks / BBT_Time::ticks_per_beat;
 
-       /* remember the 1-based counting properties of beats */
-       new_start.beats += 1;
        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
-                                                      _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
+                                                      _bar_offset, meter.divisions_per_bar(), ticks, new_beat, new_beat));
 
-       set_start (new_start);
+       set_beat (new_beat);
 }
 
 /***********************************************************************/
 
+/*
+if a meter section is position locked to frames, then it can only be at 1|1|0.
+thus we can have multiple 1|1|0s in the session tempo map.
+
+like this:
+
+BBT  1|1|0 2|1|0 3|1|0 1|1|0
+beat   0     4     8    12
+
+all other meter sections are locked to beats.
+
+the beat of a meter section is used to find its position rather than the stored bbt.
+*/
+
 const string MeterSection::xml_state_node_name = "Meter";
 
 MeterSection::MeterSection (const XMLNode& node)
-       : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
+       : MetricSection (0.0), Meter (TempoMap::default_meter())
 {
        XMLProperty const * prop;
        BBT_Time start;
        LocaleGuard lg;
-
-       if ((prop = node.property ("start")) == 0) {
+       const XMLProperty *prop;
+       BBT_Time bbt;
+       double beat = 0.0;
+       framepos_t frame = 0;
+       pair<double, BBT_Time> start;
+
+       if ((prop = node.property ("start")) != 0) {
+               if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
+                   &bbt.bars,
+                   &bbt.beats,
+                   &bbt.ticks) < 3) {
+                       error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
+               } else {
+                       /* legacy session - start used to be in bbt*/
+                       beat = -1.0;
+               }
+       } else {
                error << _("MeterSection XML node has no \"start\" property") << endmsg;
-               throw failed_constructor();
        }
 
-       if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
-                   &start.bars,
-                   &start.beats,
-                   &start.ticks) < 3) {
-               error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
-               throw failed_constructor();
+       if ((prop = node.property ("beat")) != 0) {
+               if (sscanf (prop->value().c_str(), "%lf", &beat) != 1 || beat < 0.0) {
+                       error << _("MeterSection XML node has an illegal \"beat\" value") << endmsg;
+               }
        }
 
-       set_start (start);
+       start.first = beat;
+
+       if ((prop = node.property ("bbt")) == 0) {
+               error << _("MeterSection XML node has no \"bbt\" property") << endmsg;
+       } else if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
+                   &bbt.bars,
+                   &bbt.beats,
+                   &bbt.ticks) < 3) {
+               error << _("MeterSection XML node has an illegal \"bbt\" value") << endmsg;
+               //throw failed_constructor();
+       }
+
+       start.second = bbt;
+
+       set_beat (start);
+
+       if ((prop = node.property ("frame")) != 0) {
+               if (sscanf (prop->value().c_str(), "%li", &frame) != 1) {
+                       error << _("MeterSection XML node has an illegal \"frame\" value") << endmsg;
+               } else {
+                       set_frame (frame);
+               }
+       }
 
        /* beats-per-bar is old; divisions-per-bar is new */
 
@@ -372,9 +574,8 @@ MeterSection::MeterSection (const XMLNode& node)
                        throw failed_constructor();
                }
        }
-
        if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
-               error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
+               error << _("MeterSection XML node has an illegal \"divisions-per-bar\" value") << endmsg;
                throw failed_constructor();
        }
 
@@ -382,12 +583,18 @@ MeterSection::MeterSection (const XMLNode& node)
                error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
                throw failed_constructor();
        }
-
        if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
                error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
                throw failed_constructor();
        }
 
+       if ((prop = node.property ("lock-style")) == 0) {
+               warning << _("MeterSection XML node has no \"lock-style\" property") << endmsg;
+               set_position_lock_style (MusicTime);
+       } else {
+               set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
+       }
+
        if ((prop = node.property ("movable")) == 0) {
                error << _("MeterSection XML node has no \"movable\" property") << endmsg;
                throw failed_constructor();
@@ -404,12 +611,17 @@ MeterSection::get_state() const
        LocaleGuard lg;
 
        snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
-                 start().bars,
-                 start().beats,
-                 start().ticks);
-       root->add_property ("start", buf);
+                 bbt().bars,
+                 bbt().beats,
+                 bbt().ticks);
+       root->add_property ("bbt", buf);
+       snprintf (buf, sizeof (buf), "%lf", beat());
+       root->add_property ("beat", buf);
        snprintf (buf, sizeof (buf), "%f", _note_type);
        root->add_property ("note-type", buf);
+       snprintf (buf, sizeof (buf), "%li", frame());
+       root->add_property ("frame", buf);
+       root->add_property ("lock-style", enum_2_string (position_lock_style()));
        snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
        root->add_property ("divisions-per-bar", buf);
        snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
@@ -422,21 +634,23 @@ MeterSection::get_state() const
 
 struct MetricSectionSorter {
     bool operator() (const MetricSection* a, const MetricSection* b) {
-           return a->start() < b->start();
+           return a->beat() < b->beat();
+    }
+};
+
+struct MetricSectionFrameSorter {
+    bool operator() (const MetricSection* a, const MetricSection* b) {
+           return a->frame() < b->frame();
     }
 };
 
 TempoMap::TempoMap (framecnt_t fr)
 {
        _frame_rate = fr;
-       BBT_Time start;
+       BBT_Time start (1, 1, 0);
 
-       start.bars = 1;
-       start.beats = 1;
-       start.ticks = 0;
-
-       TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Type::Ramp);
-       MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
+       TempoSection *t = new TempoSection (0.0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Constant);
+       MeterSection *m = new MeterSection (0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
 
        t->set_movable (false);
        m->set_movable (false);
@@ -533,33 +747,25 @@ TempoMap::do_insert (MetricSection* section)
 {
        bool need_add = true;
 
-       assert (section->start().ticks == 0);
-
        /* we only allow new meters to be inserted on beat 1 of an existing
         * measure.
         */
+       MeterSection* m = 0;
+       if ((m = dynamic_cast<MeterSection*>(section)) != 0) {
+               assert (m->bbt().ticks == 0);
 
-       if (dynamic_cast<MeterSection*>(section)) {
-
-               /* we need to (potentially) update the BBT times of tempo
-                  sections based on this new meter.
-               */
-
-               if ((section->start().beats != 1) || (section->start().ticks != 0)) {
-
-                       BBT_Time corrected = section->start();
-                       corrected.beats = 1;
-                       corrected.ticks = 0;
+               if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) {
 
+                       pair<double, BBT_Time> corrected = make_pair (m->beat(), m->bbt());
+                       corrected.second.beats = 1;
+                       corrected.second.ticks = 0;
+                       corrected.first = bbt_to_beats_locked (corrected.second);
                        warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
-                                                  section->start(), corrected) << endmsg;
-
-                       section->set_start (corrected);
+                                                  m->bbt(), corrected.second) << endmsg;
+                       m->set_beat (corrected);
                }
        }
 
-
-
        /* Look for any existing MetricSection that is of the same type and
           in the same bar as the new one, and remove it before adding
           the new one. Note that this means that if we find a matching,
@@ -569,24 +775,23 @@ TempoMap::do_insert (MetricSection* section)
 
        for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
 
-               bool const iter_is_tempo = dynamic_cast<TempoSection*> (*i) != 0;
-               bool const insert_is_tempo = dynamic_cast<TempoSection*> (section) != 0;
+               TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
+               TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
 
-               if (iter_is_tempo && insert_is_tempo) {
+               if (tempo && insert_tempo) {
 
                        /* Tempo sections */
+                       PositionLockStyle const ipl = insert_tempo->position_lock_style();
+                       if ((ipl == MusicTime && tempo->beat() == insert_tempo->beat()) || (ipl == AudioTime && tempo->frame() == insert_tempo->frame())) {
 
-                       if ((*i)->start().bars == section->start().bars &&
-                           (*i)->start().beats == section->start().beats) {
-
-                               if (!(*i)->movable()) {
+                               if (!tempo->movable()) {
 
                                        /* can't (re)move this section, so overwrite
                                         * its data content (but not its properties as
                                         * a section).
                                         */
 
-                                       *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(section));
+                                       *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(insert_tempo));
                                        need_add = false;
                                } else {
                                        metrics.erase (i);
@@ -594,20 +799,23 @@ TempoMap::do_insert (MetricSection* section)
                                break;
                        }
 
-               } else if (!iter_is_tempo && !insert_is_tempo) {
+               } else if (!tempo && !insert_tempo) {
 
                        /* Meter Sections */
+                       MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
+                       MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
+                       PositionLockStyle const ipl = insert_meter->position_lock_style();
 
-                       if ((*i)->start().bars == section->start().bars) {
+                       if ((ipl == MusicTime && meter->beat() == insert_meter->beat()) || (ipl == AudioTime && meter->frame() == insert_meter->frame())) {
 
-                               if (!(*i)->movable()) {
+                               if (!meter->movable()) {
 
                                        /* can't (re)move this section, so overwrite
                                         * its data content (but not its properties as
                                         * a section
                                         */
 
-                                       *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(section));
+                                       *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter));
                                        need_add = false;
                                } else {
                                        metrics.erase (i);
@@ -626,27 +834,129 @@ TempoMap::do_insert (MetricSection* section)
         */
 
        if (need_add) {
+               MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
+               TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
 
                Metrics::iterator i;
-
-               for (i = metrics.begin(); i != metrics.end(); ++i) {
-                       if ((*i)->start() > section->start()) {
-                               break;
+               if (insert_meter) {
+                       for (i = metrics.begin(); i != metrics.end(); ++i) {
+                               MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
+
+                               if (meter) {
+                                       PositionLockStyle const ipl = insert_meter->position_lock_style();
+                                       if ((ipl == MusicTime && meter->beat() > insert_meter->beat()) || (ipl == AudioTime && meter->frame() > insert_meter->frame())) {
+                                               break;
+                                       }
+                               }
+                       }
+               } else if (insert_tempo) {
+                       for (i = metrics.begin(); i != metrics.end(); ++i) {
+                               TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
+
+                               if (tempo) {
+                                       PositionLockStyle const ipl = insert_tempo->position_lock_style();
+                                       if ((ipl == MusicTime && tempo->beat() > insert_tempo->beat()) || (ipl == AudioTime && tempo->frame() > insert_tempo->frame())) {
+                                               break;
+                                       }
+                               }
                        }
                }
 
                metrics.insert (i, section);
+               //dump (std::cerr);
        }
 }
 
+/**
+* This is for a gui that needs to know the frame of a beat if a tempo section were to be moved or altered.
+* It actually alters tha ramps up to the beat parameter, so calling this commits you to replacing the section immediately.
+* It will not emit a signal or recompute the map, as you probably want to replace the tempo or do somethig else before that happens.
+* @param section - the section you want to alter
+* @param bpm - the new tempo
+* @param beat - the beat where the altered tempo will fall
+* @return returns - the position in frames where the new tempo section will lie
+*/
+framepos_t
+TempoMap::compute_replacement_tempo_section (TempoSection* section, const Tempo& bpm, const double& beat)
+{
+       Glib::Threads::RWLock::WriterLock lm (lock);
+
+       TempoSection* prev_ts = 0;
+       TempoSection* t;
+       framepos_t ret = 0;
+       MetricSectionSorter cmp;
+
+       for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
+               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+                       if (prev_ts) {
+                               if (section->beat() == t->beat()) {
+                                       continue;
+                               }
+                               if (t->beat() > beat){
+                                       prev_ts->set_c_func_from_tempo_and_beat (bpm.beats_per_minute(), beat, _frame_rate);
+                                       section->set_beat (beat);
+                                       section->set_frame (prev_ts->frame_at_beat (beat, _frame_rate));
+                                       break;
+                               }
+
+                               if (t->position_lock_style() == MusicTime) {
+                                       prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate);
+                                       t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate));
+                               } else {
+                                       prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate));
+                                       t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate));
+                               }
+                       }
+                       prev_ts = t;
+               }
+       }
+       /* now we do the whole thing again because audio-locked sections will have caused a re-order */
+       prev_ts = 0;
+       metrics.sort (cmp);
+
+       for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
+               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+                       if (prev_ts) {
+                               if (section->beat() == t->beat()) {
+                                       continue;
+                               }
+                               if (t->beat() > beat){
+                                       prev_ts->set_c_func_from_tempo_and_beat (bpm.beats_per_minute(), beat, _frame_rate);
+                                       ret = prev_ts->frame_at_beat (beat, _frame_rate);
+                                       section->set_frame (ret);
+                                       prev_ts = section;
+                                       break;
+                               }
+                               if (t->position_lock_style() == MusicTime) {
+                                       prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate);
+                                       t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate));
+                               } else {
+                                       prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate));
+                                       t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate));
+                               }
+                       }
+                       prev_ts = t;
+               }
+       }
+
+       if (!ret) {
+               prev_ts->set_c_func_from_tempo_and_beat (bpm.beats_per_minute(), beat, _frame_rate);
+               section->set_beat (beat);
+               section->set_frame (prev_ts->frame_at_beat (beat, _frame_rate));
+
+               ret = prev_ts->frame_at_beat (beat, _frame_rate);
+       }
+
+       return ret;
+}
+
 void
-TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where, TempoSection::Type type)
+TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& where, TempoSection::Type type)
 {
        {
                Glib::Threads::RWLock::WriterLock lm (lock);
                TempoSection& first (first_tempo());
-
-               if (ts.start() != first.start()) {
+               if (ts.beat() != first.beat()) {
                        remove_tempo_locked (ts);
                        add_tempo_locked (tempo, where, true, type);
                } else {
@@ -663,75 +973,222 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_T
 }
 
 void
-TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame)
+TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const framepos_t& frame, TempoSection::Type type)
 {
        {
+               Glib::Threads::RWLock::WriterLock lm (lock);
                TempoSection& first (first_tempo());
-
-               if (ts.start() != first.start()) {
-                       BBT_Time bbt;
-                       bbt_time (frame, bbt);
+               if (ts.beat() != first.beat()) {
+                       remove_tempo_locked (ts);
+                       add_tempo_locked (tempo, frame, true, type);
+               } else {
+                       first.set_type (type);
                        {
-                               Glib::Threads::RWLock::WriterLock lm (lock);
-                               ts.set_frame (frame);
-                               ts.set_start (bbt);
-
+                               /* cannot move the first tempo section */
+                               *static_cast<Tempo*>(&first) = tempo;
                                recompute_map (false);
                        }
                }
        }
 
-       MetricPositionChanged (); // Emit Signal
+       PropertyChanged (PropertyChange ());
+}
+
+Metrics
+TempoMap::get_new_order (TempoSection* section, const Tempo& bpm, const framepos_t& frame, const double& beat)
+{
+       Metrics imaginary (metrics);
+
+       TempoSection* prev_ts = 0;
+       TempoSection* t;
+
+       /*set frame and sort */
+       section->set_frame (frame);
+       MetricSectionFrameSorter fcmp;
+       imaginary.sort (fcmp);
+
+       /* recompute */
+       for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
+               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+                       if (prev_ts) {
+                               if (t == section) {
+                                       /* we have already set the frame - set the beat */
+                                       prev_ts->set_c_func (prev_ts->compute_c_func (bpm.beats_per_minute(), frame, _frame_rate));
+                                       //section->set_beat (prev_ts->beat_at_frame (frame, _frame_rate));
+                                       section->set_beat (prev_ts->beat_at_tempo (bpm.beats_per_minute(), frame, _frame_rate));
+                                       prev_ts = t;
+                                       continue;
+                               }
+                               if (t->position_lock_style() == MusicTime) {
+                                       prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate);
+                                       //t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate));
+                                       t->set_frame (prev_ts->frame_at_tempo (t->beats_per_minute(), t->beat(), _frame_rate));
+                               } else {
+                                       prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate));
+                                       //t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate));
+                                       t->set_beat (prev_ts->beat_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate));
+                               }
+                       }
+                       prev_ts = t;
+               }
+       }
+       MetricSectionSorter cmp;
+       imaginary.sort (cmp);
+       /* to do - check precision using _at_tempo() methods */
+/*
+       prev_ts = 0;
+       std::cerr << "dumping imaginary order ------" << std::endl;;
+       for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
+               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+                       if (prev_ts) {
+
+                               std::cerr << t->beats_per_minute() << " | " << t->beat() << " | " << t->frame() << std::endl;
+                               std::cerr << prev_ts->beats_per_minute() << " | " << prev_ts->beat() << " | " << prev_ts->frame() << std::endl;
+                               std::cerr << t->beats_per_minute() << " | " << prev_ts->beat_at_tempo (t->beats_per_minute()) << " | " << prev_ts->tempo_at_beat(t->beat()) << " | " << prev_ts->frame_at_tempo(t->beats_per_minute(), _frame_rate) << std::endl;
+                               std::cerr << "   ------" << std::endl;;
+
+                       }
+                       prev_ts = t;
+               }
+       }
+       std::cerr << "end dump ------";
+*/
+       return imaginary;
+}
+
+Metrics
+TempoMap::get_new_order(MeterSection* section, const Meter& mt, const framepos_t& frame, const double& beat)
+{
+       /* incomplete */
+       Metrics imaginary (metrics);
+
+       MeterSection* prev_ms = 0;
+       MeterSection* m;
+       MeterSection* our_section = 0;
+       framepos_t ret = 0;
+       MetricSectionSorter cmp;
+
+       for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
+               if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
+                       if (prev_ms) {
+                               if (section->beat() == m->beat()) {
+                                       our_section = m;
+                                       continue;
+                               }
+                               if (beat < m->beat()){
+                                       pair<double, BBT_Time> b_bbt = make_pair (beat, BBT_Time (1, 1, 0));
+                                       our_section->set_beat (b_bbt);
+                                       our_section->set_frame (frame_at_beat_locked (beat));
+                                       break;
+                               }
+
+                               if (m->position_lock_style() == MusicTime) {
+                                       m->set_frame (frame_at_beat_locked (m->beat()));
+                               } else {
+                                       pair<double, BBT_Time> b_bbt = make_pair (beat_at_frame_locked (m->frame()), BBT_Time (1, 1, 0));
+                                       m->set_beat (b_bbt);
+                               }
+                       }
+                       prev_ms = m;
+               }
+       }
+       /* now we do the whole thing again because audio-locked sections will have caused a re-order */
+       prev_ms = 0;
+       metrics.sort (cmp);
+
+       for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
+               if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
+                       if (prev_ms) {
+                               if (section->beat() == m->beat()) {
+                                       continue;
+                               }
+                               if (beat < m->beat()){
+                                       ret = frame_at_beat (beat);
+                                       section->set_frame (ret);
+                                       prev_ms = section;
+                                       break;
+                               }
+                               if (m->position_lock_style() == MusicTime) {
+                                       m->set_frame (frame_at_beat (m->beat()));
+                               } else {
+                                       pair<double, BBT_Time> b_bbt = make_pair (beat_at_frame_locked (m->frame()), BBT_Time (1, 1, 0));
+                                       m->set_beat (b_bbt);
+                               }
+                       }
+                       prev_ms = m;
+               }
+       }
+
+       if (!ret) {
+               pair<double, BBT_Time> b_bbt = make_pair (beat, BBT_Time (1, 1, 0));
+               section->set_beat (b_bbt);
+               section->set_frame (frame_at_beat_locked (beat));
+       }
+       return imaginary;
 }
 
 void
-TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::Type type)
+TempoMap::gui_move_tempo (TempoSection* ts,  const Tempo& bpm, const framepos_t& frame, const double& beat_where)
 {
        {
                Glib::Threads::RWLock::WriterLock lm (lock);
-               add_tempo_locked (tempo, where, true, type);
+               Metrics new_order = get_new_order (ts, bpm, frame, beat_where);
+
+               metrics.clear();
+               metrics = new_order;
+               recompute_map (false);
        }
 
+       MetricPositionChanged (); // Emit Signal
+}
 
-       PropertyChanged (PropertyChange ());
+void
+TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const framepos_t& frame, const double&  beat_where)
+{
+       Glib::Threads::RWLock::WriterLock lm (lock);
+       Metrics imaginary = get_new_order (ms, mt, frame, beat_where);
 }
 
 void
-TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute, ARDOUR::TempoSection::Type type)
+TempoMap::add_tempo (const Tempo& tempo, double where, ARDOUR::TempoSection::Type type)
 {
-       /* new tempos always start on a beat */
-       where.ticks = 0;
-       TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
+       {
+               Glib::Threads::RWLock::WriterLock lm (lock);
+               add_tempo_locked (tempo, where, true, type);
+       }
 
-       /* find the meter to use to set the bar offset of this
-        * tempo section.
-        */
 
-       const Meter* meter = &first_meter();
+       PropertyChanged (PropertyChange ());
+}
 
-       /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
-          at something, because we insert the default tempo and meter during
-          TempoMap construction.
+void
+TempoMap::add_tempo (const Tempo& tempo, framepos_t frame, ARDOUR::TempoSection::Type type)
+{
+       {
+               Glib::Threads::RWLock::WriterLock lm (lock);
+               add_tempo_locked (tempo, frame, true, type);
+       }
 
-          now see if we can find better candidates.
-       */
 
-       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+       PropertyChanged (PropertyChange ());
+}
 
-               const MeterSection* m;
+void
+TempoMap::add_tempo_locked (const Tempo& tempo, double where, bool recompute, ARDOUR::TempoSection::Type type)
+{
+       TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
 
-               if (where < (*i)->start()) {
-                       break;
-               }
+       do_insert (ts);
 
-               if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
-                       meter = m;
-               }
+       if (recompute) {
+               recompute_map (false);
        }
+}
 
-       ts->update_bar_offset_from_bbt (*meter);
-
-       /* and insert it */
+void
+TempoMap::add_tempo_locked (const Tempo& tempo, framepos_t frame, bool recompute, ARDOUR::TempoSection::Type type)
+{
+       TempoSection* ts = new TempoSection (frame, tempo.beats_per_minute(), tempo.note_type(), type);
 
        do_insert (ts);
 
@@ -746,10 +1203,28 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T
        {
                Glib::Threads::RWLock::WriterLock lm (lock);
                MeterSection& first (first_meter());
+               if (ms.beat() != first.beat()) {
+                       remove_meter_locked (ms);
+                       add_meter_locked (meter, bbt_to_beats_locked (where), where, true);
+               } else {
+                       /* cannot move the first meter section */
+                       *static_cast<Meter*>(&first) = meter;
+                       recompute_map (true);
+               }
+       }
+
+       PropertyChanged (PropertyChange ());
+}
 
-               if (ms.start() != first.start()) {
+void
+TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const framepos_t& frame)
+{
+       {
+               Glib::Threads::RWLock::WriterLock lm (lock);
+               MeterSection& first (first_meter());
+               if (ms.beat() != first.beat()) {
                        remove_meter_locked (ms);
-                       add_meter_locked (meter, where, true);
+                       add_meter_locked (meter, frame, true);
                } else {
                        /* cannot move the first meter section */
                        *static_cast<Meter*>(&first) = meter;
@@ -760,12 +1235,13 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T
        PropertyChanged (PropertyChange ());
 }
 
+
 void
-TempoMap::add_meter (const Meter& meter, BBT_Time where)
+TempoMap::add_meter (const Meter& meter, double beat, BBT_Time where)
 {
        {
                Glib::Threads::RWLock::WriterLock lm (lock);
-               add_meter_locked (meter, where, true);
+               add_meter_locked (meter, beat, where, true);
        }
 
 
@@ -779,7 +1255,25 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where)
 }
 
 void
-TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute)
+TempoMap::add_meter (const Meter& meter, framepos_t frame)
+{
+       {
+               Glib::Threads::RWLock::WriterLock lm (lock);
+               add_meter_locked (meter, frame, true);
+       }
+
+
+#ifndef NDEBUG
+       if (DEBUG_ENABLED(DEBUG::TempoMap)) {
+               dump (std::cerr);
+       }
+#endif
+
+       PropertyChanged (PropertyChange ());
+}
+
+void
+TempoMap::add_meter_locked (const Meter& meter, double beat, 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
@@ -796,7 +1290,20 @@ TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute)
        /* new meters *always* start on a beat. */
        where.ticks = 0;
 
-       do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
+       do_insert (new MeterSection (beat, where, meter.divisions_per_bar(), meter.note_divisor()));
+
+       if (recompute) {
+               recompute_map (true);
+       }
+
+}
+
+void
+TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, bool recompute)
+{
+
+       /* MusicTime meters always start on 1|1|0. */
+       do_insert (new MeterSection (frame, meter.divisions_per_bar(), meter.note_divisor()));
 
        if (recompute) {
                recompute_map (true);
@@ -929,15 +1436,78 @@ TempoMap::first_tempo ()
 {
        TempoSection *t = 0;
 
-       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
-               if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
-                       return *t;
+       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+               if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
+                       return *t;
+               }
+       }
+
+       fatal << _("programming error: no tempo section in tempo map!") << endmsg;
+       abort(); /*NOTREACHED*/
+       return *t;
+}
+void
+TempoMap::recompute_tempos ()
+{
+       TempoSection* prev_ts = 0;
+
+       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+               TempoSection* t;
+
+               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+                       if (prev_ts) {
+                               if (t->position_lock_style() == AudioTime) {
+                                       if (prev_ts->type() == TempoSection::Ramp) {
+                                               prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame(), _frame_rate));
+                                               //t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate));
+                                               t->set_beat (prev_ts->beat_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate));
+                                       } else {
+                                               prev_ts->set_c_func (0.0);
+                                               //t->set_beat (prev_ts->beat_at_frame (t->frame(), _frame_rate));
+                                               t->set_beat (prev_ts->beat_at_tempo (t->beats_per_minute(), t->frame(), _frame_rate));
+                                       }
+                               } else {
+                                       if (prev_ts->type() == TempoSection::Ramp) {
+                                               prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat(), _frame_rate);
+                                               //t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate));
+                                               t->set_frame (prev_ts->frame_at_tempo (t->beats_per_minute(), t->beat(), _frame_rate));
+                                       } else {
+                                               prev_ts->set_c_func (0.0);
+                                               //t->set_frame (prev_ts->frame_at_beat (t->beat(), _frame_rate));
+                                               t->set_frame (prev_ts->frame_at_tempo (t->beats_per_minute(), t->beat(), _frame_rate));
+                                       }
+                               }
+                       }
+                       prev_ts = t;
+               }
+       }
+}
+
+void
+TempoMap::recompute_meters ()
+{
+       MeterSection* meter = 0;
+
+       for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
+               /* Now we have the tempos mapped to position, set meter positions.*/
+               if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
+                       if (meter->position_lock_style() == AudioTime) {
+                               /* a frame based meter has to have a 1|1|0 bbt */
+                               pair<double, BBT_Time> pr;
+                               BBT_Time where;
+
+                               where.bars = 1;
+                               where.beats = 1;
+                               where.ticks = 0;
+
+                               pr.first = beat_at_frame_locked (meter->frame());
+                               pr.second = where;
+                               meter->set_beat (pr);
+                       } else {
+                               meter->set_frame (frame_at_tick_locked (meter->tick()));
+                       }
                }
        }
-
-       fatal << _("programming error: no tempo section in tempo map!") << endmsg;
-       abort(); /*NOTREACHED*/
-       return *t;
 }
 
 void
@@ -945,12 +1515,6 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
 {
        /* CALLER MUST HOLD WRITE LOCK */
 
-       MeterSection* meter = 0;
-       TempoSection* tempo = 0;
-       double current_frame;
-       BBT_Time current;
-       Metrics::iterator next_metric;
-
        if (end < 0) {
 
                /* we will actually stop once we hit
@@ -962,152 +1526,14 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
 
        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
 
-       for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
-               MeterSection* ms;
-
-               if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
-                       meter = ms;
-                       break;
-               }
-       }
-
-       assert(meter);
-
-       for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
-               TempoSection* ts;
-
-               if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
-                       tempo = ts;
-                       break;
-               }
-       }
-
-       assert(tempo);
-
-       /* assumes that the first meter & tempo are at frame zero */
-       current_frame = 0;
-       meter->set_frame (0);
-       tempo->set_frame (0);
-
-       /* assumes that the first meter & tempo are at 1|1|0 */
-       current.bars = 1;
-       current.beats = 1;
-       current.ticks = 0;
-       if (reassign_tempo_bbt) {
-
-               MeterSection* rmeter = meter;
-
-               DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
-
-               for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
-
-                       TempoSection* ts;
-                       MeterSection* ms;
-
-                       if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
-
-                               /* reassign the BBT time of this tempo section
-                                * based on its bar offset position.
-                                */
-
-                               ts->update_bbt_time_from_bar_offset (*rmeter);
-
-                       } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
-                               rmeter = ms;
-                       } else {
-                               fatal << _("programming error: unhandled MetricSection type") << endmsg;
-                               abort(); /*NOTREACHED*/
-                       }
-               }
-       }
-
-       DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo)));
-
-       next_metric = metrics.begin();
-       ++next_metric; // skip meter (or tempo)
-       ++next_metric; // skip tempo (or meter)
-
-       DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
-
        if (end == 0) {
                /* silly call from Session::process() during startup
                 */
                return;
        }
 
-       _extend_map (tempo, meter, next_metric, current, current_frame, end);
-}
-
-void
-TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
-                      Metrics::iterator next_metric,
-                      BBT_Time current, framepos_t current_frame, framepos_t end)
-{
-       /* CALLER MUST HOLD WRITE LOCK */
-
-       uint32_t first_tick_in_new_meter = 0;
-       Metrics::const_iterator i;
-       Metrics::const_iterator mi;
-
-       TempoSection* prev_ts = tempo;
-
-       for (mi = metrics.begin(); mi != metrics.end(); ++mi) {
-               MeterSection* m = 0;
-
-               if ((m = dynamic_cast<MeterSection*> (*mi)) != 0) {
-
-                       if (m->start() >= prev_ts->start()) {
-                               first_tick_in_new_meter = ((((m->start().bars - 1) * meter->divisions_per_bar()) + (m->start().beats - 1)) * BBT_Time::ticks_per_beat) + m->start().ticks; // expressed in ticks from the previous meter
-                               for (i = metrics.begin(); i != metrics.end(); ++i) {
-                                       TempoSection* t;
-
-                                       if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
-
-                                               if (t->start() >= m->start() && t->start() > prev_ts->start()) {
-                                                       //cerr << "new ts start bars = " << t->start().bars << " beats = " << t->start().beats << " ticks = " << t->start().ticks << endl;
-                                                       //cerr << "prev ts start bars = " << prev_ts->start().bars << " beats = " << prev_ts->start().beats << " ticks = " << prev_ts->start().ticks << endl;
-
-                                                       /*tempo section (t) lies in the previous meter */
-                                                       double ticks_at_ts = ((((t->start().bars - 1 ) * meter->divisions_per_bar()) + (t->start().beats - 1) )  * BBT_Time::ticks_per_beat) + t->start().ticks;
-                                                       double ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1))  * BBT_Time::ticks_per_beat) + prev_ts->start().ticks;
-                                                       double ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts;
-                                                       /* assume (falsely) that the target tempo is constant */
-                                                       double length_estimate = (ticks_relative_to_prev_ts /  BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
-                                                       if (prev_ts->type() == TempoSection::Type::Constant) {
-                                                               length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate);
-                                                       }
-                                                       cerr<< "initial length extimate = " << length_estimate << " ticks_relative_to_prev_ts " << ticks_relative_to_prev_ts << endl;
-                                                       double system_precision_at_target_tempo =  (_frame_rate / t->ticks_per_minute());
-                                                       cerr << " system_precision_at_target_tempo = " << system_precision_at_target_tempo << endl;
-                                                       double tick_error = system_precision_at_target_tempo + 1.0; // sorry for the wtf
-
-                                                       while (fabs (tick_error) >= system_precision_at_target_tempo) {
-
-                                                               double actual_ticks = prev_ts->tick_at_frame (length_estimate, t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate);
-                                                               tick_error = ticks_relative_to_prev_ts - actual_ticks;
-                                                               length_estimate += (tick_error / BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
-                                                               //cerr << "actual ticks = " << actual_ticks << endl;
-
-                                                               //cerr << "tick error  = " << tick_error << endl;
-                                                       }
-                                                       cerr << "setting t frame to " << length_estimate + prev_ts->frame() << "tick error  = " << tick_error << endl;
-                                                       t->set_frame (length_estimate + prev_ts->frame());
-
-                                                       if (m->start() < t->start() && m->start() == prev_ts->start()) {
-                                                               m->set_frame (prev_ts->frame());
-                                                       } else if (m->start() < t->start() && m->start() > prev_ts->start()) {
-                                                               cerr << "setting m frame to " << prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) << " ticks = " << first_tick_in_new_meter - ticks_at_prev_ts  << endl;
-
-                                                               m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate));
-                                                       }
-                                               }
-                                               prev_ts = t;
-                                       }
-                               }
-                       }
-                       meter = m;
-               }
-       }
+       recompute_tempos();
+       recompute_meters();
 }
 
 
@@ -1139,7 +1565,7 @@ TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
 
        return m;
 }
-
+/* XX meters only */
 TempoMetric
 TempoMap::metric_at (BBT_Time bbt) const
 {
@@ -1154,14 +1580,16 @@ TempoMap::metric_at (BBT_Time bbt) const
        */
 
        for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+               MeterSection* mw;
+               if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) {
+                       BBT_Time section_start (mw->bbt());
 
-               BBT_Time section_start ((*i)->start());
+                       if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
+                               break;
+                       }
 
-               if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
-                       break;
+                       m.set_metric (*i);
                }
-
-               m.set_metric (*i);
        }
 
        return m;
@@ -1179,161 +1607,105 @@ TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
                warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
                return;
        }
-       bbt = beats_to_bbt (beat_at_frame (frame));
+       bbt = beats_to_bbt_locked (beat_at_frame_locked (frame));
 }
 
-int32_t
-TempoMap::bars_in_meter_section (MeterSection* ms) const
+double
+TempoMap::bbt_to_beats (Timecode::BBT_Time bbt)
 {
-       /* YOU MUST HAVE THE READ LOCK */
-       Metrics::const_iterator i;
+       Glib::Threads::RWLock::ReaderLock lm (lock);
+       return bbt_to_beats_locked (bbt);
+}
+
+double
+TempoMap::bbt_to_beats_locked (Timecode::BBT_Time bbt)
+{
+       /* CALLER HOLDS READ LOCK */
 
-       MeterSection* next_ms = 0;
-       const MeterSection* prev_ms = &first_meter();
+       double accumulated_beats = 0.0;
+       double accumulated_bars = 0.0;
+       MeterSection* prev_ms = 0;
 
-       for (i = metrics.begin(); i != metrics.end(); ++i) {
+       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
                MeterSection* m;
                if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
-                       if (ms->frame() < m->frame()) {
-                               next_ms = m;
+                       double bars_to_m = 0.0;
+                       if (prev_ms) {
+                               bars_to_m = (m->beat() - prev_ms->beat()) / prev_ms->divisions_per_bar();
+                       }
+                       if ((bars_to_m + accumulated_bars) > (bbt.bars - 1)) {
                                break;
                        }
+                       if (prev_ms) {
+                               accumulated_beats += m->beat() - prev_ms->beat();
+                               accumulated_bars += bars_to_m;
+                       }
                        prev_ms = m;
                }
        }
-       if (next_ms) {
-               double ticks_at_next = tick_at_frame (next_ms->frame());
-               double ticks_at_prev = tick_at_frame (prev_ms->frame());
-               double ticks_in_meter = ticks_at_next - ticks_at_prev;
 
-               return (int32_t) floor ((ticks_in_meter / BBT_Time::ticks_per_beat) / prev_ms->note_divisor());
-       }
-       return -1;
+       double const remaining_bars = (bbt.bars - 1) - accumulated_bars;
+       double const remaining_bars_in_beats = remaining_bars * prev_ms->divisions_per_bar();
+       double const ret = remaining_bars_in_beats + accumulated_beats + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
+       return ret;
 }
 
 Timecode::BBT_Time
 TempoMap::beats_to_bbt (double beats)
 {
-       /* CALLER HOLDS READ LOCK */
-       BBT_Time ret;
-       MeterSection* prev_ms = &first_meter();
-
-       framecnt_t frame = frame_at_beat (beats);
-       uint32_t cnt = 0;
-
-       if (n_meters() < 2) {
-               uint32_t bars = (uint32_t) floor (beats / prev_ms->note_divisor());
-               double remaining_beats = beats - (bars *  prev_ms->note_divisor());
-               double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
-
-               ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
-               ret.beats = (uint32_t) floor (remaining_beats);
-               ret.bars = bars;
-
-               /* 0 0 0 to 1 1 0 - based mapping*/
-               ++ret.bars;
-               ++ret.beats;
-
-               if (ret.ticks >= BBT_Time::ticks_per_beat) {
-                       ++ret.beats;
-                       ret.ticks -= BBT_Time::ticks_per_beat;
-               }
-
-               if (ret.beats > prev_ms->note_divisor()) {
-                       ++ret.bars;
-                       ret.beats = 1;
-               }
+       Glib::Threads::RWLock::ReaderLock lm (lock);
+       return beats_to_bbt_locked (beats);
+}
 
-               return ret;
-       }
+Timecode::BBT_Time
+TempoMap::beats_to_bbt_locked (double beats)
+{
+       /* CALLER HOLDS READ LOCK */
 
-       uint32_t first_beat_in_meter = 0;
+       MeterSection* prev_ms = 0;
        uint32_t accumulated_bars = 0;
-       Metrics::const_iterator i;
 
-       for (i = metrics.begin(); i != metrics.end(); ++i) {
+       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
                MeterSection* m = 0;
 
                if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
-                       first_beat_in_meter = beat_at_frame (m->frame());
 
-                       if (beats < first_beat_in_meter) {
+                       if (beats < m->beat()) {
                                /* this is the meter after the one our beat is on*/
                                break;
                        }
-                       int32_t const bars_in_ms = bars_in_meter_section (m);
 
-                       if (bars_in_ms > 0) {
-                               accumulated_bars += bars_in_ms;
+                       if (prev_ms) {
+                               /* we need a whole number of bars. */
+                               accumulated_bars += ((m->beat() - prev_ms->beat()) + 1) / prev_ms->divisions_per_bar();
                        }
 
                        prev_ms = m;
-                       ++cnt;
-               }
-       }
-       //cerr << "beats to bbr with beats = " << beats << " first_beat_in_meter =  " << first_beat_in_meter << " accumulated_bars = " << accumulated_bars <<  endl;
-
-       if (beats > first_beat_in_meter) {
-               /* prev_ms is the relevant one here */
-
-               /* now get the ticks at frame */
-               double ticks_at_frame = tick_at_frame (frame);
-
-               /* find the number of ticks at the beginning of the meter section (bar 1)*/
-               double ticks_at_ms = tick_at_frame (prev_ms->frame());
-
-               double beats_used_by_ms = (ticks_at_frame - ticks_at_ms) / BBT_Time::ticks_per_beat;
-
-               uint32_t bars = (uint32_t) floor (beats_used_by_ms / prev_ms->note_divisor());
-               double remaining_beats = beats_used_by_ms - (bars *  prev_ms->note_divisor());
-               double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
-
-               ret.bars = bars + accumulated_bars;
-               ret.beats = (uint32_t) floor (remaining_beats);
-               ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
-
-               /* now ensure we srtart at 1 1 0 */
-               ++ret.bars;
-               ++ret.beats;
-               //cerr << "part 1 ret bars = " << ret.bars << " ret beats = " << ret.beats << " ret ticks = " << ret.ticks << endl;
-               if (ret.ticks >= BBT_Time::ticks_per_beat) {
-                       ++ret.beats;
-                       ret.ticks -= BBT_Time::ticks_per_beat;
                }
-
-               if (ret.beats > prev_ms->note_divisor()) {
-                       ++ret.bars;
-                       ret.beats = 1;
-               }
-
-               return ret;
        }
 
-       /* find the number of ticks at the beginning of the meter section (bar 1)*/
-       double ticks_at_ms = tick_at_frame (prev_ms->frame());
-
-       /* now get the ticks at frame */
-       double ticks_at_frame = tick_at_frame (frame);
+       double const beats_in_ms = beats - prev_ms->beat();
+       uint32_t const bars_in_ms = (uint32_t) floor (beats_in_ms / prev_ms->divisions_per_bar());
+       uint32_t const total_bars = bars_in_ms + accumulated_bars;
+       double const remaining_beats = beats_in_ms - (bars_in_ms * prev_ms->divisions_per_bar());
+       double const remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
 
-       double ticks_within_ms = ticks_at_frame - ticks_at_ms;
-
-       ret.bars = (uint32_t) floor (((ticks_within_ms / BBT_Time::ticks_per_beat) / prev_ms->note_divisor())) + accumulated_bars;
-       uint32_t remaining_ticks = ticks_within_ms - (ret.bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat);
-       ret.beats = (uint32_t) floor (remaining_ticks);
-       remaining_ticks -= ret.beats * BBT_Time::ticks_per_beat;
+       BBT_Time ret;
 
-       /* only round ticks */
        ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
+       ret.beats = (uint32_t) floor (remaining_beats);
+       ret.bars = total_bars;
 
-       /* now ensure we srtart at 1 1 0 */
+       /* 0 0 0 to 1 1 0 - based mapping*/
        ++ret.bars;
        ++ret.beats;
+
        if (ret.ticks >= BBT_Time::ticks_per_beat) {
                ++ret.beats;
                ret.ticks -= BBT_Time::ticks_per_beat;
        }
 
-       if (ret.beats > prev_ms->note_divisor()) {
+       if (ret.beats > prev_ms->divisions_per_bar()) {
                ++ret.bars;
                ret.beats = 1;
        }
@@ -1342,92 +1714,58 @@ TempoMap::beats_to_bbt (double beats)
 }
 
 double
-TempoMap::tick_at_frame (framecnt_t frame) const
+TempoMap::tick_at_frame_locked (framecnt_t frame) const
 {
-       Glib::Threads::RWLock::ReaderLock lm (lock);
+       /* HOLD (at least) THE READER LOCK */
 
-       Metrics::const_iterator i;
-       const TempoSection* prev_ts = &first_tempo();
+       TempoSection* prev_ts = 0;
        double accumulated_ticks = 0.0;
-       uint32_t cnt = 0;
 
-       for (i = metrics.begin(); i != metrics.end(); ++i) {
+       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
                TempoSection* t;
-
                if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
-
-                       if (frame < t->frame()) {
+                       if ((prev_ts) && frame < t->frame()) {
                                /*the previous ts is the one containing the frame */
-
-                               framepos_t time = frame - prev_ts->frame();
-                               framepos_t last_frame = t->frame() - prev_ts->frame();
-                               double last_beats_per_minute = t->beats_per_minute();
-
-                               return prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate) + accumulated_ticks;
-                       }
-
-                       if (cnt > 0 && t->frame() > prev_ts->frame()) {
-                               framepos_t time = t->frame() - prev_ts->frame();
-                               framepos_t last_frame = t->frame() - prev_ts->frame();
-                               double last_beats_per_minute = t->beats_per_minute();
-                               accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate);
+                               return prev_ts->tick_at_frame (frame, _frame_rate);
                        }
 
+                       accumulated_ticks = t->tick();
                        prev_ts = t;
-                       ++cnt;
                }
        }
 
-       /* treated s linear for this ts */
-       framecnt_t frames_in_section = frame - prev_ts->frame();
-       double ticks_in_section = (frames_in_section / prev_ts->frames_per_beat (_frame_rate)) * Timecode::BBT_Time::ticks_per_beat;
+       /* treated as constant for this ts */
+       double const ticks_in_section = ((frame - prev_ts->frame()) / prev_ts->frames_per_beat (_frame_rate)) * Timecode::BBT_Time::ticks_per_beat;
 
        return ticks_in_section + accumulated_ticks;
 
 }
 
 framecnt_t
-TempoMap::frame_at_tick (double tick) const
+TempoMap::frame_at_tick_locked (double tick) const
 {
        /* HOLD THE READER LOCK */
 
+       const TempoSection* prev_ts = 0;
        double accumulated_ticks = 0.0;
-       double accumulated_ticks_to_prev = 0.0;
-
-       const TempoSection* prev_ts =  &first_tempo();
-       uint32_t cnt = 0;
-
-       Metrics::const_iterator i;
 
-       for (i = metrics.begin(); i != metrics.end(); ++i) {
+       for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
                TempoSection* t;
                if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
-
-                       if (cnt > 0 && t->frame() > prev_ts->frame()) {
-                               framepos_t time = t->frame() - prev_ts->frame();
-                               framepos_t last_time = t->frame() - prev_ts->frame();
-                               double last_beats_per_minute = t->beats_per_minute();
-                               accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
-                       }
-
-                       if (tick < accumulated_ticks) {
+                       if (prev_ts && tick < t->tick()) {
                                /* prev_ts is the one affecting us. */
-
-                               double ticks_in_section = tick - accumulated_ticks_to_prev;
-                               framepos_t section_start = prev_ts->frame();
-                               framepos_t last_time = t->frame() - prev_ts->frame();
-                               double last_beats_per_minute = t->beats_per_minute();
-                               return prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start;
+                               return prev_ts->frame_at_tick (tick, _frame_rate);
                        }
-                       accumulated_ticks_to_prev = accumulated_ticks;
 
+                       accumulated_ticks = t->tick();
                        prev_ts = t;
-                       ++cnt;
                }
        }
-       double ticks_in_section = tick - accumulated_ticks_to_prev;
-       double dtime = (ticks_in_section / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
-       framecnt_t ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
+       /* must be treated as constant, irrespective of _type */
+       double const ticks_in_section = tick - accumulated_ticks;
+       double const dtime = (ticks_in_section / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate);
+
+       framecnt_t const ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
 
        return ret;
 }
@@ -1436,16 +1774,27 @@ double
 TempoMap::beat_at_frame (framecnt_t frame) const
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
+       return tick_at_frame_locked (frame) / BBT_Time::ticks_per_beat;
+}
 
-       return tick_at_frame (frame) / BBT_Time::ticks_per_beat;
+double
+TempoMap::beat_at_frame_locked (framecnt_t frame) const
+{
+       return tick_at_frame_locked (frame) / BBT_Time::ticks_per_beat;
 }
 
 framecnt_t
 TempoMap::frame_at_beat (double beat) const
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
+       return frame_at_tick_locked (beat * BBT_Time::ticks_per_beat);
+}
+
+framecnt_t
+TempoMap::frame_at_beat_locked (double beat) const
+{
 
-       return frame_at_tick (beat * BBT_Time::ticks_per_beat);
+       return frame_at_tick_locked (beat * BBT_Time::ticks_per_beat);
 }
 
 framepos_t
@@ -1459,73 +1808,18 @@ TempoMap::frame_time (const BBT_Time& bbt)
        if (bbt.beats < 1) {
                throw std::logic_error ("beats are counted from one");
        }
-
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
-       Metrics::const_iterator i;
-       uint32_t accumulated_bars = 0;
-
-       MeterSection* prev_ms = &first_meter();
-
-       for (i = metrics.begin(); i != metrics.end(); ++i) {
-               MeterSection* m;
-               if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
-                       int32_t const bims = bars_in_meter_section (m);
-
-                       if (bims < 0 || bbt.bars <= (accumulated_bars + bims)) {
-                               break;
-                       }
-                       if (bims > 0 ) {
-                               accumulated_bars += bims;
-                       }
-                       prev_ms = m;
-               }
-       }
-
-       uint32_t remaining_bars = bbt.bars - accumulated_bars - 1; // back to zero - based bars
-       double const ticks_within_prev_taken_by_remaining_bars = remaining_bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat;
-       double const ticks_after_space_used_by_bars = ((bbt.beats - 1) * BBT_Time::ticks_per_beat) + bbt.ticks; // back to zero - based beats
-       double const ticks_target = ticks_within_prev_taken_by_remaining_bars + ticks_after_space_used_by_bars;
-
-       TempoSection* prev_ts = &first_tempo();
-       double accumulated_ticks = 0.0;
-       double accumulated_ticks_to_prev = 0.0;
-
-       uint32_t cnt = 0;
-
-       for (i = metrics.begin(); i != metrics.end(); ++i) {
-               TempoSection* t;
-               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
-                       if (t->frame() < prev_ms->frame()) {
-                               continue;
-                       }
+       return frame_time_locked (bbt);;
+}
 
-                       if (cnt > 0 && t->frame() > prev_ts->frame()) {
-                               /*find the number of ticke in this section */
-                               framepos_t const time = t->frame() - prev_ts->frame();
-                               framepos_t const last_time = t->frame() - prev_ts->frame();
-                               double const last_beats_per_minute = t->beats_per_minute();
-                               accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
-                       }
+framepos_t
+TempoMap::frame_time_locked (const BBT_Time& bbt)
+{
+       /* HOLD THE READER LOCK */
 
-                       if (ticks_target < accumulated_ticks) {
-                               double const ticks_in_section = ticks_target - accumulated_ticks_to_prev;
-                               framepos_t const section_start_time = prev_ts->frame();
-                               framepos_t const last_time = t->frame() - prev_ts->frame();
-                               double const last_beats_per_minute = t->beats_per_minute();
-                               framepos_t const ret = prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start_time;
-                               return ret;
-                       }
-                       accumulated_ticks_to_prev = accumulated_ticks;
-                       prev_ts = t;
-                       ++cnt;
-               }
-       }
+       framepos_t const ret = frame_at_beat_locked (bbt_to_beats_locked (bbt));
 
-       /*treat this ts as constant tempo */
-       double const ticks_in_this_ts = ticks_target - accumulated_ticks_to_prev;
-       double const dtime = (ticks_in_this_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
-       framecnt_t const ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
        return ret;
 }
 
@@ -1533,7 +1827,6 @@ TempoMap::frame_time (const BBT_Time& bbt)
 framecnt_t
 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
 {
-
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
        Metrics::const_iterator i;
@@ -1554,19 +1847,14 @@ TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
                }
        }
        if (first && second) {
-               framepos_t const last_time = second->frame() - first->frame();
-               double const last_beats_per_minute = second->beats_per_minute();
-
-               framepos_t const time = pos - first->frame();
-               double const tick_at_time = first->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
+               double const tick_at_time = first->tick_at_frame (pos, _frame_rate);
                double const bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
+               double const time_at_bbt = first->frame_at_tick (tick_at_time + bbt_ticks, _frame_rate);
 
-               double const time_at_bbt = first->frame_at_tick (tick_at_time + bbt_ticks, last_beats_per_minute, last_time, _frame_rate);
-
-               return time_at_bbt - time;
+               return time_at_bbt - pos;
        }
-
        double const ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
+
        return (framecnt_t) floor ((ticks / BBT_Time::ticks_per_beat) * first->frames_per_beat(_frame_rate));
 }
 
@@ -1587,7 +1875,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
-       uint32_t ticks = (uint32_t) floor (tick_at_frame (fr) + 0.5);
+       uint32_t ticks = (uint32_t) floor (tick_at_frame_locked (fr) + 0.5);
        uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
        uint32_t ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
 
@@ -1673,7 +1961,7 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
                        /* on the subdivision, do nothing */
                }
        }
-       return frame_at_tick ((beats * BBT_Time::ticks_per_beat) + ticks);
+       return frame_at_tick_locked ((beats * BBT_Time::ticks_per_beat) + ticks);
 }
 
 framepos_t
@@ -1681,9 +1969,9 @@ TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
-       double const beat_at_framepos = beat_at_frame (frame);
+       double const beat_at_framepos = beat_at_frame_locked (frame);
 
-       BBT_Time bbt (beats_to_bbt (beat_at_framepos));
+       BBT_Time bbt (beats_to_bbt_locked (beat_at_framepos));
 
        switch (type) {
        case Bar:
@@ -1719,11 +2007,11 @@ TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
 
        case Beat:
                if (dir < 0) {
-                       return frame_at_beat (floor (beat_at_framepos));
+                       return frame_at_beat_locked (floor (beat_at_framepos));
                } else if (dir > 0) {
-                       return frame_at_beat (ceil (beat_at_framepos));
+                       return frame_at_beat_locked (ceil (beat_at_framepos));
                } else {
-                       return frame_at_beat (floor (beat_at_framepos + 0.5));
+                       return frame_at_beat_locked (floor (beat_at_framepos + 0.5));
                }
                break;
        }
@@ -1736,44 +2024,20 @@ TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
                    framepos_t lower, framepos_t upper)
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
-       uint32_t const upper_beat = (uint32_t) floor (beat_at_frame (upper));
-       uint32_t cnt = (uint32_t) ceil (beat_at_frame (lower));
+       uint32_t const upper_beat = (uint32_t) floor (beat_at_frame_locked (upper));
+       uint32_t cnt = (uint32_t) ceil (beat_at_frame_locked (lower));
 
        while (cnt <= upper_beat) {
                framecnt_t const pos = frame_at_beat (cnt);
                MeterSection const meter = meter_section_at (pos);
                Tempo const tempo = tempo_at (pos);
-               BBT_Time const bbt = beats_to_bbt ((double) cnt);
+               BBT_Time const bbt = beats_to_bbt_locked ((double) cnt);
 
                points.push_back (BBTPoint (meter, tempo, pos, bbt.bars, bbt.beats));
                ++cnt;
        }
 }
 
-TempoSection*
-TempoMap::tempo_section_after (framepos_t frame) const
-{
-       Glib::Threads::RWLock::ReaderLock lm (lock);
-
-       Metrics::const_iterator i;
-       TempoSection* next = 0;
-
-       for (i = metrics.begin(); i != metrics.end(); ++i) {
-               TempoSection* t;
-
-               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
-
-                       if ((*i)->frame() > frame) {
-                               next = t;
-                               break;
-                       }
-               }
-       }
-
-       return next;
-}
-
-
 const TempoSection&
 TempoMap::tempo_section_at (framepos_t frame) const
 {
@@ -1812,10 +2076,23 @@ TempoMap::frames_per_beat_at (framepos_t frame, framecnt_t sr) const
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
        const TempoSection* ts_at = &tempo_section_at (frame);
-       const TempoSection* ts_after = tempo_section_after (frame);
+       const TempoSection* ts_after = 0;
+       Metrics::const_iterator i;
+
+       for (i = metrics.begin(); i != metrics.end(); ++i) {
+               TempoSection* t;
+
+               if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+
+                       if ((*i)->frame() > frame) {
+                               ts_after = t;
+                               break;
+                       }
+               }
+       }
 
        if (ts_after) {
-               return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame - ts_at->frame(), ts_after->beats_per_minute(), ts_after->frame(), _frame_rate));
+               return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
        }
        /* must be treated as constant tempo */
        return ts_at->frames_per_beat (_frame_rate);
@@ -1836,10 +2113,7 @@ TempoMap::tempo_at (framepos_t frame) const
                if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
                        if ((prev_ts) && t->frame() > frame) {
                                /* this is the one past frame */
-                               framepos_t const time = frame - prev_ts->frame();
-                               framepos_t const last_time = t->frame() - prev_ts->frame();
-                               double const last_beats_per_minute = t->beats_per_minute();
-                               double const ret = prev_ts->tempo_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
+                               double const ret = prev_ts->tempo_at_frame (frame, _frame_rate);
                                Tempo const ret_tempo (ret, m.tempo().note_type ());
                                return ret_tempo;
                        }
@@ -1848,13 +2122,13 @@ TempoMap::tempo_at (framepos_t frame) const
        }
 
        return m.tempo();
-
 }
 
 const MeterSection&
 TempoMap::meter_section_at (framepos_t frame) const
 {
        Glib::Threads::RWLock::ReaderLock lm (lock);
+
        Metrics::const_iterator i;
        MeterSection* prev = 0;
 
@@ -1927,7 +2201,7 @@ TempoMap::set_state (const XMLNode& node, int /*version*/)
 
                                        if (ts->bar_offset() < 0.0) {
                                                if (last_meter) {
-                                                       ts->update_bar_offset_from_bbt (*last_meter);
+                                                       //ts->update_bar_offset_from_bbt (*last_meter);
                                                }
                                        }
                                }
@@ -1958,7 +2232,24 @@ TempoMap::set_state (const XMLNode& node, int /*version*/)
                        MetricSectionSorter cmp;
                        metrics.sort (cmp);
                }
+               /* check for legacy sessions where bbt was the base musical unit for tempo */
+               for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
+                       MeterSection* prev_ms;
+                       TempoSection* prev_ts;
+                       if ((prev_ms = dynamic_cast<MeterSection*>(*i)) != 0) {
+                               if (prev_ms->beat() < 0.0) {
+                                       /*XX we cannot possibly make this work??. */
+                                       pair<double, BBT_Time> start = make_pair (((prev_ms->bbt().bars - 1) * 4.0) + (prev_ms->bbt().beats - 1) + (prev_ms->bbt().ticks / BBT_Time::ticks_per_beat), prev_ms->bbt());
+                                       prev_ms->set_beat (start);
+                               }
+                       } else if ((prev_ts = dynamic_cast<TempoSection*>(*i)) != 0) {
+                               if (prev_ts->beat() < 0.0) {
+                                       double const start = ((prev_ts->legacy_bbt().bars - 1) * 4.0) + (prev_ts->legacy_bbt().beats - 1) + (prev_ts->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
+                                       prev_ts->set_beat (start);
 
+                               }
+                       }
+               }
                /* check for multiple tempo/meters at the same location, which
                   ardour2 somehow allowed.
                */
@@ -1966,16 +2257,20 @@ TempoMap::set_state (const XMLNode& node, int /*version*/)
                Metrics::iterator prev = metrics.end();
                for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
                        if (prev != metrics.end()) {
-                               if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) {
-                                       if ((*prev)->start() == (*i)->start()) {
-                                               cerr << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
-                                               error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
+                               MeterSection* ms;
+                               MeterSection* prev_ms;
+                               TempoSection* ts;
+                               TempoSection* prev_ts;
+                               if ((prev_ms = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
+                                       if (prev_ms->beat() == ms->beat()) {
+                                               cerr << string_compose (_("Multiple meter definitions found at %1"), prev_ms->beat()) << endmsg;
+                                               error << string_compose (_("Multiple meter definitions found at %1"), prev_ms->beat()) << endmsg;
                                                return -1;
                                        }
-                               } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) {
-                                       if ((*prev)->start() == (*i)->start()) {
-                                               cerr << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
-                                               error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
+                               } else if ((prev_ts = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
+                                       if (prev_ts->beat() == ts->beat()) {
+                                               cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->beat()) << endmsg;
+                                               error << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->beat()) << endmsg;
                                                return -1;
                                        }
                                }
@@ -2001,10 +2296,10 @@ TempoMap::dump (std::ostream& o) const
        for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
 
                if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
-                       o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (movable? "
+                       o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->beat() << " frame= " << t->frame() << " (movable? "
                          << t->movable() << ')' << endl;
                } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
-                       o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
+                       o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
                          << " (movable? " << m->movable() << ')' << endl;
                }
        }
@@ -2076,48 +2371,69 @@ TempoMap::insert_time (framepos_t where, framecnt_t amount)
                for (i = metrics.begin(); i != metrics.end(); ++i) {
 
                        BBT_Time bbt;
-                       TempoMetric metric (*meter, *tempo);
-
+                       //TempoMetric metric (*meter, *tempo);
+                       MeterSection* ms = const_cast<MeterSection*>(meter);
+                       TempoSection* ts = const_cast<TempoSection*>(tempo);
                        if (prev) {
-                               metric.set_start (prev->start());
-                               metric.set_frame (prev->frame());
+                               if (ts){
+                                       if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
+                                               ts->set_beat (t->beat());
+                                       }
+                                       if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
+                                               ts->set_beat (m->beat());
+                                       }
+                                       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);
+                                       }
+                                       if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
+                                               pair<double, BBT_Time> start = make_pair (t->beat(), beats_to_bbt_locked (t->beat()));
+                                               ms->set_beat (start);
+                                       }
+                                       ms->set_frame (prev->frame());
+                               }
+
                        } else {
                                // metric will be at frames=0 bbt=1|1|0 by default
                                // which is correct for our purpose
                        }
 
-                       bbt_time ((*i)->frame(), bbt);
-
-                       // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
-
-                       if (first) {
-                               first = false;
-                       } else {
+                       // cerr << bbt << endl;
 
-                               if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
-                                       /* round up to next beat */
-                                       bbt.beats += 1;
-                               }
+                       if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
+                               t->set_beat (beat_at_frame_locked (m->frame()));
+                               tempo = t;
+                               // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->beat() <<endl;
+                       } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
+                               bbt_time (m->frame(), bbt);
 
-                               bbt.ticks = 0;
+                               // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
 
-                               if (bbt.beats != 1) {
-                                       /* round up to next bar */
-                                       bbt.bars += 1;
-                                       bbt.beats = 1;
-                               }
-                       }
+                               if (first) {
+                                       first = false;
+                               } else {
 
-                       // cerr << bbt << endl;
+                                       if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
+                                               /* round up to next beat */
+                                               bbt.beats += 1;
+                                       }
 
-                       (*i)->set_start (bbt);
+                                       bbt.ticks = 0;
 
-                       if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
-                               tempo = t;
-                               // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
-                       } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
+                                       if (bbt.beats != 1) {
+                                               /* round up to next bar */
+                                               bbt.bars += 1;
+                                               bbt.beats = 1;
+                                       }
+                               }
+                               pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (m->frame()), bbt);
+                               m->set_beat (start);
                                meter = m;
-                               // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
+                               // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->beat() <<endl;
                        } else {
                                fatal << _("programming error: unhandled MetricSection type") << endmsg;
                                abort(); /*NOTREACHED*/
@@ -2294,7 +2610,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
                                }
 
                                if (next_tempo) {
-                                       pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
+                                       pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), _frame_rate);
                                } else {
                                        pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
                                }
@@ -2314,7 +2630,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
        }
 
        if (next_tempo) {
-               pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
+               pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), _frame_rate);
        } else {
                pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
        }
@@ -2346,7 +2662,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
                                }
 
                                if (next_tempo) {
-                                       pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
+                                       pos += tempo->frame_at_beat (beats, _frame_rate);
                                } else {
                                        pos += llrint (beats * frames_per_beat);
                                }
@@ -2365,13 +2681,13 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
        }
 
        if (next_tempo) {
-               pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
+               pos += tempo->frame_at_beat (beats, _frame_rate);
        } else {
                pos += llrint (beats * frames_per_beat);
        }
 
        if (op.ticks) {
-               pos += tempo->frame_at_tick (op.ticks, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
+               pos += tempo->frame_at_tick (op.ticks, _frame_rate);
        }
 
        return pos;
@@ -2406,7 +2722,7 @@ operator<< (std::ostream& o, const Tempo& t) {
 std::ostream&
 operator<< (std::ostream& o, const MetricSection& section) {
 
-       o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
+       o << "MetricSection @ " << section.frame() << ' ';
 
        const TempoSection* ts;
        const MeterSection* ms;
@@ -2414,7 +2730,7 @@ operator<< (std::ostream& o, const MetricSection& section) {
        if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
                o << *((const Tempo*) ts);
        } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
-               o << *((const Meter*) ms);
+               //o << *((const Meter*) ms);
        }
 
        return o;