new tempo handling from drmoore; don't follow playhead when doing requested_return...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 21 Dec 2007 14:48:25 +0000 (14:48 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 21 Dec 2007 14:48:25 +0000 (14:48 +0000)
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2806 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/editor.cc
gtk2_ardour/editor_mixer.cc
gtk2_ardour/editor_tempodisplay.cc
gtk2_ardour/tempo_dialog.cc
gtk2_ardour/tempo_dialog.h
libs/ardour/ardour/session.h
libs/ardour/ardour/tempo.h
libs/ardour/ladspa_plugin.cc
libs/ardour/session_transport.cc
libs/ardour/tempo.cc

index 14c89e8ee4ffe0f1532f23189ad69bc2c25fed7b..87b5f16d7fd63a3418ef40d787d20cd40c3e14e0 100644 (file)
@@ -2731,7 +2731,7 @@ Editor::setup_toolbar ()
        ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
 
        zoom_focus_selector.set_name ("ZoomFocusSelector");
-       Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Playhead", FUDGE, 0);
+       Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, _("Playhead"), FUDGE, 0);
        set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
        zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
        ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
@@ -2745,19 +2745,19 @@ Editor::setup_toolbar ()
        snap_box.set_border_width (2);
 
        snap_type_selector.set_name ("SnapTypeSelector");
-       Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
+       Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, _("SMPTE Seconds"), 2+FUDGE, 10);
        set_popdown_strings (snap_type_selector, snap_type_strings);
        snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
        ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
 
        snap_mode_selector.set_name ("SnapModeSelector");
-       Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
+       Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, _("Magnetic Snap"), 2+FUDGE, 10);
        set_popdown_strings (snap_mode_selector, snap_mode_strings);
        snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
        ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
 
        edit_point_selector.set_name ("SnapModeSelector");
-       Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
+       Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, _("Playhead"), 2+FUDGE, 10);
        set_popdown_strings (edit_point_selector, edit_point_strings);
        edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
        ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
@@ -4140,10 +4140,14 @@ Editor::get_preferred_edit_position (bool ignore_playhead)
                
        case EditAtSelectedMarker:
                if (!selection->markers.empty()) {
-                       bool whocares;
-                       Location* loc = find_location_from_marker (selection->markers.front(), whocares);
+                       bool is_start;
+                       Location* loc = find_location_from_marker (selection->markers.front(), is_start);
                        if (loc) {
-                               where =  loc->start();
+                               if (is_start) {
+                                       where =  loc->start();
+                               } else {
+                                       where = loc->end();
+                               }
                                break;
                        }
                } 
index 0e41fcaeac8fcb549409d70f0f65ae6a90b04be3..2f6e9d57049322f0b4975a68c7b0d34237305ba6 100644 (file)
@@ -183,7 +183,7 @@ Editor::update_current_screen ()
 
                /* only update if the playhead is on screen or we are following it */
 
-               if (_follow_playhead) {
+               if (_follow_playhead && session->requested_return_frame() < 0) {
 
                        playhead_cursor->canvas_item.show();
 
index 854f670121a98b735daea8f63caf0524ccdecbbf..26363b99978bed38c27751a7c2130e201fda4d5a 100644 (file)
@@ -308,13 +308,14 @@ Editor::mouse_add_new_tempo_event (nframes_t frame)
        BBT_Time requested;
        
        bpm = tempo_dialog.get_bpm ();
+       double nt = tempo_dialog.get_note_type();
        bpm = max (0.01, bpm);
        
        tempo_dialog.get_bbt_time (requested);
        
        begin_reversible_command (_("add tempo mark"));
         XMLNode &before = map.get_state();
-       map.add_tempo (Tempo (bpm), requested);
+       map.add_tempo (Tempo (bpm,nt), requested);
         XMLNode &after = map.get_state();
        session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
        commit_reversible_command ();
@@ -429,13 +430,14 @@ Editor::edit_tempo_section (TempoSection* section)
        }
 
        double bpm = tempo_dialog.get_bpm ();
+       double nt = tempo_dialog.get_note_type ();
        BBT_Time when;
        tempo_dialog.get_bbt_time(when);
        bpm = max (0.01, bpm);
        
        begin_reversible_command (_("replace tempo mark"));
         XMLNode &before = session->tempo_map().get_state();
-       session->tempo_map().replace_tempo (*section, Tempo (bpm));
+       session->tempo_map().replace_tempo (*section, Tempo (bpm,nt));
        session->tempo_map().move_tempo (*section, when);
         XMLNode &after = session->tempo_map().get_state();
        session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after));
