return bbt_at_frame_locked (_metrics, frame);
}
+BBT_Time
+TempoMap::bbt_at_frame_rt (framepos_t frame)
+{
+ Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
+
+ if (!lm.locked()) {
+ throw std::logic_error ("TempoMap::bbt_time_rt() could not lock tempo map");
+ }
+
+ return bbt_at_frame_locked (_metrics, frame);
+}
+
Timecode::BBT_Time
TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
{
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) {
}
}
+#if (0)
recompute_tempos (imaginary);
if (check_solved (imaginary)) {
return true;
+ } else {
+ dunp (imaginary, std::cout);
}
+#endif
MetricSectionFrameSorter fcmp;
imaginary.sort (fcmp);
section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
}
+#if (0)
recompute_tempos (imaginary);
if (check_solved (imaginary)) {
return true;
+ } else {
+ dunp (imaginary, std::cout);
}
+#endif
MetricSectionSorter cmp;
imaginary.sort (cmp);
}
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.
*/
double contribution = 0.0;
- double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
}
- frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
- double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
+ const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
+
+ const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
+ const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
+
double new_bpm;
if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
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_t->frame())
- / (double) ((frame + prev_t_frame_contribution) - 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 */
Evoral::Beats
TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
{
- return Evoral::Beats (beat_at_frame (pos + distance) - beat_at_frame (pos));
+ Glib::Threads::RWLock::ReaderLock lm (lock);
+
+ return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
}
struct bbtcmp {