summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/editor_drag.cc30
-rw-r--r--libs/ardour/ardour/tempo.h6
-rw-r--r--libs/ardour/tempo.cc157
3 files changed, 129 insertions, 64 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index fe67b71dd2..080e82d984 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -3199,17 +3199,15 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
Timecode::BBT_Time bbt;
map.bbt_time (pf, bbt);
/* round bbt to bars */
- map.round_bbt (bbt, -1);
- const MeterSection& prev_m = map.meter_section_at (_real_section->frame() - 1);
+ map.round_bbt (bbt, -1, RoundNearest);
if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier ())) {
+ /* adjust previous tempo to match meter frame */
_editor->session()->tempo_map().gui_dilate_tempo (_real_section, pf);
- } else if (bbt.bars > _real_section->bbt().bars) {
- const double pulse = _real_section->pulse() + (prev_m.note_divisor() / prev_m.divisions_per_bar());
- _editor->session()->tempo_map().gui_move_meter (_real_section, pulse);
- } else if (bbt.bars < _real_section->bbt().bars) {
- const double pulse = _real_section->pulse() - (prev_m.note_divisor() / prev_m.divisions_per_bar());
- _editor->session()->tempo_map().gui_move_meter (_real_section, pulse);
+ } else if ((bbt.bars > _real_section->bbt().bars && pf > last_pointer_frame())
+ || (bbt.bars < _real_section->bbt().bars && pf < last_pointer_frame())) {
+ /* move meter beat-based */
+ _editor->session()->tempo_map().gui_move_meter (_real_section, bbt);
}
} else {
/* AudioTime */
@@ -3352,17 +3350,17 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
if (_real_section->position_lock_style() == MusicTime) {
if (use_snap && _editor->snap_type() == SnapToBar) {
- map.round_bbt (bbt, -1);
+ map.round_bbt (bbt, -1, (frame > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
} else if (use_snap) {
- map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
+ map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
}
double const pulse = map.predict_tempo_pulse (_real_section, map.frame_time (bbt));
_real_section = map.add_tempo (_marker->tempo(), pulse, _real_section->type());
} else {
if (use_snap && _editor->snap_type() == SnapToBar) {
- map.round_bbt (bbt, -1);
+ map.round_bbt (bbt, -1, (frame > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
} else if (use_snap) {
- map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
+ map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
}
if (use_snap) {
frame = map.predict_tempo_frame (_real_section, bbt);
@@ -3417,17 +3415,17 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
const double pulse = map.predict_tempo_pulse (_real_section, pf);
when = map.pulse_to_bbt (pulse);
if (use_snap && _editor->snap_type() == SnapToBar) {
- map.round_bbt (when, -1);
+ map.round_bbt (when, -1, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
} else if (use_snap) {
- map.round_bbt (when, _editor->get_grid_beat_divisions (0));
+ map.round_bbt (when, _editor->get_grid_beat_divisions (0), RoundNearest);
}
const double beat = map.bbt_to_beats (when);
map.gui_move_tempo_beat (_real_section, beat);
} else {
if (use_snap && _editor->snap_type() == SnapToBar) {
- map.round_bbt (when, -1);
+ map.round_bbt (when, -1, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
} else if (use_snap) {
- map.round_bbt (when, _editor->get_grid_beat_divisions (0));
+ map.round_bbt (when, _editor->get_grid_beat_divisions (0), RoundNearest);
}
if (use_snap) {
pf = map.predict_tempo_frame (_real_section, when);
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index eb6eeb3a50..87023e0cd8 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -396,7 +396,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
void gui_move_tempo_beat (TempoSection*, const double& beat);
void gui_move_tempo_pulse (TempoSection*, const double& pulse);
void gui_move_meter (MeterSection*, const framepos_t& frame);
- void gui_move_meter (MeterSection*, const double& pulse);
+ void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt);
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
@@ -408,7 +408,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
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_subdivision (framepos_t fr, int sub_num, RoundMode dir);
- void round_bbt (Timecode::BBT_Time& when, const int32_t& snap_divisor);
+ void round_bbt (Timecode::BBT_Time& when, const int32_t& snap_divisor, RoundMode dir);
void set_length (framepos_t frames);
@@ -477,7 +477,7 @@ private:
bool solve_map (Metrics& metrics, TempoSection* section, const framepos_t& frame);
bool solve_map (Metrics& metrics, TempoSection* section, const double& pulse);
bool solve_map (Metrics& metrics, MeterSection* section, const framepos_t& frame);
- bool solve_map (Metrics& metrics, MeterSection* section, const double& pulse);
+ bool solve_map (Metrics& metrics, MeterSection* section, const Timecode::BBT_Time& bbt);
friend class ::BBTTest;
friend class ::FrameposPlusBeatsTest;
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 7af7545b76..a9707c85ef 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -1105,7 +1105,7 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
do_insert (new_meter);
if (recompute) {
- solve_map (_metrics, new_meter, pulse);
+ solve_map (_metrics, new_meter, where);
}
return new_meter;
@@ -2092,10 +2092,8 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
TempoSection* t;
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
- if (t->frame() == section->frame()) {
- meter_locked_tempo = t;
- break;
- }
+ meter_locked_tempo = t;
+ break;
}
}
}
@@ -2209,7 +2207,6 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
section->set_pulse (0.0);
}
- //section->set_frame (frame);
break;
}
@@ -2232,33 +2229,37 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
}
bool
-TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const double& pulse)
+TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
{
MeterSection* prev_m = 0;
- section->set_pulse (pulse);
-
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
MeterSection* m;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
- double new_pulse = 0.0;
pair<double, BBT_Time> b_bbt;
+ double new_pulse = 0.0;
if (prev_m && m == section){
- /* the first meter is always audio-locked, so prev_m should exist.
- should we allow setting audio locked meters by pulse?
- */
- const double beats = floor (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + 0.5);
- const int32_t bars = (beats) / prev_m->divisions_per_bar();
- pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), BBT_Time (bars + prev_m->bbt().bars, 1, 0));
+ const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
+ const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
+
+ b_bbt = make_pair (beats + prev_m->beat(), when);
+
section->set_beat (b_bbt);
+ section->set_pulse (pulse);
section->set_frame (frame_at_pulse_locked (imaginary, pulse));
+
prev_m = m;
continue;
+
+ } else if (m->bbt().bars == when.bars) {
+ return false;
}
+
if (m->position_lock_style() == AudioTime) {
if (m->movable()) {
const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
+
if (beats + prev_m->beat() != m->beat()) {
/* tempo/ meter change caused a change in beat (bar). */
b_bbt = make_pair (beats + prev_m->beat()
@@ -2271,12 +2272,23 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const double& pu
} else {
b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
}
+
+ m->set_beat (b_bbt);
+ m->set_pulse (new_pulse);
+
} else {
- new_pulse = prev_m->pulse() + ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar() / prev_m->note_divisor());
- b_bbt = make_pair (((new_pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat(), m->bbt());
+ const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
+
+ b_bbt = make_pair (beats + prev_m->beat()
+ , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
+ new_pulse = prev_m->pulse() + ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar()
+ / prev_m->note_divisor());
+
+ m->set_beat (b_bbt);
+ m->set_pulse (new_pulse);
+ m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
}
- m->set_beat (b_bbt);
- m->set_pulse (new_pulse);
+
prev_m = m;
}
}
@@ -2521,14 +2533,14 @@ TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
}
void
-TempoMap::gui_move_meter (MeterSection* ms, const double& pulse)
+TempoMap::gui_move_meter (MeterSection* ms, const Timecode::BBT_Time& bbt)
{
Metrics future_map;
{
Glib::Threads::RWLock::WriterLock lm (lock);
MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
- if (solve_map (future_map, copy, pulse)) {
- solve_map (_metrics, ms, pulse);
+ if (solve_map (future_map, copy, bbt)) {
+ solve_map (_metrics, ms, bbt);
}
}
@@ -2821,16 +2833,27 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
}
void
-TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num)
+TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num, RoundMode dir)
{
if (sub_num == -1) {
- const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
- if ((double) when.beats > bpb / 2.0) {
+ if (dir > 0) {
++when.bars;
+ when.beats = 1;
+ when.ticks = 0;
+ } else if (dir < 0) {
+ when.beats = 1;
+ when.ticks = 0;
+ } else {
+ const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
+ if ((double) when.beats > bpb / 2.0) {
+ ++when.bars;
+ }
+ when.beats = 1;
+ when.ticks = 0;
}
- when.beats = 1;
- when.ticks = 0;
+
return;
+
} else if (sub_num == 0) {
const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
if ((double) when.ticks > BBT_Time::ticks_per_beat / 2.0) {
@@ -2841,32 +2864,76 @@ TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num)
}
}
when.ticks = 0;
+
return;
}
+
const uint32_t ticks_one_subdivisions_worth = BBT_Time::ticks_per_beat / sub_num;
- double rem;
- if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
- /* closer to the next subdivision, so shift forward */
- when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
+ if (dir > 0) {
+ /* round to next (or same iff dir == RoundUpMaybe) */
- if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
- ++when.beats;
- when.ticks -= Timecode::BBT_Time::ticks_per_beat;
+ uint32_t mod = when.ticks % ticks_one_subdivisions_worth;
+
+ if (mod == 0 && dir == RoundUpMaybe) {
+ /* right on the subdivision, which is fine, so do nothing */
+
+ } else if (mod == 0) {
+ /* right on the subdivision, so the difference is just the subdivision ticks */
+ when.ticks += ticks_one_subdivisions_worth;
+
+ } else {
+ /* not on subdivision, compute distance to next subdivision */
+
+ when.ticks += ticks_one_subdivisions_worth - mod;
}
- } else if (rem > 0) {
- /* closer to previous subdivision, so shift backward */
+ if (when.ticks >= BBT_Time::ticks_per_beat) {
+ when.ticks -= BBT_Time::ticks_per_beat;
+ }
- if (rem > when.ticks) {
- if (when.beats == 0) {
- /* can't go backwards past zero, so ... */
- }
- /* step back to previous beat */
- --when.beats;
- when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
+ } else if (dir < 0) {
+ /* round to previous (or same iff dir == RoundDownMaybe) */
+
+ uint32_t difference = when.ticks % ticks_one_subdivisions_worth;
+
+ if (difference == 0 && dir == RoundDownAlways) {
+ /* right on the subdivision, but force-rounding down,
+ so the difference is just the subdivision ticks */
+ difference = ticks_one_subdivisions_worth;
+ }
+
+ if (when.ticks < difference) {
+ when.ticks = BBT_Time::ticks_per_beat - when.ticks;
} else {
- when.ticks = when.ticks - rem;
+ when.ticks -= difference;
+ }
+
+ } else {
+ /* round to nearest */ double rem;
+ if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
+ /* closer to the next subdivision, so shift forward */
+
+ when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
+
+ if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
+ ++when.beats;
+ when.ticks -= Timecode::BBT_Time::ticks_per_beat;
+ }
+
+ } else if (rem > 0) {
+ /* closer to previous subdivision, so shift backward */
+
+ if (rem > when.ticks) {
+ if (when.beats == 0) {
+ /* can't go backwards past zero, so ... */
+ }
+ /* step back to previous beat */
+ --when.beats;
+ when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
+ } else {
+ when.ticks = when.ticks - rem;
+ }
}
}
}