index aee3dc44e648f82fd37c394202455308e9cfcca5..9d5ba926c559c16569251eeb4ea5e631617313d7 100644 (file)
@@ -37,6 +37,7 @@ TempoDialog::TempoDialog (TempoMap& map, nframes_t frame, const string & action)
          bpm_adjustment (60.0, 1.0, 999.9, 0.1, 1.0, 1.0),
          bpm_spinner (bpm_adjustment),
          bpm_frame (_("Beats per minute")),
+         note_frame (_("BPM denominator")),
          ok_button (action),
          cancel_button (_("Cancel")),
          when_bar_label (_("Bar")),
@@ -48,7 +49,7 @@ TempoDialog::TempoDialog (TempoMap& map, nframes_t frame, const string & action)
        Tempo tempo (map.tempo_at (frame));
        map.bbt_time (frame, when);
 
-       init (when, tempo.beats_per_minute(), true);
+       init (when, tempo.beats_per_minute(), tempo.note_type(), true);
 }
 
 TempoDialog::TempoDialog (TempoSection& section, const string & action)
@@ -63,23 +64,62 @@ TempoDialog::TempoDialog (TempoSection& section, const string & action)
          when_table (2, 2),
          when_frame (_("Location"))
 {
-       init (section.start(), section.beats_per_minute(), section.movable());
+       init (section.start(), section.beats_per_minute(), section.note_type(), section.movable());
 }
 
 void
-TempoDialog::init (const BBT_Time& when, double bpm, bool movable)
+TempoDialog::init (const BBT_Time& when, double bpm, double note_type, bool movable)
 {
        bpm_spinner.set_numeric (true);
        bpm_spinner.set_digits (2);
        bpm_spinner.set_wrap (true);
        bpm_spinner.set_value (bpm);
 
+       strings.push_back (_("whole (1)"));
+       strings.push_back (_("second (2)"));
+       strings.push_back (_("third (3)"));
+       strings.push_back (_("quarter (4)"));
+       strings.push_back (_("eighth (8)"));
+       strings.push_back (_("sixteenth (16)"));
+       strings.push_back (_("thirty-second (32)"));
+       
+       /* the string here needs to be the longest one to display */
+       const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button
+       // TRANSLATORS: this is not a mis-spelling of "thirty", we're including a vertical 
+       // descender to make sure the height gets computed properly.
+        Gtkmm2ext::set_size_request_to_display_given_text (note_types, "thirtq-second (32)", 7+FUDGE, 15);
+
+       set_popdown_strings (note_types, strings);
+
+       if (note_type==1.0f)
+               note_types.set_active_text (_("whole (1)"));
+       else if (note_type==2.0f)
+               note_types.set_active_text (_("second (2)"));
+       else if (note_type==3.0f)
+               note_types.set_active_text (_("third (3)"));
+       else if (note_type==4.0f)
+               note_types.set_active_text (_("quarter (4)"));
+       else if (note_type==8.0f)
+               note_types.set_active_text (_("eighth (8)"));
+       else if (note_type==16.0f)
+               note_types.set_active_text (_("sixteenth (16)"));
+       else if (note_type==32.0f)
+               note_types.set_active_text (_("thirty-second (32)"));
+       else
+               note_types.set_active_text (_("quarter (4)"));
+
        hspacer1.set_border_width (5);
        hspacer1.pack_start (bpm_spinner, false, false);
        vspacer1.set_border_width (5);
        vspacer1.pack_start (hspacer1, false, false);
 
+       hspacer2.set_border_width (5);
+       hspacer2.pack_start (note_types, false, false);
+       vspacer2.set_border_width (5);
+       vspacer2.pack_start (hspacer2, false, false);
+
        bpm_frame.add (vspacer1);
+       note_frame.add (vspacer2);
 
        if (movable) {
                snprintf (buf, sizeof (buf), "%" PRIu32, when.bars);
@@ -115,9 +155,12 @@ TempoDialog::init (const BBT_Time& when, double bpm, bool movable)
 
        bpm_frame.set_name ("MetricDialogFrame");
        bpm_spinner.set_name ("MetricEntry");
+       note_frame.set_name ("MetricDialogFrame");
 
+       get_vbox()->set_border_width (12);
        get_vbox()->pack_start (bpm_frame, false, false);
-       
+       get_vbox()->pack_start (note_frame, false, false);
+
        add_button (Stock::CANCEL, RESPONSE_CANCEL);
        add_button (Stock::APPLY, RESPONSE_ACCEPT);
        set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
@@ -131,6 +174,7 @@ TempoDialog::init (const BBT_Time& when, double bpm, bool movable)
        bpm_spinner.signal_activate().connect (bind (mem_fun (*this, &TempoDialog::response), RESPONSE_ACCEPT));
        bpm_spinner.signal_button_press_event().connect (mem_fun (*this, &TempoDialog::bpm_button_press), false);
        bpm_spinner.signal_button_release_event().connect (mem_fun (*this, &TempoDialog::bpm_button_release), false);
+       note_types.signal_changed().connect (mem_fun (*this, &TempoDialog::note_types_change));
 }
 
 bool
@@ -168,6 +212,41 @@ TempoDialog::get_bbt_time (BBT_Time& requested)
        return true;
 }
 
+double
+TempoDialog::get_note_type ()
+{
+       double note_type = 0;
+       vector<string>::iterator i;
+       string text = note_types.get_active_text();
+       
+       for (i = strings.begin(); i != strings.end(); ++i) {
+               if (text == *i) {
+                       if (sscanf (text.c_str(), "%*[^0-9]%lf", &note_type) != 1) {
+                               error << string_compose(_("garbaged note type entry (%1)"), text) << endmsg;
+                               return 0;
+                       } else {
+                               break;
+                       }
+               }
+       } 
+       
+       if (i == strings.end()) {
+               if (sscanf (text.c_str(), "%lf", &note_type) != 1) {
+                       error << string_compose(_("incomprehensible note type entry (%1)"), text) << endmsg;
+                       return 0;
+               }
+       }
+
+       cerr << "returning " << note_type << " based on " << text << endl;
+       return note_type;
+}
+
+void
+TempoDialog::note_types_change ()
+{
+        set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
+}
+
 
 MeterDialog::MeterDialog (TempoMap& map, nframes_t frame, const string & action)
        : ArdourDialog ("meter dialog"),
@@ -216,6 +295,13 @@ MeterDialog::init (const BBT_Time& when, double bpb, double note_type, bool mova
        strings.push_back (_("sixteenth (16)"));
        strings.push_back (_("thirty-second (32)"));
        
+       /* the string here needs to be the longest one to display */
+       const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button
+
+       // TRANSLATORS: this is not a mis-spelling of "thirty", we're including a vertical 
+       // descender to make sure the height gets computed properly.
+        Gtkmm2ext::set_size_request_to_display_given_text (note_types, _("thirtq-second (32)"), 7+FUDGE, 15);
+
        set_popdown_strings (note_types, strings);
 
        if (note_type==1.0f)
@@ -235,10 +321,6 @@ MeterDialog::init (const BBT_Time& when, double bpb, double note_type, bool mova
        else
                note_types.set_active_text (_("quarter (4)"));
                
-       /* the string here needs to be the longest one to display */
-       const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button
-        Gtkmm2ext::set_size_request_to_display_given_text (note_types, "thirty-second (32)", 7+FUDGE, 7);
-
        hspacer1.set_border_width (5);
        hspacer1.pack_start (note_types, false, false);
        vspacer1.set_border_width (5);
@@ -283,6 +365,8 @@ MeterDialog::init (const BBT_Time& when, double bpb, double note_type, bool mova
                
                get_vbox()->pack_start (when_frame, false, false);
        }
+
+       get_vbox()->set_border_width (12);
        get_vbox()->pack_start (bpb_frame, false, false);
        get_vbox()->pack_start (note_frame, false, false);
        
index b9f6a16b24e8aea7f9752d971412383fea18f606..a92f26f8e3664a4be4d18b480bbe75847e8442f0 100644 (file)
@@ -37,6 +37,9 @@
 
 struct TempoDialog : public ArdourDialog 
 {
+    Gtk::ComboBoxText note_types;
+    vector<string> strings;
+    Gtk::Frame   note_frame;
     Gtk::Adjustment   bpm_adjustment;
     Gtk::SpinButton   bpm_spinner;
     Gtk::Frame        bpm_frame;
@@ -44,8 +47,8 @@ struct TempoDialog : public ArdourDialog
     Gtk::Button  ok_button;
     Gtk::Button  cancel_button;
     Gtk::HBox    button_box;
-    Gtk::HBox    hspacer1;
-    Gtk::VBox    vspacer1;
+    Gtk::HBox    hspacer1, hspacer2;
+    Gtk::VBox    vspacer1, vspacer2;
     Gtk::Entry   when_bar_entry;
     Gtk::Entry   when_beat_entry;
     Gtk::Label   when_bar_label;
@@ -58,13 +61,15 @@ struct TempoDialog : public ArdourDialog
     TempoDialog (ARDOUR::TempoSection&, const string & action);
 
     double get_bpm ();
+    double get_note_type ();
     bool   get_bbt_time (ARDOUR::BBT_Time&);
     
   private:
-    void init (const ARDOUR::BBT_Time& start, double, bool);
+    void init (const ARDOUR::BBT_Time& start, double, double, bool);
     void bpm_changed ();
     bool bpm_button_press (GdkEventButton* );
     bool bpm_button_release (GdkEventButton* );
+    void note_types_change ();
 };
 
 struct MeterDialog : public ArdourDialog 
index 42ad79f3c0fb414275202d7071ec40ace4c46b13..8aea4929105ed65452da92126a3c8c5bcc72c4cc 100644 (file)
@@ -966,35 +966,35 @@ class Session : public PBD::StatefulDestructible
 
        typedef void (Session::*process_function_type)(nframes_t);
 
-       AudioEngine            &_engine;
-       mutable gint            processing_prohibited;
+       AudioEngine&            _engine;
+       mutable gint             processing_prohibited;
        process_function_type    process_function;
        process_function_type    last_process_function;
        bool                     waiting_for_sync_offset;
-       nframes_t          _base_frame_rate;
-       nframes_t          _current_frame_rate;  //this includes video pullup offset
+       nframes_t               _base_frame_rate;
+       nframes_t               _current_frame_rate;  //this includes video pullup offset
        int                      transport_sub_state;
-       mutable gint           _record_status;
-       nframes_t          _transport_frame;
+       mutable gint            _record_status;
+       volatile nframes_t      _transport_frame;
        Location*                end_location;
        Location*                start_location;
-       Slave                  *_slave;
+       Slave*                  _slave;
        bool                    _silent;
        volatile float          _transport_speed;
        volatile float          _desired_transport_speed;
        float                   _last_transport_speed;
        bool                     auto_play_legal;
-       nframes_t          _last_slave_transport_frame;
-       nframes_t           maximum_output_latency;
-       nframes_t           last_stop_frame;
-       nframes64_t             _requested_return_frame;
+       nframes_t               _last_slave_transport_frame;
+       nframes_t                maximum_output_latency;
+       nframes_t                last_stop_frame;
+       volatile nframes64_t    _requested_return_frame;
        vector<Sample *>        _passthru_buffers;
        vector<Sample *>        _silent_buffers;
        vector<Sample *>        _send_buffers;
-       nframes_t           current_block_size;
-       nframes_t          _worst_output_latency;
-       nframes_t          _worst_input_latency;
-       nframes_t          _worst_track_latency;
+       nframes_t                current_block_size;
+       nframes_t               _worst_output_latency;
+       nframes_t               _worst_input_latency;
+       nframes_t               _worst_track_latency;
        bool                    _have_captured;
        float                   _meter_hold;
        float                   _meter_falloff;
index 5e3e93e48b8595ac6f2be64b2435d16a9f59d343..fcd42734b0a3dfef7d3a1d376593c4dfbf0e7295 100644 (file)
@@ -40,27 +40,29 @@ using std::list;
 using std::vector;
 
 namespace ARDOUR {
-
+class Meter;
 class Tempo {
   public:
-       Tempo (double bpm)
-               : _beats_per_minute (bpm) {}
+       Tempo (double bpm, double type=4.0) // defaulting to quarter note
+               : _beats_per_minute (bpm), _note_type(type) {} 
        Tempo (const Tempo& other) {
                _beats_per_minute = other._beats_per_minute;
+               _note_type = other._note_type;
        }
        void operator= (const Tempo& other) {
                if (&other != this) {
                        _beats_per_minute = other._beats_per_minute;
+                       _note_type = other._note_type;
                }
        }
 
-       double beats_per_minute () const { return _beats_per_minute; }
-       double frames_per_beat (nframes_t sr) const {
-               return  ((60.0 * sr) / _beats_per_minute);
-       }
+       double beats_per_minute () const { return _beats_per_minute;}
+       double note_type () const { return _note_type;}
+       double frames_per_beat (nframes_t sr, const Meter& meter) const;
 
   protected:
        double _beats_per_minute;
+       double _note_type;
 };
 
 class Meter {
@@ -149,8 +151,8 @@ class MeterSection : public MetricSection, public Meter {
 
 class TempoSection : public MetricSection, public Tempo {
   public:
-       TempoSection (const BBT_Time& start, double qpm)
-               : MetricSection (start), Tempo (qpm) {}
+       TempoSection (const BBT_Time& start, double qpm, double note_type)
+               : MetricSection (start), Tempo (qpm, note_type) {}
        TempoSection (const XMLNode&);
 
        static const string xml_state_node_name;
index a7aab441e04a2b0f5a2b01908bc13acfafcdb21d..3b32d62dc7f93adf824c15eb965b88bb3fd8fe17 100644 (file)
@@ -161,7 +161,7 @@ string
 LadspaPlugin::unique_id() const
 {
        char buf[32];
-       snprintf (buf, sizeof (buf), "%u", descriptor->UniqueID);
+       snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
        return string (buf);
 }
 
index 635e32de627dcd09b5a9f8c00098f0aba92b5e3b..2422918753db1820cac070fa2ad893cb2affd87c 100644 (file)
@@ -478,7 +478,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                
        }
 
-       PositionChanged (_transport_frame); /* EMIT SIGNAL */
+        PositionChanged ((nframes_t) _transport_frame); /* EMIT SIGNAL */
        TransportStateChange (); /* EMIT SIGNAL */
 
        /* and start it up again if relevant */
index cd59e93054145fb05160c52f1aad2fdecfd9ab46..780f5c6a5df6513ff903cdd8e6706595ad5ecf5b 100644 (file)
@@ -43,12 +43,17 @@ Tempo    TempoMap::_default_tempo (120.0);
 
 const double Meter::ticks_per_beat = 1920.0;
 
+double Tempo::frames_per_beat (nframes_t sr, const Meter& meter) const
+{
+       return  ((60.0 * sr) / (_beats_per_minute * meter.note_divisor()/_note_type));
+}
+
 /***********************************************************************/
 
 double
 Meter::frames_per_bar (const Tempo& tempo, nframes_t sr) const
 {
-       return ((60.0 * sr * _beats_per_bar) / tempo.beats_per_minute());
+       return ((60.0 * sr * _beats_per_bar) / (tempo.beats_per_minute() * _note_type/tempo.note_type()));
 }
 
 /***********************************************************************/
@@ -86,6 +91,16 @@ TempoSection::TempoSection (const XMLNode& node)
                error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
                throw failed_constructor();
        }
+       
+       if ((prop = node.property ("note-type")) == 0) {
+               /* older session, make note type be quarter by default */
+               _note_type = 4.0;
+       } else {
+               if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
+                       error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
+                       throw failed_constructor();
+               }
+       }
 
        if ((prop = node.property ("movable")) == 0) {
                error << _("TempoSection XML node has no \"movable\" property") << endmsg;
@@ -109,6 +124,8 @@ TempoSection::get_state() const
        root->add_property ("start", buf);
        snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
        root->add_property ("beats-per-minute", buf);
+       snprintf (buf, sizeof (buf), "%f", _note_type);
+       root->add_property ("note-type", buf);
        snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
        root->add_property ("movable", buf);
 
@@ -210,7 +227,7 @@ TempoMap::TempoMap (nframes_t fr)
        start.beats = 1;
        start.ticks = 0;
 
-       TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute());
+       TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
        MeterSection *m = new MeterSection (start, _default_meter.beats_per_bar(), _default_meter.note_divisor());
 
        t->set_movable (false);
@@ -359,7 +376,7 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
        
                where.ticks = 0;
                
-               do_insert (new TempoSection (where, tempo.beats_per_minute()));
+               do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()));
        }
 
        StateChanged (Change (0));
@@ -614,7 +631,7 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me
 
        const double beats_per_bar = metric.meter().beats_per_bar();
        const double frames_per_bar = metric.meter().frames_per_bar (metric.tempo(), _frame_rate);
-       const double beat_frames = metric.tempo().frames_per_beat (_frame_rate);
+       const double beat_frames = metric.tempo().frames_per_beat (_frame_rate, metric.meter());
 
        /* now compute how far beyond that point we actually are. */
 
@@ -667,7 +684,7 @@ TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) con
                + start.ticks/Meter::ticks_per_beat;
 
 
-       start_frame = m.frame() + (nframes_t) rint( beat_offset * m.tempo().frames_per_beat(_frame_rate));
+       start_frame = m.frame() + (nframes_t) rint( beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
 
        m =  metric_at(end);
 
@@ -676,7 +693,7 @@ TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) con
        beat_offset = bar_offset * m.meter().beats_per_bar() - (m.start().beats -1) + (end.beats - 1) 
                + end.ticks/Meter::ticks_per_beat;
 
-       end_frame = m.frame() + (nframes_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate));
+       end_frame = m.frame() + (nframes_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
 
        frames = end_frame - start_frame;
 
@@ -697,7 +714,7 @@ TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo,
        double beat_frames = 0;
 
        beats_per_bar = meter.beats_per_bar();
-       beat_frames = tempo.frames_per_beat (_frame_rate);
+       beat_frames = tempo.frames_per_beat (_frame_rate,meter);
 
        frames = 0;
 
@@ -1088,7 +1105,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
 
        beats_per_bar = meter->beats_per_bar ();
        frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
-       beat_frames = tempo->frames_per_beat (_frame_rate);
+       beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
        
        if (meter->frame() > tempo->frame()) {
                bar = meter->start().bars;
@@ -1198,7 +1215,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
 
                        beats_per_bar = meter->beats_per_bar ();
                        frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
-                       beat_frames = tempo->frames_per_beat (_frame_rate);
+                       beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
                        
                        ++i;
                }
@@ -1304,7 +1321,7 @@ 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 << ' ' << t->beats_per_minute() << " BPM at " << t->start() << " frame= " << t->frame() << " (move? "
+                       o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
                          << t->movable() << ')' << endl;
                } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
                        o << "Meter @ " << *i << ' ' << m->beats_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()