summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/editor_drag.cc47
-rw-r--r--gtk2_ardour/editor_tempodisplay.cc4
-rw-r--r--libs/ardour/ardour/tempo.h7
-rw-r--r--libs/ardour/tempo.cc86
4 files changed, 76 insertions, 68 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index d60df1c896..9cbeb1984a 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -3339,7 +3339,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
} else if (use_snap) {
map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
}
- double const pulse = map.predict_tempo (_real_section, bbt).first;
+ double const pulse = map.predict_tempo_position (_real_section, bbt).first;
_real_section = map.add_tempo (_marker->tempo(), pulse, 0, _real_section->type(), MusicTime);
} else {
if (use_snap && _editor->snap_type() == SnapToBar) {
@@ -3348,7 +3348,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
}
if (use_snap) {
- frame = map.predict_tempo (_real_section, bbt).second;
+ frame = map.predict_tempo_position (_real_section, bbt).second;
}
_real_section = map.add_tempo (_marker->tempo(), 0.0, frame, _real_section->type(), AudioTime);
}
@@ -3359,25 +3359,30 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
framepos_t pf;
if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier ())) {
+ /* use vertical movement to alter tempo .. should be log */
double new_bpm = _real_section->beats_per_minute() + ((last_pointer_y() - current_pointer_y()) / 5.0);
- _editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type()));
stringstream strs;
+
+ _editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type()));
strs << new_bpm;
show_verbose_cursor_text (strs.str());
+
} else if (_movable && !_real_section->locked_to_meter()) {
+
if (!_editor->snap_musical()) {
/* snap normally (this is not self-referential).*/
pf = adjusted_current_frame (event);
+
} else {
/* but this is.
we can't use the map for anything related to tempo,
so we round bbt using meters, which have no dependency
on pulse for this kind of thing.
*/
- bool use_snap;
TempoMap& map (_editor->session()->tempo_map());
+ Timecode::BBT_Time when;
+ bool use_snap;
- pf = adjusted_current_frame (event, false);
if (ArdourKeyboard::indicates_snap (event->button.state)) {
if (_editor->snap_mode() == Editing::SnapOff) {
use_snap = true;
@@ -3392,36 +3397,24 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
}
}
- Timecode::BBT_Time when;
+ pf = adjusted_current_frame (event);
map.bbt_time (pf, when);
- if (_real_section->position_lock_style() == MusicTime) {
+ if (use_snap && _editor->snap_type() == SnapToBar) {
+ map.round_bbt (when, -1, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
- const double pulse = map.predict_tempo (_real_section, when).first;
- when = map.pulse_to_bbt (pulse);
- if (use_snap && _editor->snap_type() == SnapToBar) {
- 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), 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, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
- } else if (use_snap) {
- map.round_bbt (when, _editor->get_grid_beat_divisions (0), RoundNearest);
- }
- if (use_snap) {
- pf = map.predict_tempo (_real_section, when).second;
- }
- map.gui_move_tempo_frame (_real_section, pf);
}
+ const pair<double, framepos_t> future_pos = map.predict_tempo_position (_real_section, when);
+ map.gui_move_tempo (_real_section, future_pos);
+
}
show_verbose_cursor_time (_real_section->frame());
}
+
+ /* this has moved the bar lines themselves, so recalibrate the offset */
+ setup_pointer_frame_offset();
+
_marker->set_position (pf);
}
diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc
index 9fdae28b30..82906137c7 100644
--- a/gtk2_ardour/editor_tempodisplay.cc
+++ b/gtk2_ardour/editor_tempodisplay.cc
@@ -426,10 +426,10 @@ Editor::edit_tempo_section (TempoSection* section)
XMLNode &before = _session->tempo_map().get_state();
if (tempo_dialog.get_lock_style() == AudioTime) {
- framepos_t const f = _session->tempo_map().predict_tempo (section, when).second;
+ framepos_t const f = _session->tempo_map().predict_tempo_position (section, when).second;
_session->tempo_map().replace_tempo (*section, Tempo (bpm, nt), 0.0, f, tempo_dialog.get_tempo_type(), AudioTime);
} else {
- double const p = _session->tempo_map().predict_tempo (section, when).first;
+ double const p = _session->tempo_map().predict_tempo_position (section, when).first;
_session->tempo_map().replace_tempo (*section, Tempo (bpm, nt), p, 0, tempo_dialog.get_tempo_type(), MusicTime);
}
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index a3eec81bb9..db618a4513 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -397,12 +397,13 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where, const framepos_t& frame
, PositionLockStyle pls);
- std::pair<double, framepos_t> predict_tempo (TempoSection* section, const Timecode::BBT_Time& bbt);
+ std::pair<double, framepos_t> predict_tempo_position (TempoSection* section, const Timecode::BBT_Time& bbt);
+
+ void gui_move_tempo (TempoSection*, const std::pair<const double&, const framepos_t&>& pulse);
- void gui_move_tempo_frame (TempoSection*, const framepos_t& frame);
- void gui_move_tempo_beat (TempoSection*, const double& beat);
void gui_move_meter_frame (MeterSection*, const framepos_t& frame);
void gui_move_meter_bbt (MeterSection*, const Timecode::BBT_Time& bbt);
+
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame, const double& pulse);
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 87e1620425..75065917fd 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -586,10 +586,9 @@ MeterSection::get_state() const
/*
Tempo Map Overview
- Tempo can be thought of as a source of the musical pulse.
- Meters divide that pulse into measures and beats.
- Tempo pulses can be divided to be in sympathy with the meter, but this does not affect the beat
- at any particular time.
+ Tempo is the rate of the musical pulse.
+ Meters divide the pulses into measures and beats.
+
Note that Tempo::beats_per_minute() has nothing to do with musical beats.
It should rather be thought of as tempo note divisions per minute.
@@ -602,6 +601,19 @@ MeterSection::get_state() const
Having done this, we can now find any one of tempo, beat, frame or pulse if a beat, frame, pulse or tempo is known.
+ With tepo sections potentially being ramped, meters provide a way of mapping beats to whole pulses without
+ referring to the tempo function(s) involved as the distance in whole pulses between a meter and a subsequent beat is
+ sb->beat() - meter->beat() / meter->note_divisor().
+ Because every meter falls on a known pulse, (derived from its bar), the rest is easy as the duration in pulses between
+ two meters is of course
+ (meater_b->bar - meter_a->bar) * meter_a->divisions_per_bar / meter_a->note_divisor.
+
+ Below, beat calculations are based on meter sections and all pulse and tempo calculations are based on tempo sections.
+ Beat to frame conversion of course requires the use of meter and tempo.
+
+ Remembering that ramped tempo sections interact, it is important to avoid referring to any other tempos when moving tempo sections,
+ Here, beats (meters) are used to determine the new pulse (see predict_tempo_position())
+
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.
@@ -1211,7 +1223,6 @@ TempoMap::recompute_tempos (Metrics& metrics)
/* tempos must be positioned correctly.
the current approach is to use a meter's bbt time as its base position unit.
- this means that a meter's beat may change, but its bbt may not.
an audio-locked meter requires a recomputation of pulse and beat (but not bbt),
while a music-locked meter requires recomputations of frame pulse and beat (but not bbt)
*/
@@ -1507,7 +1518,7 @@ TempoMap::beat_at_frame (const framecnt_t& frame) const
return beat_at_frame_locked (_metrics, frame);
}
-/* meter section based */
+/* meter / tempo section based */
double
TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
{
@@ -2306,15 +2317,14 @@ TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
}
/**
-* This is for a gui that needs to know the frame of a tempo section if it were to be moved to some bbt time,
+* This is for a gui that needs to know the pulse or frame of a tempo section if it were to be moved to some bbt time,
* taking any possible reordering as a consequence of this into account.
* @param section - the section to be altered
-* @param bpm - the new Tempo
* @param bbt - the bbt where the altered tempo will fall
-* @return returns - the position in frames where the new tempo section will lie.
+* @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
*/
pair<double, framepos_t>
-TempoMap::predict_tempo (TempoSection* section, const BBT_Time& bbt)
+TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
{
Metrics future_map;
pair<double, framepos_t> ret = make_pair (0.0, 0);
@@ -2342,37 +2352,29 @@ TempoMap::predict_tempo (TempoSection* section, const BBT_Time& bbt)
}
void
-TempoMap::gui_move_tempo_frame (TempoSection* ts, const framepos_t& frame)
+TempoMap::gui_move_tempo (TempoSection* ts, const pair<const double&, const framepos_t&>& pulse)
{
Metrics future_map;
- {
- Glib::Threads::RWLock::WriterLock lm (lock);
- TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- if (solve_map_frame (future_map, tempo_copy, frame)) {
- solve_map_frame (_metrics, ts, frame);
- recompute_meters (_metrics);
- }
- }
- Metrics::const_iterator d = future_map.begin();
- while (d != future_map.end()) {
- delete (*d);
- ++d;
- }
+ if (ts->position_lock_style() == MusicTime) {
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
+ if (solve_map_pulse (future_map, tempo_copy, pulse.first)) {
+ solve_map_pulse (_metrics, ts, pulse.first);
+ recompute_meters (_metrics);
+ }
+ }
- MetricPositionChanged (); // Emit Signal
-}
+ } else {
-void
-TempoMap::gui_move_tempo_beat (TempoSection* ts, const double& beat)
-{
- Metrics future_map;
- {
- Glib::Threads::RWLock::WriterLock lm (lock);
- TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
- if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
- solve_map_pulse (_metrics, ts, pulse_at_beat_locked (_metrics, beat));
- recompute_meters (_metrics);
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
+ if (solve_map_frame (future_map, tempo_copy, pulse.second)) {
+ solve_map_frame (_metrics, ts, pulse.second);
+ recompute_meters (_metrics);
+ }
}
}
@@ -2758,6 +2760,12 @@ TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num, RoundMode dir)
}
if (when.ticks >= BBT_Time::ticks_per_beat) {
+ ++when.beats;
+ const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
+ if ((double) when.beats > bpb) {
+ ++when.bars;
+ when.beats = 1;
+ }
when.ticks -= BBT_Time::ticks_per_beat;
}
@@ -2773,6 +2781,12 @@ TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num, RoundMode dir)
}
if (when.ticks < difference) {
+ --when.beats;
+ const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
+ if ((double) when.beats < bpb) {
+ --when.bars;
+ //when.beats = 1;
+ }
when.ticks = BBT_Time::ticks_per_beat - when.ticks;
} else {
when.ticks -= difference;