mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-16 11:46:25 +01:00
Tempo ramps - more bbt dragging work.
- display prev tempo and tempo at mouse while dragging - simplify ramp dilation somewhat.
This commit is contained in:
parent
abac4ce854
commit
5ccfeea5bc
6 changed files with 57 additions and 132 deletions
|
|
@ -2254,6 +2254,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
||||||
friend class RegionSpliceDrag;
|
friend class RegionSpliceDrag;
|
||||||
friend class RegionRippleDrag;
|
friend class RegionRippleDrag;
|
||||||
friend class TrimDrag;
|
friend class TrimDrag;
|
||||||
|
friend class BBTRulerDrag;
|
||||||
friend class MeterMarkerDrag;
|
friend class MeterMarkerDrag;
|
||||||
friend class TempoMarkerDrag;
|
friend class TempoMarkerDrag;
|
||||||
friend class CursorDrag;
|
friend class CursorDrag;
|
||||||
|
|
|
||||||
|
|
@ -3478,32 +3478,47 @@ TempoMarkerDrag::aborted (bool moved)
|
||||||
|
|
||||||
BBTRulerDrag::BBTRulerDrag (Editor* e, ArdourCanvas::Item* i)
|
BBTRulerDrag::BBTRulerDrag (Editor* e, ArdourCanvas::Item* i)
|
||||||
: Drag (e, i)
|
: Drag (e, i)
|
||||||
|
, _pulse (0.0)
|
||||||
|
, _beat (0.0)
|
||||||
, _tempo (0)
|
, _tempo (0)
|
||||||
, before_state (0)
|
, before_state (0)
|
||||||
{
|
{
|
||||||
DEBUG_TRACE (DEBUG::Drags, "New BBTRulerDrag\n");
|
DEBUG_TRACE (DEBUG::Drags, "New BBTRulerDrag\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
||||||
{
|
{
|
||||||
Drag::start_grab (event, cursor);
|
Drag::start_grab (event, cursor);
|
||||||
|
|
||||||
TempoMap& map (_editor->session()->tempo_map());
|
TempoMap& map (_editor->session()->tempo_map());
|
||||||
ostringstream sstr;
|
ostringstream sstr;
|
||||||
sstr << fixed << setprecision(3) << map.tempo_at (adjusted_current_frame (event)).beats_per_minute();
|
|
||||||
show_verbose_cursor_text (sstr.str());
|
|
||||||
_tempo = const_cast<TempoSection*> (&map.tempo_section_at (adjusted_current_frame (event, false)));
|
|
||||||
|
|
||||||
if (!_tempo) {
|
_tempo = const_cast<TempoSection*> (&map.tempo_section_at (raw_grab_frame()));
|
||||||
Drag::abort();
|
sstr << "^" << fixed << setprecision(3) << map.tempo_at (adjusted_current_frame (event)).beats_per_minute() << "\n";
|
||||||
}
|
sstr << "<" << fixed << setprecision(3) << _tempo->beats_per_minute();
|
||||||
|
show_verbose_cursor_text (sstr.str());
|
||||||
|
finished (event, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BBTRulerDrag::setup_pointer_frame_offset ()
|
BBTRulerDrag::setup_pointer_frame_offset ()
|
||||||
{
|
{
|
||||||
TempoMap& map (_editor->session()->tempo_map());
|
TempoMap& map (_editor->session()->tempo_map());
|
||||||
_pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (floor (map.beat_at_frame (raw_grab_frame())));
|
const double beat_at_frame = map.beat_at_frame (raw_grab_frame());
|
||||||
|
const uint32_t divisions = _editor->get_grid_beat_divisions (0);
|
||||||
|
if (divisions > 0) {
|
||||||
|
_beat = floor (beat_at_frame) + (floor (((beat_at_frame - floor (beat_at_frame)) * divisions)) / divisions);
|
||||||
|
} else {
|
||||||
|
/* while it makes some sense for the user to determine the division to 'grab',
|
||||||
|
grabbing a bar often leads to confusing results wrt the actual tempo section being altered
|
||||||
|
and the result over steep tempo curves. Use sixteenths.
|
||||||
|
*/
|
||||||
|
_beat = floor (beat_at_frame) + (floor (((beat_at_frame - floor (beat_at_frame)) * 4)) / 4);
|
||||||
|
}
|
||||||
|
_pulse = map.pulse_at_beat (_beat);
|
||||||
|
_pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (_beat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3521,10 +3536,11 @@ BBTRulerDrag::motion (GdkEvent* event, bool first_move)
|
||||||
|
|
||||||
if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier())) {
|
if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier())) {
|
||||||
/* adjust previous tempo to match pointer frame */
|
/* adjust previous tempo to match pointer frame */
|
||||||
_editor->session()->tempo_map().gui_dilate_tempo (_tempo, last_pointer_frame(), pf);
|
_editor->session()->tempo_map().gui_dilate_tempo (_tempo, map.frame_at_pulse (_pulse), pf, _pulse);
|
||||||
}
|
}
|
||||||
ostringstream sstr;
|
ostringstream sstr;
|
||||||
sstr << fixed << setprecision(3) << map.tempo_at (pf).beats_per_minute();
|
sstr << "^" << fixed << setprecision(3) << map.tempo_at (pf).beats_per_minute() << "\n";
|
||||||
|
sstr << "<" << fixed << setprecision(3) << _tempo->beats_per_minute();
|
||||||
show_verbose_cursor_text (sstr.str());
|
show_verbose_cursor_text (sstr.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -764,6 +764,8 @@ public:
|
||||||
void setup_pointer_frame_offset ();
|
void setup_pointer_frame_offset ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
double _pulse;
|
||||||
|
double _beat;
|
||||||
ARDOUR::TempoSection* _tempo;
|
ARDOUR::TempoSection* _tempo;
|
||||||
XMLNode* before_state;
|
XMLNode* before_state;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,8 @@ Editor::compute_current_bbt_points (std::vector<TempoMap::BBTPoint>& grid, frame
|
||||||
|
|
||||||
/* prevent negative values of leftmost from creeping into tempomap
|
/* prevent negative values of leftmost from creeping into tempomap
|
||||||
*/
|
*/
|
||||||
_session->tempo_map().get_grid (grid, max (leftmost, (framepos_t) 0), rightmost);
|
const double lower_beat = floor (_session->tempo_map().beat_at_frame (leftmost));
|
||||||
|
_session->tempo_map().get_grid (grid, max (_session->tempo_map().frame_at_beat (lower_beat), (framepos_t) 0), rightmost);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -398,9 +398,8 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
|
||||||
void gui_move_meter (MeterSection*, const framepos_t& frame);
|
void gui_move_meter (MeterSection*, const framepos_t& frame);
|
||||||
void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt);
|
void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt);
|
||||||
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
|
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
|
||||||
void gui_dilate_next_tempo (const framepos_t& frame, const framepos_t& end_frame);
|
|
||||||
void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
|
void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
|
||||||
void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame);
|
void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame, const double& pulse);
|
||||||
|
|
||||||
bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt);
|
bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2783,118 +2783,16 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TempoMap::gui_dilate_next_tempo (const framepos_t& frame, const framepos_t& end_frame)
|
TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
|
||||||
{
|
{
|
||||||
Metrics future_map;
|
/*
|
||||||
TempoSection* ts = 0;
|
Ts (future prev_t) Tnext
|
||||||
|
| |
|
||||||
|
| [drag^] |
|
||||||
|
|----------|----------
|
||||||
|
e_f pulse(frame)
|
||||||
|
*/
|
||||||
|
|
||||||
{
|
|
||||||
Glib::Threads::RWLock::WriterLock lm (lock);
|
|
||||||
|
|
||||||
for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
|
|
||||||
TempoSection* t = 0;
|
|
||||||
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
|
|
||||||
if (t->frame() > end_frame) {
|
|
||||||
ts = t;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ts) {
|
|
||||||
ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
TempoSection* next_t = copy_metrics_and_point (_metrics, future_map, ts);
|
|
||||||
TempoSection* prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, next_t->frame() - 1));
|
|
||||||
TempoSection* prev_to_prev_t = 0;
|
|
||||||
const frameoffset_t fr_off = end_frame - frame;
|
|
||||||
|
|
||||||
if (prev_t && prev_t->pulse() > 0.0) {
|
|
||||||
prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, prev_t->frame() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
|
|
||||||
contribution = prev_t->beats_per_minute() / (prev_t->beats_per_minute() + next_t->beats_per_minute());
|
|
||||||
}
|
|
||||||
|
|
||||||
frameoffset_t prev_t_frame_contribution = fr_off;
|
|
||||||
|
|
||||||
const double start_tempo = prev_t->tempo_at_frame (frame, _frame_rate);
|
|
||||||
const double end_tempo = prev_t->tempo_at_frame (frame + prev_t_frame_contribution, _frame_rate);
|
|
||||||
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) {
|
|
||||||
new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
|
|
||||||
/ (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* prev to prev is irrelevant */
|
|
||||||
|
|
||||||
if (start_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()));
|
|
||||||
} else {
|
|
||||||
/* prev_to_prev_t is irrelevant */
|
|
||||||
|
|
||||||
if (end_frame != prev_t->frame()) {
|
|
||||||
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 {
|
|
||||||
const double end_minute = ((next_t->frame() + prev_t_frame_contribution - prev_t->frame()) / (double) _frame_rate) / 60.0;
|
|
||||||
const double pulse_delta_at_next = prev_t->pulse_at_frame ((next_t->frame()) + prev_t_frame_contribution, _frame_rate) - next_t->pulse();
|
|
||||||
const double target_pulse = (next_t->pulse() - prev_t->pulse()) + (pulse_delta_at_next);
|
|
||||||
|
|
||||||
new_bpm = (prev_t->tempo_at_frame (next_t->frame() - prev_t_frame_contribution, _frame_rate)) * (double) prev_t->note_type();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
next_t->set_beats_per_minute (new_bpm);
|
|
||||||
recompute_tempos (future_map);
|
|
||||||
recompute_meters (future_map);
|
|
||||||
|
|
||||||
if (check_solved (future_map, true)) {
|
|
||||||
ts->set_beats_per_minute (new_bpm);
|
|
||||||
recompute_tempos (_metrics);
|
|
||||||
recompute_meters (_metrics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Metrics::const_iterator d = future_map.begin();
|
|
||||||
while (d != future_map.end()) {
|
|
||||||
delete (*d);
|
|
||||||
++d;
|
|
||||||
}
|
|
||||||
|
|
||||||
MetricPositionChanged (); // Emit Signal
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame)
|
|
||||||
{
|
|
||||||
Metrics future_map;
|
Metrics future_map;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -2926,22 +2824,23 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
|
||||||
constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
|
constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
|
||||||
*/
|
*/
|
||||||
double contribution = 0.0;
|
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) {
|
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());
|
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);
|
frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
|
||||||
const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
|
double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
|
||||||
const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
|
|
||||||
double new_bpm;
|
double new_bpm;
|
||||||
|
|
||||||
if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
|
if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
|
||||||
|
|
||||||
if (prev_t->position_lock_style() == MusicTime) {
|
if (prev_t->position_lock_style() == MusicTime) {
|
||||||
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
|
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()));
|
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 {
|
} else {
|
||||||
/* prev to prev is irrelevant */
|
/* prev to prev is irrelevant */
|
||||||
|
|
@ -2968,14 +2867,21 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const frameoffset_t halfway = ((next_t->frame() + prev_t->frame()) / 2.0);
|
|
||||||
const frameoffset_t halfway_off = halfway + prev_t_frame_contribution;
|
|
||||||
const double halfway_pulse = prev_t->pulse_at_frame (halfway, _frame_rate);
|
|
||||||
const double halfway_off_minute = ((halfway_off - prev_t->frame()) / (double) _frame_rate) / 60.0;
|
|
||||||
|
|
||||||
new_bpm = (((halfway_pulse - prev_t->pulse()) * prev_t->c_func())
|
double frame_ratio;
|
||||||
/ (exp (halfway_off_minute * prev_t->c_func()) - 1.0)) * (double) prev_t->note_type();
|
double pulse_ratio;
|
||||||
|
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()) / (double) (end_pulse - prev_to_prev_t->pulse()));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
|
||||||
|
pulse_ratio = ((start_pulse) / (double) (end_pulse));
|
||||||
|
}
|
||||||
|
new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_t->set_beats_per_minute (new_bpm);
|
prev_t->set_beats_per_minute (new_bpm);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue