View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0000940 | ardour | bugs | public | 2005-03-29 11:31 | 2020-04-19 20:12 |
| Reporter | csuwi | Assigned To | seablade | ||
| Priority | normal | Severity | minor | Reproducibility | always |
| Status | closed | Resolution | fixed | ||
| Summary | 0000940: Time signatures with subdivisions other than four not correctly measured. | ||||
| Description | Basically, a bar of 3/8 should be half the length of a bar of 3/4 but as it is the subdivisions don't seem to make a difference. | ||||
| Additional Information | libardour 0.880 | ||||
| Tags | No tags attached. | ||||
|
|
This is caused by a conceptual/design issue that is confusing without documentation, and probably should be altered over the long term. At present, Ardour defines the "b" in "bpm" to mean "whatever note length is defined by the mete denominator". If you set bpm to 120 and use 4/4, then its 120 quarter notes per minute. If you set the meter to 3/8, its 120 eighth notes per minute. This is not quite so inconvenient as it seems, because for many common uses of meter switches, it is necessary to change the tempo even in systems where bpm == quarters per minute. The major difference in Ardour right now is that the new bpm you should enter must take into account that it is *not* a quarter-per-minute count, but a beat-per-minute count. In the long term, we will probably change this so that the user can define the interpretation of bpm to be one of (quarters-per-minute, meter-denominator-per-minute,some-other-note-length-per-minute). Let me know if this all makes sense to you. |
|
|
It makes sense as an explanation but I think it makes it incompatible with convention and with tools such as Hydrogen and Rosegarden. The long term solution seems reasonable, certainly. I also notice some weirdness with odd time signatures scrambling the position of bar lines. I will report this as a seperate bug. |
|
2007-12-21 13:17
|
dm_timesig_patch (12,457 bytes)
Index: gtk2_ardour/tempo_dialog.cc
===================================================================
--- gtk2_ardour/tempo_dialog.cc (revision 2798)
+++ gtk2_ardour/tempo_dialog.cc (working copy)
@@ -37,6 +37,7 @@
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 @@
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,60 @@
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)"));
+
+ 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)"));
+
+ /* 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 (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 +153,11 @@
bpm_frame.set_name ("MetricDialogFrame");
bpm_spinner.set_name ("MetricEntry");
+ note_frame.set_name ("MetricDialogFrame");
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 +171,7 @@
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,7 +209,41 @@
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", ¬e_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", ¬e_type) != 1) {
+ error << string_compose(_("incomprehensible note type entry (%1)"), text) << endmsg;
+ return 0;
+ }
+ }
+ 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"),
note_frame (_("Meter denominator")),
Index: gtk2_ardour/editor_tempodisplay.cc
===================================================================
--- gtk2_ardour/editor_tempodisplay.cc (revision 2798)
+++ gtk2_ardour/editor_tempodisplay.cc (working copy)
@@ -308,13 +308,14 @@
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 @@
}
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: gtk2_ardour/tempo_dialog.h
===================================================================
--- gtk2_ardour/tempo_dialog.h (revision 2798)
+++ gtk2_ardour/tempo_dialog.h (working copy)
@@ -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 @@
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 @@
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: libs/ardour/ardour/tempo.h
===================================================================
--- libs/ardour/ardour/tempo.h (revision 2798)
+++ libs/ardour/ardour/tempo.h (working copy)
@@ -40,27 +40,29 @@
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 {
Index: libs/ardour/tempo.cc
===================================================================
--- libs/ardour/tempo.cc (revision 2798)
+++ libs/ardour/tempo.cc (working copy)
@@ -43,12 +43,17 @@
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 @@
error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
throw failed_constructor();
}
+
+ if ((prop = node.property ("note-type")) == 0) {
+ error << _("TempoSection XML node has no \"note-type\" property") << endmsg;
+ throw failed_constructor();
+ }
+
+ 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 @@
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);
@@ -614,7 +631,7 @@
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 @@
+ 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 @@
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 @@
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 @@
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 @@
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;
}
|
|
|
Attached a patch that attempts to change this behaviour in: URL: http://subversion.ardour.org/svn/ardour2/branches/2.0-ongoing Revision: 2798 Adds a tempo denominator dropdown to TempoDialog Adds a tempo denominator member var to Tempo Modifies time calculations to take this into account. Not extensively tested but feedback greatly appreciated. |
|
|
drmoore - i applied your patch after a few fixes. thanks very much. this does have one disadvantage that in existing ardour sessions with tempo changes, the changes will not happen in the way they have before. but i am reasonably happy with the idea that this is right thing to do anyway, so its just time to force a little pain on users. i might even fix that too (i can see a way to force the old behaviour for old sessions only). |
|
2007-12-28 21:46
|
dm_timesig_patch_trunk (14,719 bytes)
diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc
index 831fe3b..f18392c 100644
--- a/gtk2_ardour/editor_tempodisplay.cc
+++ b/gtk2_ardour/editor_tempodisplay.cc
@@ -235,13 +235,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 ();
@@ -356,13 +357,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));
diff --git a/gtk2_ardour/tempo_dialog.cc b/gtk2_ardour/tempo_dialog.cc
index d69acf7..8eab45a 100644
--- a/gtk2_ardour/tempo_dialog.cc
+++ b/gtk2_ardour/tempo_dialog.cc
@@ -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,56 @@ 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 (1);
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)"));
+
+ 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 +149,11 @@ 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()->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 +167,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 +205,40 @@ 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", ¬e_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", ¬e_type) != 1) {
+ error << string_compose(_("incomprehensible note type entry (%1)"), text) << endmsg;
+ return 0;
+ }
+ }
+
+ 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"),
diff --git a/gtk2_ardour/tempo_dialog.h b/gtk2_ardour/tempo_dialog.h
index b9f6a16..a92f26f 100644
--- a/gtk2_ardour/tempo_dialog.h
+++ b/gtk2_ardour/tempo_dialog.h
@@ -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
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index 2d8462a..79df425 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -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 {
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index b8d82bd..b332d74 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -345,7 +345,7 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
// FIXME: assumes tempo never changes after start
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
- _session.engine().frame_rate());
+ _session.engine().frame_rate(), _session.tempo_map().meter_at(_timeline_position));
const uint64_t start_ticks = (uint64_t)((start / frames_per_beat) * _ppqn);
@@ -457,7 +457,7 @@ SMFSource::append_event_unlocked(const MidiEvent& ev)
// FIXME: assumes tempo never changes after start
const double frames_per_beat = _session.tempo_map().tempo_at
- (_timeline_position).frames_per_beat(_session.engine().frame_rate());
+ (_timeline_position).frames_per_beat(_session.engine().frame_rate(),_session.tempo_map().meter_at(_timeline_position));
const uint32_t delta_time = (uint32_t)((ev.time() - _last_ev_time) / frames_per_beat * _ppqn);
@@ -888,7 +888,7 @@ SMFSource::load_model(bool lock, bool force_reload)
// FIXME: assumes tempo never changes after start
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
- _session.engine().frame_rate());
+ _session.engine().frame_rate(),_session.tempo_map().meter_at(_timeline_position));
uint32_t delta_t = 0;
int ret;
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index cd59e93..dc3301d 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -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) {
+ error << _("TempoSection XML node has no \"note-type\" property") << endmsg;
+ throw failed_constructor();
+ }
+
+ 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);
@@ -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;
}
|
|
|
added a version of the patch (sans paul's bugfixes) based on the current trunk. It needed some minor modifications to smf_source.cc to compile. |
|
|
This can be closed. All seems good in 2.6. |
|
|
Resolving issue as it seems to be fixed in recent versions of Ardour per OP's observations. If there is still any issue post up and I will reopen. Seablade |
|
|
Issue has been closed automatically, by Trigger Close Plugin. Feel free to re-open with additional information if you think the issue is not resolved. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2005-03-29 11:31 | csuwi | New Issue | |
| 2005-03-29 11:31 | csuwi | => bjb-ardour-dev@deus.net | |
| 2005-03-29 11:31 | csuwi | Name | => Ben Bell |
| 2005-04-01 12:43 | paul | Note Added: 0002154 | |
| 2005-04-01 12:43 | paul | Status | new => feedback |
| 2005-04-01 16:40 | csuwi | Note Added: 0002157 | |
| 2007-12-21 13:17 | drmoore | File Added: dm_timesig_patch | |
| 2007-12-21 13:20 | drmoore | Note Added: 0004609 | |
| 2007-12-21 15:01 | paul | Note Added: 0004610 | |
| 2007-12-28 21:46 | drmoore | File Added: dm_timesig_patch_trunk | |
| 2007-12-28 21:49 | drmoore | Note Added: 0004614 | |
| 2008-10-23 14:40 | csuwi | Note Added: 0005208 | |
| 2008-11-24 11:45 | seablade | cost | => 0.00 |
| 2008-11-24 11:45 | seablade | Status | feedback => resolved |
| 2008-11-24 11:45 | seablade | Resolution | open => fixed |
| 2008-11-24 11:45 | seablade | Assigned To | => seablade |
| 2008-11-24 11:45 | seablade | Note Added: 0005332 | |
| 2020-04-19 20:12 | system | Note Added: 0021449 | |
| 2020-04-19 20:12 | system | Status | resolved => closed |