mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-09 23:25:43 +01:00
Tempo ramps - rework tempo drags, improve comments.
This commit is contained in:
parent
f182235410
commit
8b2f73d5ac
4 changed files with 76 additions and 68 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Metrics::const_iterator d = future_map.begin();
|
||||
while (d != future_map.end()) {
|
||||
delete (*d);
|
||||
++d;
|
||||
}
|
||||
} else {
|
||||
|
||||
MetricPositionChanged (); // Emit Signal
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue