Compare commits

...

2 Commits

Author SHA1 Message Date
Ben Loftis a258b82ce9 tweak behavior and naming of tempo-map drags:
* correctly handle clicks on the immediate right or left of a beat line
* prefer Mid-Twist and End-Stretch terminology over Twist and Linear
* static-tempo vs ramped-tempo is orthogonal to mid- and end- drags (TODO)
2023-05-04 09:33:08 -05:00
Ben Loftis 912f9e5ea3 provide functions for both linear and ramped tempo-twists 2023-05-04 09:22:28 -05:00
6 changed files with 114 additions and 46 deletions

View File

@ -2547,8 +2547,7 @@ private:
friend class RegionMoveDrag; friend class RegionMoveDrag;
friend class TrimDrag; friend class TrimDrag;
friend class MappingTwistDrag; friend class MappingTwistDrag;
friend class MappingLinearDrag; friend class MappingEndDrag;
friend class MappingStretchDrag;
friend class MeterMarkerDrag; friend class MeterMarkerDrag;
friend class BBTMarkerDrag; friend class BBTMarkerDrag;
friend class TempoMarkerDrag; friend class TempoMarkerDrag;

View File

@ -3476,7 +3476,7 @@ BBTMarkerDrag::aborted (bool moved)
/******************************************************************************/ /******************************************************************************/
MappingLinearDrag::MappingLinearDrag (Editor* e, ArdourCanvas::Item* i, Temporal::TempoMap::WritableSharedPtr& wmap, TempoPoint& tp, TempoPoint& ap, XMLNode& before) MappingEndDrag::MappingEndDrag (Editor* e, ArdourCanvas::Item* i, Temporal::TempoMap::WritableSharedPtr& wmap, TempoPoint& tp, TempoPoint& ap, XMLNode& before)
: Drag (e, i, Temporal::BeatTime) : Drag (e, i, Temporal::BeatTime)
, _tempo (tp) , _tempo (tp)
, _after (ap) , _after (ap)
@ -3485,12 +3485,12 @@ MappingLinearDrag::MappingLinearDrag (Editor* e, ArdourCanvas::Item* i, Temporal
, _before_state (&before) , _before_state (&before)
, _drag_valid (true) , _drag_valid (true)
{ {
DEBUG_TRACE (DEBUG::Drags, "New MappingLinearDrag\n"); DEBUG_TRACE (DEBUG::Drags, "New MappingEndDrag\n");
} }
void void
MappingLinearDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) MappingEndDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{ {
Drag::start_grab (event, cursor); Drag::start_grab (event, cursor);
@ -3509,7 +3509,7 @@ MappingLinearDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
} }
void void
MappingLinearDrag::setup_pointer_offset () MappingEndDrag::setup_pointer_offset ()
{ {
Beats grab_qn = max (Beats(), raw_grab_time().beats()); Beats grab_qn = max (Beats(), raw_grab_time().beats());
@ -3524,7 +3524,7 @@ MappingLinearDrag::setup_pointer_offset ()
} }
void void
MappingLinearDrag::motion (GdkEvent* event, bool first_move) MappingEndDrag::motion (GdkEvent* event, bool first_move)
{ {
if (!_drag_valid) { if (!_drag_valid) {
return; return;
@ -3554,7 +3554,7 @@ MappingLinearDrag::motion (GdkEvent* event, bool first_move)
} }
void void
MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred) MappingEndDrag::finished (GdkEvent* event, bool movement_occurred)
{ {
if (!_drag_valid) { if (!_drag_valid) {
aborted (false); aborted (false);
@ -3576,7 +3576,7 @@ MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
} }
void void
MappingLinearDrag::aborted (bool /* moved */) MappingEndDrag::aborted (bool /* moved */)
{ {
_editor->abort_reversible_command (); _editor->abort_reversible_command ();
_editor->abort_tempo_mapping (); _editor->abort_tempo_mapping ();
@ -3600,7 +3600,8 @@ MappingTwistDrag::MappingTwistDrag (Editor* e, ArdourCanvas::Item* i, Temporal::
, _drag_valid (true) , _drag_valid (true)
{ {
DEBUG_TRACE (DEBUG::Drags, "New MappingTwistDrag\n"); DEBUG_TRACE (DEBUG::Drags, "New MappingTwistDrag\n");
initial_npm = focus.note_types_per_minute (); initial_focus_npm = focus.note_types_per_minute ();
initial_pre_npm = prv.note_types_per_minute ();
} }
void void
@ -3630,13 +3631,15 @@ MappingTwistDrag::motion (GdkEvent* event, bool first_move)
if (_drags->current_pointer_x() < last_pointer_x()) { if (_drags->current_pointer_x() < last_pointer_x()) {
if (direction < 0.) { if (direction < 0.) {
direction = 1.; direction = 1.;
initial_npm += delta; initial_focus_npm += delta;
initial_pre_npm += delta;
delta = 0.; delta = 0.;
} }
} else { } else {
if (direction >= 0.) { if (direction >= 0.) {
direction = -1.; direction = -1.;
initial_npm += delta; initial_focus_npm += delta;
initial_pre_npm += delta;
delta = 0.; delta = 0.;
} }
} }
@ -3657,7 +3660,12 @@ MappingTwistDrag::motion (GdkEvent* event, bool first_move)
delta += scaling_factor * pixel_distance; delta += scaling_factor * pixel_distance;
std::cerr << "pixels " << pixel_distance << " spp " << spp << " SF " << scaling_factor << " delta = " << delta << std::endl; std::cerr << "pixels " << pixel_distance << " spp " << spp << " SF " << scaling_factor << " delta = " << delta << std::endl;
map->twist_tempi (prev, focus, next, initial_npm + delta); bool do_a_ramp = true; // @ben
if (do_a_ramp) {
map->ramped_twist_tempi (prev, focus, next, initial_pre_npm + delta);
} else {
map->linear_twist_tempi (prev, focus, next, initial_focus_npm + delta);
}
_editor->mid_tempo_change (Editor::MappingChanged); _editor->mid_tempo_change (Editor::MappingChanged);
} }

View File

@ -912,10 +912,10 @@ private:
XMLNode* _before_state; XMLNode* _before_state;
}; };
class MappingLinearDrag : public Drag class MappingEndDrag : public Drag
{ {
public: public:
MappingLinearDrag (Editor *, ArdourCanvas::Item *, Temporal::TempoMap::WritableSharedPtr&, Temporal::TempoPoint&, Temporal::TempoPoint& after, XMLNode& before_state); MappingEndDrag (Editor *, ArdourCanvas::Item *, Temporal::TempoMap::WritableSharedPtr&, Temporal::TempoPoint&, Temporal::TempoPoint& after, XMLNode& before_state);
void start_grab (GdkEvent *, Gdk::Cursor* c = 0); void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
void motion (GdkEvent *, bool); void motion (GdkEvent *, bool);
@ -975,7 +975,8 @@ private:
double direction; double direction;
double delta; double delta;
double initial_npm; double initial_focus_npm;
double initial_pre_npm;
XMLNode* _before_state; XMLNode* _before_state;
bool _drag_valid; bool _drag_valid;

View File

@ -2924,6 +2924,13 @@ Editor::get_pointer_position (double& x, double& y) const
void void
Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event) Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
{ {
/* In a departure from convention, this event is not handled by a widget
* 'on' the ruler-bar, like a tempo marker, but is instead handled by the
* mapping-bar widget itself. The intent is for the user to feel that they
* are manipulating the 'beat and bar grid' which may or may not have tempo
* markers already assigned at the point under the mouse.
*/
if (item != mapping_bar) { if (item != mapping_bar) {
return; return;
} }
@ -2935,9 +2942,9 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
Temporal::TempoMap::WritableSharedPtr map = begin_tempo_mapping (); Temporal::TempoMap::WritableSharedPtr map = begin_tempo_mapping ();
/* Decide between a tempo twist drag, which we do if the /* Decide between a mid-twist, which we do if the
* pointer is between two tempo markers, and a tempo stretch * pointer is between two tempo markers, and an end-stretch,
* drag, which we do if the pointer is after the last tempo * which we do if the pointer is after the last tempo
* marker before the end of the map or a BBT Marker. * marker before the end of the map or a BBT Marker.
*/ */
@ -2952,17 +2959,38 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
TempoPoint* before; TempoPoint* before;
TempoPoint* focus; TempoPoint* focus;
bool stretch = false; bool at_end = false;
if (!after || dynamic_cast<MusicTimePoint*>(after)) { if (!after || dynamic_cast<MusicTimePoint*>(after)) {
stretch = true; at_end = true;
} }
BBT_Argument bbt = map->bbt_at (pointer_time); BBT_Argument bbt = map->bbt_at (pointer_time);
bbt = BBT_Argument (bbt.reference(), bbt.round_to_beat ()); bbt = BBT_Argument (bbt.reference(), bbt.round_to_beat ());
if (tempo.bbt() != bbt) { /* BBT_Argument is meter-agnostic so we need to use the map's meter to resolve bar boundaries */
const Meter& m = map->meter_at (pointer_time);
if (bbt.beats > m.divisions_per_bar()){
bbt.beats = 1;
bbt.bars++;
}
if (tempo.bbt() == bbt) {
std::cerr << "we are on the RIGHT side of an EXISTING tempo marker" << bbt << " == " << tempo.bbt() << "\n";
before = const_cast<TempoPoint*> (map->previous_tempo (tempo));
focus = &tempo;
} else if ((after && after->bbt() == bbt )) {
std::cerr << "we are on the LEFT side of an EXISTING tempo marker" << bbt << " == " << after->bbt() << "\n";
before = const_cast<TempoPoint*> (&tempo);
focus = after;
after = const_cast<TempoPoint*> (map->next_tempo (*focus));
if (!after) {
at_end = true; //but it's the last one, so we're operating on the last
}
} else {
std::cerr << "ADD TEMPO MARKER " << bbt << " != " << tempo.bbt() << "\n"; std::cerr << "ADD TEMPO MARKER " << bbt << " != " << tempo.bbt() << "\n";
/* Add a new tempo marker at the nearest beat point /* Add a new tempo marker at the nearest beat point
@ -2978,32 +3006,20 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
reset_tempo_marks (); reset_tempo_marks ();
map->dump (std::cerr); map->dump (std::cerr);
} else {
std::cerr << "USE TEMPO MARKER\n";
before = const_cast<TempoPoint*> (map->previous_tempo (tempo));
if (!before) {
delete before_state;
return;
}
focus = &tempo;
} }
/* Reversible commands start here, must be ended/aborted in drag */ /* Reversible commands start here, must be ended/aborted in drag */
if (stretch) { if (at_end) {
begin_reversible_command (_("map tempo/stretch")); begin_reversible_command (_("tempo mapping: end-stretch"));
std::cerr << "STRETCH\n"; std::cerr << "END STRETCH\n";
_drags->set (new MappingLinearDrag (this, item, map, tempo, *focus, *before_state), event); _drags->set (new MappingEndDrag (this, item, map, tempo, *focus, *before_state), event);
return; return;
} }
if (before && focus && after) {
std::cerr << "TWIST\n"; std::cerr << "TWIST\n";
begin_reversible_command (_("map tempo/twist")); begin_reversible_command (_("tempo mapping: mid-twist"));
_drags->set (new MappingTwistDrag (this, item, map, *before, *focus, *after, *before_state), event); _drags->set (new MappingTwistDrag (this, item, map, *before, *focus, *after, *before_state), event);
}
} }

View File

@ -3631,7 +3631,49 @@ TempoMap::iteratively_solve_ramp (TempoPoint& earlier, TempoPoint& later)
} }
void void
TempoMap::twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_value) TempoMap::linear_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_value)
{
/* Check if the new tempo value is within an acceptable range */
if (tempo_value < 4.0 || tempo_value > 400) {
return;
}
TempoPoint old_prev (prev);
TempoPoint old_focus (focus);
/* Our job here is to reposition @param focus without altering the
* positions of @param prev and @param next. We do this by changing
* the tempo of prev (as opposed to ramped_twist_tempi, below )
*/
/* set a fixed tempo for the previous marker (this results in 'focus' moving a bit with the mouse) */
prev.set_note_types_per_minute (tempo_value);
prev.set_end_npm (tempo_value);
/* reposition focus, using prev to define audio time; leave beat time
* and BBT alone
*/
focus.set (prev.superclock_at (focus.beats()), focus.beats(), focus.bbt());
/* Now iteratively adjust focus.superclocks_per_quarter_note() (the
* section's starting tempo) so that next.sclock() remains within 1
* sample of its current position
*/
std::cerr << "pre-iter\n";
dump (std::cerr);
if (!iteratively_solve_ramp (focus, next)) {
prev = old_prev;
focus = old_focus;
return;
}
}
void
TempoMap::ramped_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_value)
{ {
/* Check if the new tempo value is within an acceptable range */ /* Check if the new tempo value is within an acceptable range */

View File

@ -766,7 +766,9 @@ class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
LIBTEMPORAL_API int set_state (XMLNode const&, int version); LIBTEMPORAL_API int set_state (XMLNode const&, int version);
LIBTEMPORAL_API void twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta); LIBTEMPORAL_API void linear_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
LIBTEMPORAL_API void ramped_twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta);
LIBTEMPORAL_API void stretch_tempo (TempoPoint& ts, double new_npm); LIBTEMPORAL_API void stretch_tempo (TempoPoint& ts, double new_npm);
LIBTEMPORAL_API void stretch_tempo_end (TempoPoint* ts, samplepos_t sample, samplepos_t end_sample); LIBTEMPORAL_API void stretch_tempo_end (TempoPoint* ts, samplepos_t sample, samplepos_t end_sample);