if (prev_t) {
if (t == section) {
section_prev = prev_t;
+ if (t->locked_to_meter()) {
+ prev_t = t;
+ }
continue;
}
if (t->position_lock_style() == MusicTime) {
}
void
-TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame)
+TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame, const int& sub_num)
{
Metrics future_map;
+ bool was_musical = ts->position_lock_style() == MusicTime;
+
+ if (sub_num == 0 && was_musical) {
+ /* if we're not snapping to music,
+ AudioTime and MusicTime may be treated identically.
+ */
+ ts->set_position_lock_style (AudioTime);
+ }
if (ts->position_lock_style() == MusicTime) {
{
+ /* if we're snapping to a musical grid, set the pulse exactly instead of via the supplied frame. */
Glib::Threads::RWLock::WriterLock lm (lock);
TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- const double pulse = pulse_at_frame_locked (future_map, frame);
+ double beat = beat_at_frame_locked (future_map, frame);
+
+ if (sub_num > 1) {
+ beat = floor (beat) + (floor (((beat - floor (beat)) * (double) sub_num) + 0.5) / sub_num);
+ } else if (sub_num == 1) {
+ /* snap to beat */
+ beat = floor (beat + 0.5);
+ }
+
+ double pulse = pulse_at_beat_locked (future_map, beat);
+
+ if (sub_num == -1) {
+ /* snap to bar */
+ BBT_Time bbt = bbt_at_beat_locked (future_map, beat);
+ bbt.beats = 1;
+ bbt.ticks = 0;
+ pulse = pulse_at_bbt_locked (future_map, bbt);
+ }
+
if (solve_map_pulse (future_map, tempo_copy, pulse)) {
solve_map_pulse (_metrics, ts, pulse);
recompute_meters (_metrics);
}
}
+ if (sub_num == 0 && was_musical) {
+ ts->set_position_lock_style (MusicTime);
+ }
+
Metrics::const_iterator d = future_map.begin();
while (d != future_map.end()) {
delete (*d);
}
}
}
+ /* minimum allowed measurement distance in frames */
+ const framepos_t min_dframe = 2;
/* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
if (prev_t->position_lock_style() == MusicTime) {
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
- new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
- / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
-
+ new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
+ / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
} else {
/* prev to prev is irrelevant */
- if (start_pulse != prev_t->pulse()) {
+ if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
} else {
new_bpm = prev_t->beats_per_minute();
} else {
/* AudioTime */
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
- new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
- / (double) ((end_frame) - prev_to_prev_t->frame()));
+ if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
+
+ new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
+ / (double) ((end_frame) - prev_to_prev_t->frame()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
} else {
/* prev_to_prev_t is irrelevant */
- if (end_frame != prev_t->frame()) {
+ if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
} else {
new_bpm = prev_t->beats_per_minute();
}
} else {
- double frame_ratio;
- double pulse_ratio;
+ double frame_ratio = 1.0;
+ double pulse_ratio = 1.0;
const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
if (prev_to_prev_t) {
-
- frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
- pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
+ if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
+ frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
+ }
+ if (end_pulse > prev_to_prev_t->pulse() && start_pulse > prev_to_prev_t->pulse()) {
+ pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
+ }
} else {
-
- frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
+ if (pulse_pos > prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_t->frame() + min_dframe) {
+ frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
+ }
pulse_ratio = (start_pulse / end_pulse);
}
new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
}
+ /* don't clamp and proceed here.
+ testing has revealed that this can go negative,
+ which is an entirely different thing to just being too low.
+ */
+ if (new_bpm < 0.5) {
+ return;
+ }
+ new_bpm = min (new_bpm, (double) 1000.0);
prev_t->set_beats_per_minute (new_bpm);
recompute_tempos (future_map);
recompute_meters (future_map);
if (cnt < 0.0) {
cnt = 0.0;
}
+
+ if (frame_at_beat_locked (_metrics, cnt) >= upper) {
+ return;
+ }
+
while (pos < upper) {
pos = frame_at_beat_locked (_metrics, cnt);
const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
}
if (ts_after) {
- return (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
+ return (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate) * ts_at->note_type());
}
/* must be treated as constant tempo */
return ts_at->frames_per_beat (_frame_rate);