Tempo ramps - first stab at metric marks locked to frames or beats.

- pretty much untested.
This commit is contained in:
nick_m 2016-02-28 04:59:34 +11:00
parent d8549c6ff5
commit bc42dea451
6 changed files with 404 additions and 62 deletions

View file

@ -3210,7 +3210,13 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
if (_copy == true) { if (_copy == true) {
_editor->begin_reversible_command (_("copy meter mark")); _editor->begin_reversible_command (_("copy meter mark"));
XMLNode &before = map.get_state(); XMLNode &before = map.get_state();
map.add_meter (_marker->meter(), map.beat_at_frame (_marker->position()), when);
if (_marker->meter().position_lock_style() == AudioTime) {
map.add_meter (_marker->meter(), _marker->position());
} else {
map.add_meter (_marker->meter(), map.bbt_to_beats (when), when);
}
XMLNode &after = map.get_state(); XMLNode &after = map.get_state();
_editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after)); _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
_editor->commit_reversible_command (); _editor->commit_reversible_command ();
@ -3219,8 +3225,12 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
_editor->begin_reversible_command (_("move meter mark")); _editor->begin_reversible_command (_("move meter mark"));
/* we removed it before, so add it back now */ /* we removed it before, so add it back now */
if (_marker->meter().position_lock_style() == AudioTime) {
map.add_meter (_marker->meter(), _marker->position());
} else {
map.add_meter (_marker->meter(), map.beat_at_frame (_marker->position()), when);
}
map.add_meter (_marker->meter(), map.beat_at_frame (_marker->position()), when);
XMLNode &after = map.get_state(); XMLNode &after = map.get_state();
_editor->session()->add_command(new MementoCommand<TempoMap>(map, before_state, &after)); _editor->session()->add_command(new MementoCommand<TempoMap>(map, before_state, &after));
_editor->commit_reversible_command (); _editor->commit_reversible_command ();
@ -3336,21 +3346,32 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
return; return;
} }
motion (event, false); //motion (event, false);
TempoMap& map (_editor->session()->tempo_map()); TempoMap& map (_editor->session()->tempo_map());
if (_copy == true) { if (_copy == true) {
_editor->begin_reversible_command (_("copy tempo mark")); _editor->begin_reversible_command (_("copy tempo mark"));
XMLNode &before = map.get_state(); XMLNode &before = map.get_state();
map.add_tempo (_marker->tempo(), _real_section->beat(), _marker->tempo().type());
if (_marker->tempo().position_lock_style() == MusicTime) {
map.add_tempo (_marker->tempo(), _real_section->beat(), _marker->tempo().type());
} else {
map.add_tempo (_marker->tempo(), _real_section->frame(), _marker->tempo().type());
}
XMLNode &after = map.get_state(); XMLNode &after = map.get_state();
_editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after)); _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
_editor->commit_reversible_command (); _editor->commit_reversible_command ();
} else { } else {
/* we removed it before, so add it back now */ /* we removed it before, so add it back now */
map.replace_tempo (*_real_section, _marker->tempo().beats_per_minute() , _real_section->beat(), _marker->tempo().type()); if (_marker->tempo().position_lock_style() == MusicTime) {
map.replace_tempo (*_real_section, _marker->tempo().beats_per_minute() , _real_section->beat(), _marker->tempo().type());
} else {
map.replace_tempo (*_real_section, _marker->tempo().beats_per_minute() , _real_section->frame(), _marker->tempo().type());
}
XMLNode &after = map.get_state(); XMLNode &after = map.get_state();
_editor->session()->add_command (new MementoCommand<TempoMap>(map, before_state, &after)); _editor->session()->add_command (new MementoCommand<TempoMap>(map, before_state, &after));
_editor->commit_reversible_command (); _editor->commit_reversible_command ();
@ -3368,7 +3389,11 @@ TempoMarkerDrag::aborted (bool moved)
if (moved) { if (moved) {
TempoMap& map (_editor->session()->tempo_map()); TempoMap& map (_editor->session()->tempo_map());
/* we removed it before, so add it back now */ /* we removed it before, so add it back now */
map.add_tempo (_marker->tempo(), _marker->tempo().beat(), _marker->tempo().type()); if (_marker->tempo().position_lock_style() == MusicTime) {
map.add_tempo (_marker->tempo(), _marker->tempo().beat(), _marker->tempo().type());
} else {
map.add_tempo (_marker->tempo(), _marker->tempo().frame(), _marker->tempo().type());
}
// delete the dummy marker we used for visual representation while moving. // delete the dummy marker we used for visual representation while moving.
// a new visual marker will show up automatically. // a new visual marker will show up automatically.
delete _marker; delete _marker;

View file

@ -238,16 +238,18 @@ Editor::mouse_add_new_tempo_event (framepos_t frame)
double bpm = 0; double bpm = 0;
Timecode::BBT_Time requested; Timecode::BBT_Time requested;
bpm = tempo_dialog.get_bpm (); bpm = tempo_dialog.get_bpm ();
double nt = tempo_dialog.get_note_type(); double nt = tempo_dialog.get_note_type();
bpm = max (0.01, bpm); bpm = max (0.01, bpm);
tempo_dialog.get_bbt_time (requested); tempo_dialog.get_bbt_time (requested);
begin_reversible_command (_("add tempo mark")); begin_reversible_command (_("add tempo mark"));
XMLNode &before = map.get_state(); XMLNode &before = map.get_state();
map.add_tempo (Tempo (bpm,nt), map.bbt_to_beats (requested), tempo_dialog.get_tempo_type()); if (tempo_dialog.get_lock_style() == MusicTime) {
map.add_tempo (Tempo (bpm,nt), map.bbt_to_beats (requested), tempo_dialog.get_tempo_type());
} else {
map.add_tempo (Tempo (bpm,nt), frame, tempo_dialog.get_tempo_type());
}
XMLNode &after = map.get_state(); XMLNode &after = map.get_state();
_session->add_command(new MementoCommand<TempoMap>(map, &before, &after)); _session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
commit_reversible_command (); commit_reversible_command ();
@ -286,7 +288,11 @@ Editor::mouse_add_new_meter_event (framepos_t frame)
begin_reversible_command (_("add meter mark")); begin_reversible_command (_("add meter mark"));
XMLNode &before = map.get_state(); XMLNode &before = map.get_state();
map.add_meter (Meter (bpb, note_type), map.bbt_to_beats (requested), requested); if (meter_dialog.get_lock_style() == MusicTime) {
map.add_meter (Meter (bpb, note_type), map.bbt_to_beats (requested), requested);
} else {
map.add_meter (Meter (bpb, note_type), frame, meter_dialog.get_lock_style());
}
_session->add_command(new MementoCommand<TempoMap>(map, &before, &map.get_state())); _session->add_command(new MementoCommand<TempoMap>(map, &before, &map.get_state()));
commit_reversible_command (); commit_reversible_command ();
@ -330,13 +336,17 @@ Editor::edit_meter_section (MeterSection* section)
bpb = max (1.0, bpb); // XXX is this a reasonable limit? bpb = max (1.0, bpb); // XXX is this a reasonable limit?
double note_type = meter_dialog.get_note_type (); double note_type = meter_dialog.get_note_type ();
Timecode::BBT_Time when; Timecode::BBT_Time when;
meter_dialog.get_bbt_time(when); meter_dialog.get_bbt_time(when);
framepos_t const frame = _session->tempo_map().frame_at_beat (_session->tempo_map().bbt_to_beats (when));
begin_reversible_command (_("replace tempo mark")); begin_reversible_command (_("replace tempo mark"));
XMLNode &before = _session->tempo_map().get_state(); XMLNode &before = _session->tempo_map().get_state();
_session->tempo_map().replace_meter (*section, Meter (bpb, note_type), when); if (meter_dialog.get_lock_style() == MusicTime) {
_session->tempo_map().replace_meter (*section, Meter (bpb, note_type), when);
} else {
_session->tempo_map().replace_meter (*section, Meter (bpb, note_type), frame);
}
XMLNode &after = _session->tempo_map().get_state(); XMLNode &after = _session->tempo_map().get_state();
_session->add_command(new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after)); _session->add_command(new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
commit_reversible_command (); commit_reversible_command ();
@ -356,13 +366,20 @@ Editor::edit_tempo_section (TempoSection* section)
double bpm = tempo_dialog.get_bpm (); double bpm = tempo_dialog.get_bpm ();
double nt = tempo_dialog.get_note_type (); double nt = tempo_dialog.get_note_type ();
double beat;
Timecode::BBT_Time when; Timecode::BBT_Time when;
tempo_dialog.get_bbt_time(when); tempo_dialog.get_bbt_time(when);
bpm = max (0.01, bpm); bpm = max (0.01, bpm);
beat = _session->tempo_map().bbt_to_beats (when);
begin_reversible_command (_("replace tempo mark")); begin_reversible_command (_("replace tempo mark"));
XMLNode &before = _session->tempo_map().get_state(); XMLNode &before = _session->tempo_map().get_state();
_session->tempo_map().replace_tempo (*section, Tempo (bpm, nt), _session->tempo_map().bbt_to_beats (when), tempo_dialog.get_tempo_type()); if (tempo_dialog.get_lock_style() == MusicTime) {
_session->tempo_map().replace_tempo (*section, Tempo (bpm, nt), beat, tempo_dialog.get_tempo_type());
} else {
_session->tempo_map().replace_tempo (*section, Tempo (bpm, nt), _session->tempo_map().frame_at_beat (beat), tempo_dialog.get_tempo_type());
}
XMLNode &after = _session->tempo_map().get_state(); XMLNode &after = _session->tempo_map().get_state();
_session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after)); _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
commit_reversible_command (); commit_reversible_command ();

View file

@ -47,7 +47,7 @@ TempoDialog::TempoDialog (TempoMap& map, framepos_t frame, const string&)
Tempo tempo (map.tempo_at (frame)); Tempo tempo (map.tempo_at (frame));
map.bbt_time (frame, when); map.bbt_time (frame, when);
init (when, tempo.beats_per_minute(), tempo.note_type(), TempoSection::Constant, true); init (when, tempo.beats_per_minute(), tempo.note_type(), TempoSection::Constant, true, PositionLockStyle::MusicTime);
} }
TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&) TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&)
@ -61,11 +61,11 @@ TempoDialog::TempoDialog (TempoMap& map, TempoSection& section, const string&)
{ {
Timecode::BBT_Time when; Timecode::BBT_Time when;
map.bbt_time (map.frame_at_beat (section.beat()), when); map.bbt_time (map.frame_at_beat (section.beat()), when);
init (when, section.beats_per_minute(), section.note_type(), section.type(), section.movable()); init (when, section.beats_per_minute(), section.note_type(), section.type(), section.movable(), section.position_lock_style());
} }
void void
TempoDialog::init (const Timecode::BBT_Time& when, double bpm, double note_type, TempoSection::Type type, bool movable) TempoDialog::init (const Timecode::BBT_Time& when, double bpm, double note_type, TempoSection::Type type, bool movable, PositionLockStyle style)
{ {
vector<string> strings; vector<string> strings;
NoteTypes::iterator x; NoteTypes::iterator x;
@ -123,15 +123,33 @@ TempoDialog::init (const Timecode::BBT_Time& when, double bpm, double note_type,
} }
} }
if (tt == tempo_types.end()) { if (tt == tempo_types.end()) {
tempo_type.set_active_text (strings[0]); // "ramped" tempo_type.set_active_text (strings[1]); // "constant"
}
strings.clear();
lock_styles.insert (make_pair (_("music"), PositionLockStyle::MusicTime));
strings.push_back (_("music"));
lock_styles.insert (make_pair (_("audio"), PositionLockStyle::AudioTime));
strings.push_back (_("audio"));
set_popdown_strings (lock_style, strings);
LockStyles::iterator ls;
for (ls = lock_styles.begin(); ls != lock_styles.end(); ++ls) {
if (ls->second == style) {
lock_style.set_active_text (ls->first);
break;
}
}
if (ls == lock_styles.end()) {
lock_style.set_active_text (strings[0]); // "music"
} }
Table* table; Table* table;
if (UIConfiguration::instance().get_allow_non_quarter_pulse()) { if (UIConfiguration::instance().get_allow_non_quarter_pulse()) {
table = manage (new Table (5, 6)); table = manage (new Table (5, 7));
} else { } else {
table = manage (new Table (5, 5)); table = manage (new Table (5, 6));
} }
table->set_spacings (6); table->set_spacings (6);
@ -182,6 +200,12 @@ TempoDialog::init (const Timecode::BBT_Time& when, double bpm, double note_type,
get_vbox()->set_border_width (12); get_vbox()->set_border_width (12);
get_vbox()->pack_end (*table); get_vbox()->pack_end (*table);
Label* lock_style_label = manage (new Label(_("Lock Style:"), ALIGN_LEFT, ALIGN_CENTER));
table->attach (*lock_style_label, 0, 1, row+2, row+3);
table->attach (lock_style, 1, 2, row+2, row + 3);
get_vbox()->set_border_width (12);
get_vbox()->pack_end (*table);
table->show_all (); table->show_all ();
add_button (Stock::CANCEL, RESPONSE_CANCEL); add_button (Stock::CANCEL, RESPONSE_CANCEL);
@ -206,6 +230,7 @@ TempoDialog::init (const Timecode::BBT_Time& when, double bpm, double note_type,
when_beat_entry.signal_key_release_event().connect (sigc::mem_fun (*this, &TempoDialog::entry_key_release), false); when_beat_entry.signal_key_release_event().connect (sigc::mem_fun (*this, &TempoDialog::entry_key_release), false);
pulse_selector.signal_changed().connect (sigc::mem_fun (*this, &TempoDialog::pulse_change)); pulse_selector.signal_changed().connect (sigc::mem_fun (*this, &TempoDialog::pulse_change));
tempo_type.signal_changed().connect (sigc::mem_fun (*this, &TempoDialog::tempo_type_change)); tempo_type.signal_changed().connect (sigc::mem_fun (*this, &TempoDialog::tempo_type_change));
lock_style.signal_changed().connect (sigc::mem_fun (*this, &TempoDialog::lock_style_change));
tap_tempo_button.signal_button_press_event().connect (sigc::mem_fun (*this, &TempoDialog::tap_tempo_button_press), false); tap_tempo_button.signal_button_press_event().connect (sigc::mem_fun (*this, &TempoDialog::tap_tempo_button_press), false);
tap_tempo_button.signal_focus_out_event().connect (sigc::mem_fun (*this, &TempoDialog::tap_tempo_focus_out)); tap_tempo_button.signal_focus_out_event().connect (sigc::mem_fun (*this, &TempoDialog::tap_tempo_focus_out));
@ -296,6 +321,19 @@ TempoDialog::get_tempo_type ()
return x->second; return x->second;
} }
PositionLockStyle
TempoDialog::get_lock_style ()
{
LockStyles::iterator x = lock_styles.find (lock_style.get_active_text());
if (x == lock_styles.end()) {
error << string_compose(_("incomprehensible lock style (%1)"), lock_style.get_active_text()) << endmsg;
return PositionLockStyle::MusicTime;
}
return x->second;
}
void void
TempoDialog::pulse_change () TempoDialog::pulse_change ()
{ {
@ -308,6 +346,12 @@ TempoDialog::tempo_type_change ()
set_response_sensitive (RESPONSE_ACCEPT, is_user_input_valid()); set_response_sensitive (RESPONSE_ACCEPT, is_user_input_valid());
} }
void
TempoDialog::lock_style_change ()
{
set_response_sensitive (RESPONSE_ACCEPT, is_user_input_valid());
}
bool bool
TempoDialog::tap_tempo_button_press (GdkEventButton *ev) TempoDialog::tap_tempo_button_press (GdkEventButton *ev)
{ {
@ -362,7 +406,7 @@ MeterDialog::MeterDialog (TempoMap& map, framepos_t frame, const string&)
Meter meter (map.meter_at(frame)); Meter meter (map.meter_at(frame));
map.bbt_time (frame, when); map.bbt_time (frame, when);
init (when, meter.divisions_per_bar(), meter.note_divisor(), true); init (when, meter.divisions_per_bar(), meter.note_divisor(), true, PositionLockStyle::MusicTime);
} }
MeterDialog::MeterDialog (TempoMap& map, MeterSection& section, const string&) MeterDialog::MeterDialog (TempoMap& map, MeterSection& section, const string&)
@ -370,11 +414,11 @@ MeterDialog::MeterDialog (TempoMap& map, MeterSection& section, const string&)
{ {
Timecode::BBT_Time when; Timecode::BBT_Time when;
map.bbt_time (map.frame_at_beat (section.beat()), when); map.bbt_time (map.frame_at_beat (section.beat()), when);
init (when, section.divisions_per_bar(), section.note_divisor(), section.movable()); init (when, section.divisions_per_bar(), section.note_divisor(), section.movable(), section.position_lock_style());
} }
void void
MeterDialog::init (const Timecode::BBT_Time& when, double bpb, double divisor, bool movable) MeterDialog::init (const Timecode::BBT_Time& when, double bpb, double divisor, bool movable, PositionLockStyle style)
{ {
char buf[64]; char buf[64];
vector<string> strings; vector<string> strings;
@ -417,9 +461,28 @@ MeterDialog::init (const Timecode::BBT_Time& when, double bpb, double divisor, b
note_type.set_active_text (strings[3]); // "quarter" note_type.set_active_text (strings[3]); // "quarter"
} }
strings.clear();
lock_styles.insert (make_pair (_("music"), PositionLockStyle::MusicTime));
strings.push_back (_("music"));
lock_styles.insert (make_pair (_("audio ur brane wul xplod"), PositionLockStyle::AudioTime));
strings.push_back (_("audio"));
set_popdown_strings (lock_style, strings);
LockStyles::iterator ls;
for (ls = lock_styles.begin(); ls != lock_styles.end(); ++ls) {
if (ls->second == style) {
lock_style.set_active_text (ls->first);
break;
}
}
if (ls == lock_styles.end()) {
lock_style.set_active_text (strings[0]); // "music"
}
Label* note_label = manage (new Label (_("Note value:"), ALIGN_LEFT, ALIGN_CENTER)); Label* note_label = manage (new Label (_("Note value:"), ALIGN_LEFT, ALIGN_CENTER));
Label* lock_label = manage (new Label (_("Lock style:"), ALIGN_LEFT, ALIGN_CENTER));
Label* bpb_label = manage (new Label (_("Beats per bar:"), ALIGN_LEFT, ALIGN_CENTER)); Label* bpb_label = manage (new Label (_("Beats per bar:"), ALIGN_LEFT, ALIGN_CENTER));
Table* table = manage (new Table (3, 2)); Table* table = manage (new Table (3, 3));
table->set_spacings (6); table->set_spacings (6);
table->attach (*bpb_label, 0, 1, 0, 1, FILL|EXPAND, FILL|EXPAND); table->attach (*bpb_label, 0, 1, 0, 1, FILL|EXPAND, FILL|EXPAND);
@ -438,6 +501,9 @@ MeterDialog::init (const Timecode::BBT_Time& when, double bpb, double divisor, b
table->attach (when_bar_entry, 1, 2, 2, 3, FILL | EXPAND, FILL | EXPAND); table->attach (when_bar_entry, 1, 2, 2, 3, FILL | EXPAND, FILL | EXPAND);
} }
table->attach (*lock_label, 0, 1, 3, 4, FILL|EXPAND, FILL|EXPAND);
table->attach (lock_style, 1, 2, 3, 4, FILL|EXPAND, SHRINK);
get_vbox()->set_border_width (12); get_vbox()->set_border_width (12);
get_vbox()->pack_start (*table, false, false); get_vbox()->pack_start (*table, false, false);
@ -456,6 +522,8 @@ MeterDialog::init (const Timecode::BBT_Time& when, double bpb, double divisor, b
when_bar_entry.signal_key_press_event().connect (sigc::mem_fun (*this, &MeterDialog::entry_key_press), false); when_bar_entry.signal_key_press_event().connect (sigc::mem_fun (*this, &MeterDialog::entry_key_press), false);
when_bar_entry.signal_key_release_event().connect (sigc::mem_fun (*this, &MeterDialog::entry_key_release)); when_bar_entry.signal_key_release_event().connect (sigc::mem_fun (*this, &MeterDialog::entry_key_release));
note_type.signal_changed().connect (sigc::mem_fun (*this, &MeterDialog::note_type_change)); note_type.signal_changed().connect (sigc::mem_fun (*this, &MeterDialog::note_type_change));
lock_style.signal_changed().connect (sigc::mem_fun (*this, &MeterDialog::lock_style_change));
} }
bool bool
@ -527,6 +595,12 @@ MeterDialog::note_type_change ()
set_response_sensitive (RESPONSE_ACCEPT, is_user_input_valid()); set_response_sensitive (RESPONSE_ACCEPT, is_user_input_valid());
} }
void
MeterDialog::lock_style_change ()
{
set_response_sensitive (RESPONSE_ACCEPT, is_user_input_valid());
}
double double
MeterDialog::get_bpb () MeterDialog::get_bpb ()
{ {
@ -552,6 +626,19 @@ MeterDialog::get_note_type ()
return x->second; return x->second;
} }
PositionLockStyle
MeterDialog::get_lock_style ()
{
LockStyles::iterator x = lock_styles.find (lock_style.get_active_text());
if (x == lock_styles.end()) {
error << string_compose(_("incomprehensible meter lock style (%1)"), lock_style.get_active_text()) << endmsg;
return PositionLockStyle::MusicTime;
}
return x->second;
}
bool bool
MeterDialog::get_bbt_time (Timecode::BBT_Time& requested) MeterDialog::get_bbt_time (Timecode::BBT_Time& requested)
{ {

View file

@ -45,9 +45,10 @@ public:
double get_note_type (); double get_note_type ();
bool get_bbt_time (Timecode::BBT_Time&); bool get_bbt_time (Timecode::BBT_Time&);
ARDOUR::TempoSection::Type get_tempo_type (); ARDOUR::TempoSection::Type get_tempo_type ();
ARDOUR::PositionLockStyle get_lock_style ();
private: private:
void init (const Timecode::BBT_Time& start, double bpm , double note_type, ARDOUR::TempoSection::Type type, bool movable); void init (const Timecode::BBT_Time& start, double bpm , double note_type, ARDOUR::TempoSection::Type type, bool movable, ARDOUR::PositionLockStyle style);
bool is_user_input_valid() const; bool is_user_input_valid() const;
void bpm_changed (); void bpm_changed ();
bool bpm_button_press (GdkEventButton* ); bool bpm_button_press (GdkEventButton* );
@ -55,6 +56,7 @@ private:
bool entry_key_release (GdkEventKey* ); bool entry_key_release (GdkEventKey* );
void pulse_change (); void pulse_change ();
void tempo_type_change (); void tempo_type_change ();
void lock_style_change ();
bool tap_tempo_button_press (GdkEventButton* ); bool tap_tempo_button_press (GdkEventButton* );
bool tap_tempo_focus_out (GdkEventFocus* ); bool tap_tempo_focus_out (GdkEventFocus* );
@ -64,6 +66,9 @@ private:
typedef std::map<std::string, ARDOUR::TempoSection::Type> TempoTypes; typedef std::map<std::string, ARDOUR::TempoSection::Type> TempoTypes;
TempoTypes tempo_types; TempoTypes tempo_types;
typedef std::map<std::string, ARDOUR::PositionLockStyle> LockStyles;
LockStyles lock_styles;
bool tapped; // whether the tap-tempo button has been clicked bool tapped; // whether the tap-tempo button has been clicked
double sum_x, sum_xx, sum_xy, sum_y; double sum_x, sum_xx, sum_xy, sum_y;
double tap_count; double tap_count;
@ -80,6 +85,8 @@ private:
Gtk::Label pulse_selector_label; Gtk::Label pulse_selector_label;
Gtk::Button tap_tempo_button; Gtk::Button tap_tempo_button;
Gtk::ComboBoxText tempo_type; Gtk::ComboBoxText tempo_type;
Gtk::ComboBoxText lock_style;
}; };
@ -92,20 +99,26 @@ public:
double get_bpb (); double get_bpb ();
double get_note_type (); double get_note_type ();
ARDOUR::PositionLockStyle get_lock_style ();
bool get_bbt_time (Timecode::BBT_Time&); bool get_bbt_time (Timecode::BBT_Time&);
private: private:
void init (const Timecode::BBT_Time&, double, double, bool); void init (const Timecode::BBT_Time&, double, double, bool, ARDOUR::PositionLockStyle style);
bool is_user_input_valid() const; bool is_user_input_valid() const;
bool entry_key_press (GdkEventKey* ); bool entry_key_press (GdkEventKey* );
bool entry_key_release (GdkEventKey* ); bool entry_key_release (GdkEventKey* );
void note_type_change (); void note_type_change ();
void lock_style_change ();
typedef std::map<std::string,float> NoteTypes; typedef std::map<std::string,float> NoteTypes;
NoteTypes note_types; NoteTypes note_types;
typedef std::map<std::string, ARDOUR::PositionLockStyle> LockStyles;
LockStyles lock_styles;
Gtk::Entry bpb_entry; Gtk::Entry bpb_entry;
Gtk::ComboBoxText note_type; Gtk::ComboBoxText note_type;
Gtk::ComboBoxText lock_style;
std::vector<std::string> strings; std::vector<std::string> strings;
Gtk::Button ok_button; Gtk::Button ok_button;
Gtk::Button cancel_button; Gtk::Button cancel_button;

