summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/editor_drag.cc10
-rw-r--r--gtk2_ardour/editor_drag.h3
-rw-r--r--libs/ardour/ardour/tempo.h3
-rw-r--r--libs/ardour/tempo.cc139
4 files changed, 138 insertions, 17 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 0116f9feaa..4ccb1c0ba5 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -3478,6 +3478,7 @@ TempoMarkerDrag::aborted (bool moved)
BBTRulerDrag::BBTRulerDrag (Editor* e, ArdourCanvas::Item* i)
: Drag (e, i)
+ , _tempo (0)
, before_state (0)
{
DEBUG_TRACE (DEBUG::Drags, "New BBTRulerDrag\n");
@@ -3491,13 +3492,18 @@ BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
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) {
+ Drag::abort();
+ }
}
void
BBTRulerDrag::setup_pointer_frame_offset ()
{
TempoMap& map (_editor->session()->tempo_map());
- _pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (ceil (map.beat_at_frame (raw_grab_frame())));
+ _pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (floor (map.beat_at_frame (raw_grab_frame())));
}
void
@@ -3515,7 +3521,7 @@ BBTRulerDrag::motion (GdkEvent* event, bool first_move)
if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier())) {
/* adjust previous tempo to match pointer frame */
- _editor->session()->tempo_map().gui_dilate_tempo (last_pointer_frame(), pf);
+ _editor->session()->tempo_map().gui_dilate_tempo (_tempo, last_pointer_frame(), pf);
}
ostringstream sstr;
sstr << fixed << setprecision(3) << map.tempo_at (pf).beats_per_minute();
diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h
index 5b5ca6d432..f75c9a681d 100644
--- a/gtk2_ardour/editor_drag.h
+++ b/gtk2_ardour/editor_drag.h
@@ -37,6 +37,7 @@
namespace ARDOUR {
class Location;
+ class TempoSection;
}
namespace ArdourCanvas {
@@ -763,7 +764,7 @@ public:
void setup_pointer_frame_offset ();
private:
-
+ ARDOUR::TempoSection* _tempo;
XMLNode* before_state;
};
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index ba28e8a44a..81fad2e0fc 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -398,8 +398,9 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
void gui_move_meter (MeterSection*, const framepos_t& frame);
void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt);
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 (const framepos_t& frame, const framepos_t& end_frame);
+ void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame);
bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt);
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 07fa80d52c..e3d25948de 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -2783,7 +2783,7 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
}
void
-TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame)
+TempoMap::gui_dilate_next_tempo (const framepos_t& frame, const framepos_t& end_frame)
{
Metrics future_map;
TempoSection* ts = 0;
@@ -2791,13 +2791,22 @@ TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame
{
Glib::Threads::RWLock::WriterLock lm (lock);
- ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1));
+ 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) {
- return;
+ ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1));
}
- TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
+ 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;
@@ -2812,11 +2821,10 @@ TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame
double contribution = 0.0;
if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
- /* prev to prev_t's position will remain constant in terms of frame and pulse. lets use frames. */
- contribution = prev_to_prev_t->beats_per_minute() / (prev_to_prev_t->beats_per_minute() + prev_t->beats_per_minute());
+ contribution = prev_t->beats_per_minute() / (prev_t->beats_per_minute() + next_t->beats_per_minute());
}
- frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
+ 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);
@@ -2856,21 +2864,126 @@ TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame
}
}
} else {
- const double end_minute = (((frame + prev_t_frame_contribution) - prev_t->frame()) / (double) _frame_rate) / 60.0;
+ 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 = (((start_pulse - prev_t->pulse()) * prev_t->c_func())
- / (exp (end_minute * prev_t->c_func()) - 1)) * (double) prev_t->note_type();
+ new_bpm = (prev_t->tempo_at_frame (next_t->frame() - prev_t_frame_contribution, _frame_rate)) * (double) prev_t->note_type();
}
- prev_t->set_beats_per_minute (new_bpm);
+ 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);
+ }
+ }
- prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1));
- prev_t->set_beats_per_minute (new_bpm);
+ 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;
+
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+
+ if (!ts) {
+ return;
+ }
+
+ TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
+ 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));
+ }
+ TempoSection* next_t = 0;
+ for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
+ TempoSection* t = 0;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ if (t->frame() > ts->frame()) {
+ next_t = t;
+ break;
+ }
+ }
+ }
+
+ /* 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 (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);
+ 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 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())
+ / (exp (halfway_off_minute * prev_t->c_func()) - 1.0)) * (double) prev_t->note_type();
+
+ }
+
+ prev_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);
}