framepos_t pf;
double beat = 0.0;
-
- if (!_editor->snap_musical()) {
- pf = adjusted_current_frame (event);
- } else {
- pf = adjusted_current_frame (event, false);
- Timecode::BBT_Time when;
- _editor->session()->tempo_map().bbt_time (pf, when);
- if (_real_section->position_lock_style() == MusicTime) {
- if (_editor->snap_type() == SnapToBar) {
- _editor->session()->tempo_map().round_bbt (when, -1);
- } else {
- _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0));
- }
- beat = _editor->session()->tempo_map().bbt_to_beats (when);
- } else {
- if (_editor->snap_type() == SnapToBar) {
- _editor->session()->tempo_map().round_bbt (when, -1);
- } else {
- _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0));
- }
- pf = _editor->session()->tempo_map().predict_tempo_frame (_real_section, Tempo (_real_section->beats_per_minute(), _real_section->note_type()), when);
- }
- }
Tempo const tp = _marker->tempo();
if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::constraint_modifier ())) {
strs << new_bpm;
show_verbose_cursor_text (strs.str());
} else if (_movable) {
-
- if (_real_section->position_lock_style() == MusicTime) {
- _editor->session()->tempo_map().gui_move_tempo_beat (_real_section, tp, beat);
+ if (!_editor->snap_musical()) {
+ pf = adjusted_current_frame (event);
} else {
- _editor->session()->tempo_map().gui_move_tempo_frame (_real_section, tp, pf);
+ pf = adjusted_current_frame (event, false);
+ bool use_snap;
+
+ if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::snap_modifier ())) {
+ if (_editor->snap_mode() == Editing::SnapOff) {
+ use_snap = true;
+ } else {
+ use_snap = false;
+ }
+ } else {
+ if (_editor->snap_mode() == Editing::SnapOff) {
+ use_snap = false;
+ } else {
+ use_snap = true;
+ }
+ }
+
+ Timecode::BBT_Time when;
+ _editor->session()->tempo_map().bbt_time (pf, when);
+ if (_real_section->position_lock_style() == MusicTime) {
+ if (use_snap && _editor->snap_type() == SnapToBar) {
+ _editor->session()->tempo_map().round_bbt (when, -1);
+ } else if (use_snap) {
+ _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0));
+ }
+ beat = _editor->session()->tempo_map().bbt_to_beats (when);
+ _editor->session()->tempo_map().gui_move_tempo_beat (_real_section, tp, beat);
+ } else {
+ if (use_snap && _editor->snap_type() == SnapToBar) {
+ _editor->session()->tempo_map().round_bbt (when, -1);
+ } else if (use_snap) {
+ _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0));
+ }
+ pf = _editor->session()->tempo_map().predict_tempo_frame (_real_section, Tempo (_real_section->beats_per_minute(), _real_section->note_type()), when);
+ _editor->session()->tempo_map().gui_move_tempo_frame (_real_section, tp, pf);
+ }
}
+
show_verbose_cursor_time (pf);
}
_marker->set_position (pf);
}
/***********************************************************************/
-
+/*
+ Tempo Map Overview
+
+ We have tempos, which are nice to think of in whole pulses per minute,
+ and meters which divide tempo pulses into bars (via divisions_per_bar)
+ and beats (via note_divisor).
+ Tempos and meters may be locked to audio or music.
+ Because the notion of a beat cannot be determined without both tempo and meter, the first tempo
+ and first meter are special. they must move together, and must be locked to audio.
+ Audio locked tempos which lie before the first meter are made inactive.
+ They will be re-activated if the first meter is again placed before them.
+
+ Both tempos and meters have a pulse position and a frame position.
+ Recomputing the tempo map is the process where the 'missing' position
+ (pulse in the case of AudioTime and frame for MusicTime) is calculated
+ based on the lock preference (position_lock_style).
+
+ It is important to keep the _metrics in an order that makes sense.
+ Because ramped MusicTime and AudioTime tempos can interact with each other
+ and cause reordering, care must be taken to keep _metrics in a solved state.
+ Solved means ordered by frame or pulse with frame-accurate precision (see check_solved()).
+*/
struct MetricSectionSorter {
bool operator() (const MetricSection* a, const MetricSection* b) {
return a->pulse() < b->pulse();
if ((by_frame && t->frame() < prev_ts->frame()) || (!by_frame && t->pulse() < prev_ts->pulse())) {
return false;
}
- if (by_frame && t->frame() != prev_ts->frame_at_pulse (t->pulse(), _frame_rate)) {
+ /* precision check ensures pulses and frames align independent of lock style.*/
+ if (t->frame() != prev_ts->frame_at_pulse (t->pulse(), _frame_rate)) {
return false;
}
- /*
- if (!by_frame && fabs (t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate)) > 0.00001) {
- std::cerr << "beat precision too low for bpm: " << t->beats_per_minute() << std::endl <<
- " |error :" << t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) << std::endl <<
- "|frame at beat :" << prev_ts->frame_at_pulse (t->pulse(), _frame_rate) << std::endl <<
- " |frame at tempo : " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
- return false;
- }
- */
}
prev_ts = t;
}