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;
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 > 0) {
+ beat = floor (beat) + (floor (((beat - floor (beat)) * (double) sub_num) + 0.5) / sub_num);
+ } else if (sub_num == -2) {
+ /* snap to beat */
+ beat = floor (beat + 0.5);
+ }
+
+ double pulse = pulse_at_beat_locked (future_map, beat);
+
+ if (sub_num == -3) {
+ /* snap to bar */
+ pulse = floor (pulse + 0.5);
+ }
+
if (solve_map_pulse (future_map, tempo_copy, pulse)) {
solve_map_pulse (_metrics, ts, pulse);
recompute_meters (_metrics);
}
}
}
+ /* 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);
framepos_t
TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
{
- return frame_at_beat (beat_at_frame (pos) + beats.to_double());
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) + beats.to_double());
}
/** Subtract some (fractional) beats from a frame position, and return the result in frames */
framepos_t
TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
{
- return frame_at_beat (beat_at_frame (pos) - beats.to_double());
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) - beats.to_double());
}
/** Add the BBT interval op to pos and return the result */