View file

@ -100,9 +100,9 @@ class LIBARDOUR_API Meter {
class LIBARDOUR_API MetricSection { class LIBARDOUR_API MetricSection {
public: public:
MetricSection (double beat) MetricSection (double beat)
: _beat (beat), _frame (0), _movable (true), _position_lock_style (MusicTime) {} : _beat (beat), _frame (0), _movable (true), _position_lock_style (PositionLockStyle::MusicTime) {}
MetricSection (framepos_t frame) MetricSection (framepos_t frame)
: _beat (0), _frame (frame), _movable (true), _position_lock_style (MusicTime) {} : _beat (0), _frame (frame), _movable (true), _position_lock_style (PositionLockStyle::AudioTime) {}
virtual ~MetricSection() {} virtual ~MetricSection() {}
@ -362,14 +362,20 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
const MeterSection& meter_section_at (framepos_t) const; const MeterSection& meter_section_at (framepos_t) const;
void add_tempo (const Tempo&, double where, TempoSection::Type type); void add_tempo (const Tempo&, double where, TempoSection::Type type);
void add_tempo (const Tempo&, framepos_t frame, TempoSection::Type type);
void add_meter (const Meter&, double beat, Timecode::BBT_Time where); void add_meter (const Meter&, double beat, Timecode::BBT_Time where);
void add_meter (const Meter&, framepos_t frame);
void remove_tempo (const TempoSection&, bool send_signal); void remove_tempo (const TempoSection&, bool send_signal);
void remove_meter (const MeterSection&, bool send_signal); void remove_meter (const MeterSection&, bool send_signal);
void replace_tempo (const TempoSection&, const Tempo&, const double& where, TempoSection::Type type); void replace_tempo (const TempoSection&, const Tempo&, const double& where, TempoSection::Type type);
void replace_tempo (const TempoSection&, const Tempo&, const framepos_t& where, TempoSection::Type type);
void gui_set_tempo_frame (TempoSection&, framepos_t where, double beat); void gui_set_tempo_frame (TempoSection&, framepos_t where, double beat);
void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where); void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
void replace_meter (const MeterSection&, const Meter&, const framepos_t& frame);
framepos_t round_to_bar (framepos_t frame, RoundMode dir); framepos_t round_to_bar (framepos_t frame, RoundMode dir);
framepos_t round_to_beat (framepos_t frame, RoundMode dir); framepos_t round_to_beat (framepos_t frame, RoundMode dir);
@ -435,7 +441,10 @@ private:
void do_insert (MetricSection* section); void do_insert (MetricSection* section);
void add_tempo_locked (const Tempo&, double where, bool recompute, TempoSection::Type type); void add_tempo_locked (const Tempo&, double where, bool recompute, TempoSection::Type type);
void add_tempo_locked (const Tempo&, framepos_t frame, bool recompute, TempoSection::Type type);
void add_meter_locked (const Meter&, double beat, Timecode::BBT_Time where, bool recompute); void add_meter_locked (const Meter&, double beat, Timecode::BBT_Time where, bool recompute);
void add_meter_locked (const Meter&, framepos_t frame, bool recompute);
bool remove_tempo_locked (const TempoSection&); bool remove_tempo_locked (const TempoSection&);
bool remove_meter_locked (const MeterSection&); bool remove_meter_locked (const MeterSection&);

View file

@ -80,6 +80,7 @@ TempoSection::TempoSection (const XMLNode& node)
LocaleGuard lg; LocaleGuard lg;
BBT_Time bbt; BBT_Time bbt;
double beat; double beat;
uint32_t frame;
if ((prop = node.property ("start")) != 0) { if ((prop = node.property ("start")) != 0) {
if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
@ -102,8 +103,13 @@ TempoSection::TempoSection (const XMLNode& node)
} else { } else {
set_beat (beat); set_beat (beat);
} }
} else { }
error << _("TempoSection XML node has no \"beat\" property") << endmsg; 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) { if ((prop = node.property ("beats-per-minute")) == 0) {
@ -147,6 +153,12 @@ TempoSection::TempoSection (const XMLNode& node)
} else { } else {
_type = Type (string_2_enum (prop->value(), _type)); _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())));
}
} }
XMLNode& XMLNode&
@ -158,6 +170,8 @@ TempoSection::get_state() const
snprintf (buf, sizeof (buf), "%f", beat()); snprintf (buf, sizeof (buf), "%f", beat());
root->add_property ("beat", buf); root->add_property ("beat", buf);
snprintf (buf, sizeof (buf), "%li", frame());
root->add_property ("frame", buf);
snprintf (buf, sizeof (buf), "%f", _beats_per_minute); snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
root->add_property ("beats-per-minute", buf); root->add_property ("beats-per-minute", buf);
snprintf (buf, sizeof (buf), "%f", _note_type); snprintf (buf, sizeof (buf), "%f", _note_type);
@ -167,6 +181,7 @@ TempoSection::get_state() const
snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no"); snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
root->add_property ("movable", buf); root->add_property ("movable", buf);
root->add_property ("tempo-type", enum_2_string (_type)); root->add_property ("tempo-type", enum_2_string (_type));
root->add_property ("lock-style", enum_2_string (position_lock_style()));
return *root; return *root;
} }
@ -282,7 +297,7 @@ Duration in beats at time a is the integral of some Tempo function.
In our case, the Tempo function (Tempo at time t) is In our case, the Tempo function (Tempo at time t) is
T(t) = T0(e^(ct)) T(t) = T0(e^(ct))
where c is the function constant with function constant
c = log(Ta/T0)/a c = log(Ta/T0)/a
so so
a = log(Ta/T0)/c a = log(Ta/T0)/c
@ -298,17 +313,16 @@ t(T) = log(T / T0) / c
We define c for this tempo ramp by placing a new tempo section at some time t after this one. 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. Our problem is that we usually don't know t.
We usually do know the duration in beats between this and the next tempo section. 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 t = a (i.e. when a is equal to the time of the next tempo section), we can solve t in terms of Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
beat duration and our two tempos.
A bit of scribbling with the beat function gives us:
t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1)) t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
By substituting our expanded t as a in the c function above, we see that our problem is reduced to: 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 c = T0 (e^(log (Ta / T0)) - 1) / b
We can now evaluate and store c for use in beat, time and tempo calculations until the following tempo section We can now store c for future time calculations.
(the one that defines c in conjunction with this one) is changed or moved. If the following tempo section (the one that defines c in conjunction with this one)
is changed or moved, c is no longer valid.
Most of this stuff is taken from this paper: Most of this stuff is taken from this paper:
@ -440,6 +454,7 @@ MeterSection::MeterSection (const XMLNode& node)
const XMLProperty *prop; const XMLProperty *prop;
BBT_Time bbt; BBT_Time bbt;
double beat = 0.0; double beat = 0.0;
framepos_t frame = 0;
pair<double, BBT_Time> start; pair<double, BBT_Time> start;
if ((prop = node.property ("start")) != 0) { if ((prop = node.property ("start")) != 0) {
@ -460,8 +475,6 @@ MeterSection::MeterSection (const XMLNode& node)
if (sscanf (prop->value().c_str(), "%lf", &beat) != 1 || beat < 0.0) { if (sscanf (prop->value().c_str(), "%lf", &beat) != 1 || beat < 0.0) {
error << _("MeterSection XML node has an illegal \"beat\" value") << endmsg; error << _("MeterSection XML node has an illegal \"beat\" value") << endmsg;
} }
} else {
error << _("MeterSection XML node has no \"beat\" property") << endmsg;
} }
start.first = beat; start.first = beat;
@ -480,6 +493,14 @@ MeterSection::MeterSection (const XMLNode& node)
set_beat (start); 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 */ /* beats-per-bar is old; divisions-per-bar is new */
if ((prop = node.property ("divisions-per-bar")) == 0) { if ((prop = node.property ("divisions-per-bar")) == 0) {
@ -504,6 +525,14 @@ MeterSection::MeterSection (const XMLNode& node)
throw failed_constructor(); throw failed_constructor();
} }
if ((prop = node.property ("lock-style")) == 0) {
warning << _("MeterSection XML node has no \"lock-style\" property") << endmsg;
//throw failed_constructor();
set_position_lock_style (PositionLockStyle::MusicTime);
} else {
set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
}
if ((prop = node.property ("movable")) == 0) { if ((prop = node.property ("movable")) == 0) {
error << _("MeterSection XML node has no \"movable\" property") << endmsg; error << _("MeterSection XML node has no \"movable\" property") << endmsg;
throw failed_constructor(); throw failed_constructor();
@ -527,7 +556,10 @@ MeterSection::get_state() const
snprintf (buf, sizeof (buf), "%lf", beat()); snprintf (buf, sizeof (buf), "%lf", beat());
root->add_property ("beat", buf); root->add_property ("beat", buf);
snprintf (buf, sizeof (buf), "%f", _note_type); snprintf (buf, sizeof (buf), "%f", _note_type);
root->add_property ("frame", buf);
snprintf (buf, sizeof (buf), "%li", frame());
root->add_property ("note-type", buf); root->add_property ("note-type", buf);
root->add_property ("lock-style", enum_2_string (position_lock_style()));
snprintf (buf, sizeof (buf), "%f", _divisions_per_bar); snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
root->add_property ("divisions-per-bar", buf); root->add_property ("divisions-per-bar", buf);
snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no"); snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
@ -697,8 +729,9 @@ TempoMap::do_insert (MetricSection* section)
if (tempo && insert_tempo) { if (tempo && insert_tempo) {
/* Tempo sections */ /* Tempo sections */
PositionLockStyle const tpl = tempo->position_lock_style();
if (tempo->beat() == insert_tempo->beat()) { PositionLockStyle const ipl = insert_tempo->position_lock_style();
if (tpl == ipl && ((ipl == MusicTime && tempo->beat() == insert_tempo->beat()) || (ipl == AudioTime && tempo->frame() == insert_tempo->frame()))) {
if (!tempo->movable()) { if (!tempo->movable()) {
@ -720,7 +753,10 @@ TempoMap::do_insert (MetricSection* section)
/* Meter Sections */ /* Meter Sections */
MeterSection* const meter = dynamic_cast<MeterSection*> (*i); MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section); MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
if (meter->beat() == insert_meter->beat()) { PositionLockStyle const mpl = meter->position_lock_style();
PositionLockStyle const ipl = insert_meter->position_lock_style();
if (mpl == ipl && ((ipl == MusicTime && meter->beat() == insert_meter->beat()) || (ipl == AudioTime && meter->frame() == insert_meter->frame()))) {
if (!meter->movable()) { if (!meter->movable()) {
@ -756,8 +792,14 @@ TempoMap::do_insert (MetricSection* section)
for (i = metrics.begin(); i != metrics.end(); ++i) { for (i = metrics.begin(); i != metrics.end(); ++i) {
MeterSection* const meter = dynamic_cast<MeterSection*> (*i); MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
if (meter && meter->beat() > insert_meter->beat()) { if (meter) {
break; PositionLockStyle const ipl = insert_meter->position_lock_style();
if (ipl == MusicTime && meter->beat() > insert_meter->beat()) {
break;
}
if (ipl == AudioTime && meter->frame() > insert_meter->frame()) {
break;
}
} }
} }
} else if (insert_tempo) { } else if (insert_tempo) {
@ -765,7 +807,8 @@ TempoMap::do_insert (MetricSection* section)
TempoSection* const tempo = dynamic_cast<TempoSection*> (*i); TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
if (tempo) { if (tempo) {
if (tempo->beat() > insert_tempo->beat()) { PositionLockStyle const ipl = insert_tempo->position_lock_style();
if ((ipl == MusicTime && tempo->beat() > insert_tempo->beat()) || (ipl == AudioTime && tempo->frame() > insert_tempo->frame())) {
break; break;
} }
} }
@ -798,20 +841,60 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const doubl
PropertyChanged (PropertyChange ()); PropertyChanged (PropertyChange ());
} }
void
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.beat() != first.beat()) {
remove_tempo_locked (ts);
add_tempo_locked (tempo, frame, true, type);
} else {
first.set_type (type);
{
/* cannot move the first tempo section */
*static_cast<Tempo*>(&first) = tempo;
recompute_map (false);
}
}
}
PropertyChanged (PropertyChange ());
}
void void
TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame, double beat_where) TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame, double beat_where)
{ {
{ {
Glib::Threads::RWLock::WriterLock lm (lock); Glib::Threads::RWLock::WriterLock lm (lock);
/* currently this is always done in audio time */ if (ts.position_lock_style() == MusicTime) {
//if (ts.position_lock_style() == MusicTime) { std::cerr << "Music " << " beat where : " << beat_where << " frame : " << frame <<std::endl;
if (0) {
/* MusicTime */ /* MusicTime */
ts.set_beat (beat_where); ts.set_beat (beat_where);
Metrics::const_iterator i;
TempoSection* prev_ts = 0;
MetricSectionSorter cmp; MetricSectionSorter cmp;
metrics.sort (cmp); metrics.sort (cmp);
for (i = metrics.begin(); i != metrics.end(); ++i) {
TempoSection* t;
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
if (t->beat() >= beat_where) {
break;
}
prev_ts = t;
}
}
prev_ts->set_c_func_from_tempo_and_beat (ts.beats_per_minute(), ts.beat() - prev_ts->beat(), _frame_rate);
ts.set_frame (prev_ts->frame_at_beat (ts.beat() - prev_ts->beat(), _frame_rate));
} else { } else {
std::cerr << "Audio " << " beat where : " << beat_where << " frame : " << frame <<std::endl;
/*AudioTime*/ /*AudioTime*/
ts.set_frame (frame); ts.set_frame (frame);
MetricSectionFrameSorter fcmp; MetricSectionFrameSorter fcmp;
@ -892,9 +975,22 @@ TempoMap::add_tempo (const Tempo& tempo, double where, ARDOUR::TempoSection::Typ
PropertyChanged (PropertyChange ()); PropertyChanged (PropertyChange ());
} }
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);
}
PropertyChanged (PropertyChange ());
}
void void
TempoMap::add_tempo_locked (const Tempo& tempo, double where, bool recompute, ARDOUR::TempoSection::Type type) 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); TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
do_insert (ts); do_insert (ts);
@ -904,6 +1000,19 @@ TempoMap::add_tempo_locked (const Tempo& tempo, double where, bool recompute, AR
} }
} }
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);
std::cerr << "add tempo locked frame = " << ts->frame() << " pos lock : " << ts->position_lock_style() << std::endl;
do_insert (ts);
if (recompute) {
recompute_map (false);
}
}
void void
TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where) TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
{ {
@ -923,6 +1032,26 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T
PropertyChanged (PropertyChange ()); PropertyChanged (PropertyChange ());
} }
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, frame, true);
} else {
/* cannot move the first meter section */
*static_cast<Meter*>(&first) = meter;
recompute_map (true);
}
}
PropertyChanged (PropertyChange ());
}
void void
TempoMap::add_meter (const Meter& meter, double beat, BBT_Time where) TempoMap::add_meter (const Meter& meter, double beat, BBT_Time where)
{ {
@ -932,6 +1061,24 @@ TempoMap::add_meter (const Meter& meter, double beat, BBT_Time where)
} }
#ifndef NDEBUG
if (DEBUG_ENABLED(DEBUG::TempoMap)) {
dump (std::cerr);
}
#endif
PropertyChanged (PropertyChange ());
}
void
TempoMap::add_meter (const Meter& meter, framepos_t frame)
{
{
Glib::Threads::RWLock::WriterLock lm (lock);
add_meter_locked (meter, frame, true);
}
#ifndef NDEBUG #ifndef NDEBUG
if (DEBUG_ENABLED(DEBUG::TempoMap)) { if (DEBUG_ENABLED(DEBUG::TempoMap)) {
dump (std::cerr); dump (std::cerr);
@ -967,6 +1114,29 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
} }
void
TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, bool recompute)
{
/* MusicTime meters *always* start on 1|1|0. */
MeterSection* ms = new MeterSection (frame, meter.divisions_per_bar(), meter.note_divisor());
BBT_Time bbt;
pair<double, BBT_Time> pr;
bbt.bars = 1;
bbt.beats = 1;
bbt.ticks = 0;
/* just a dummy - the actual beat should be applied in recompute_map() as thins is AudioTime */
pr.first = 0.0;
pr.second = bbt;
ms->set_beat (pr);
do_insert (ms);
if (recompute) {
recompute_map (true);
}
}
void void
TempoMap::change_initial_tempo (double beats_per_minute, double note_type) TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
{ {
@ -1126,37 +1296,58 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
} }
Metrics::const_iterator i; Metrics::const_iterator i;
TempoSection* prev_ts = 0; TempoSection* prev_ts = 0;
for (i = metrics.begin(); i != metrics.end(); ++i) { for (i = metrics.begin(); i != metrics.end(); ++i) {
TempoSection* t; TempoSection* t;
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
if (prev_ts) { if (prev_ts) {
if (prev_ts->type() == TempoSection::Ramp) { if (t->position_lock_style() == AudioTime) {
prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat() - prev_ts->beat(), _frame_rate); if (prev_ts->type() == TempoSection::Ramp) {
t->set_frame (prev_ts->frame_at_tempo (t->beats_per_minute(), _frame_rate) + prev_ts->frame()); prev_ts->set_c_func (prev_ts->compute_c_func (t->beats_per_minute(), t->frame() - prev_ts->frame(), _frame_rate));
} else { t->set_beat (prev_ts->beat_at_frame (t->frame() - prev_ts->frame(), _frame_rate) + prev_ts->beat());
double const ticks_relative_to_prev = (t->beat() - prev_ts->beat()) * BBT_Time::ticks_per_beat; } else {
framecnt_t const duration = (framecnt_t) floor (ticks_relative_to_prev * prev_ts->frames_per_beat (_frame_rate) prev_ts->set_c_func (0.0);
* BBT_Time::ticks_per_beat); t->set_beat (prev_ts->beat_at_frame (t->frame() - prev_ts->frame(), _frame_rate) + prev_ts->beat());
prev_ts->set_c_func (0.0); }
t->set_frame (duration + prev_ts->frame()); } else if (t->position_lock_style() == MusicTime) {
if (prev_ts->type() == TempoSection::Ramp) {
prev_ts->set_c_func_from_tempo_and_beat (t->beats_per_minute(), t->beat() - prev_ts->beat(), _frame_rate);
t->set_frame (prev_ts->frame_at_beat (t->beat() - prev_ts->beat(), _frame_rate) + prev_ts->frame());
} else {
double const ticks_relative_to_prev = (t->beat() - prev_ts->beat()) * BBT_Time::ticks_per_beat;
framecnt_t const duration = (framecnt_t) floor (ticks_relative_to_prev * prev_ts->frames_per_beat (_frame_rate)
* BBT_Time::ticks_per_beat);
prev_ts->set_c_func (0.0);
t->set_frame (duration + prev_ts->frame());
}
} }
} }
prev_ts = t; prev_ts = t;
} }
} }
Metrics::const_iterator mi;
MeterSection* meter = 0; MeterSection* meter = 0;
for (mi = metrics.begin(); mi != metrics.end(); ++mi) { for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
/* We now have the tempo map set. use it to set meter positions.*/ /* We now have the tempo map set. use it to set meter positions.*/
if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) { if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
meter->set_frame (frame_at_tick (meter->beat() * BBT_Time::ticks_per_beat)); 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 = tick_at_frame (meter->frame()) / BBT_Time::ticks_per_beat;
pr.second = where;
meter->set_beat (pr);
} else if (meter->position_lock_style() == MusicTime) {
meter->set_frame (frame_at_tick (meter->beat() * BBT_Time::ticks_per_beat));
}
} }
} }
} }