tempo mapping: various tweaks and improvements to workflow/Ux

This commit is contained in:
Paul Davis 2023-04-13 17:47:34 -06:00
parent f29557348e
commit c10b265333
3 changed files with 61 additions and 53 deletions

View File

@ -3476,12 +3476,13 @@ BBTMarkerDrag::aborted (bool moved)
/******************************************************************************/
MappingLinearDrag::MappingLinearDrag (Editor* e, ArdourCanvas::Item* i, Temporal::TempoMap::WritableSharedPtr& wmap)
MappingLinearDrag::MappingLinearDrag (Editor* e, ArdourCanvas::Item* i, Temporal::TempoMap::WritableSharedPtr& wmap, TempoPoint& tp, TempoPoint& ap, XMLNode& before)
: Drag (e, i, Temporal::BeatTime)
, _tempo (0)
, _tempo (tp)
, _after (ap)
, _grab_bpm (0)
, map (wmap)
, _before_state (0)
, _before_state (&before)
, _drag_valid (true)
{
DEBUG_TRACE (DEBUG::Drags, "New MappingLinearDrag\n");
@ -3493,33 +3494,23 @@ MappingLinearDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{
Drag::start_grab (event, cursor);
_tempo = const_cast<TempoPoint*> (&map->metric_at (raw_grab_time().beats()).tempo());
_grab_bpm = _tempo->note_types_per_minute();
if (adjusted_current_time (event, false) <= _tempo->time()) {
std::cerr << "too early for " << *_tempo << std::endl;
_drag_valid = false;
return;
}
_grab_bpm = _tempo.note_types_per_minute();
ostringstream sstr;
if (_tempo->continuing()) {
TempoPoint const * prev = map->previous_tempo (*_tempo);
if (_tempo.continuing()) {
TempoPoint const * prev = map->previous_tempo (_tempo);
if (prev) {
sstr << "end: " << fixed << setprecision(3) << prev->end_note_types_per_minute() << "\n";
}
}
sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute();
sstr << "start: " << fixed << setprecision(3) << _tempo.note_types_per_minute();
show_verbose_cursor_text (sstr.str());
}
void
MappingLinearDrag::setup_pointer_offset ()
{
/* get current state */
_before_state = &map->get_state();
Beats grab_qn = max (Beats(), raw_grab_time().beats());
uint32_t divisions = _editor->get_grid_beat_divisions (_editor->grid_type());
@ -3539,14 +3530,26 @@ MappingLinearDrag::motion (GdkEvent* event, bool first_move)
return;
}
if (first_move) {
_editor->begin_reversible_command (_("map tempo"));
const double pixel_distance = current_pointer_x() - grab_x();
const double spp = _editor->get_current_zoom();
const double scaling_factor = 0.4 * (spp / 1000.);
const double delta = scaling_factor * pixel_distance;
double new_bpm = std::min (300., std::max (3., _grab_bpm - delta));
Temporal::Tempo new_tempo (new_bpm, _tempo.note_type());
/* Change both the previous tempo and the one under the pointer */
map->change_tempo (_tempo, new_tempo);
/* if the user drags the last tempo, then _tempo and _focus are the
* same object.
*/
if (_after.sclock() != _tempo.sclock()) {
map->change_tempo (_after, new_tempo);
}
double new_bpm = std::max (1.5, _grab_bpm - ((current_pointer_x() - grab_x()) / 5.0));
stringstream strs;
Temporal::Tempo new_tempo (new_bpm, _tempo->note_type());
map->change_tempo (*_tempo, new_tempo);
_editor->mid_tempo_change (Editor::MappingChanged);
}
@ -3554,7 +3557,7 @@ void
MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
{
if (!_drag_valid) {
_editor->abort_tempo_mapping ();
aborted (false);
return;
}
@ -3572,7 +3575,7 @@ MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
XMLNode &after = map->get_state();
_editor->session()->add_command (new Temporal::TempoCommand (_("move BBT point"), _before_state, &after));
_editor->session()->add_command (new Temporal::TempoCommand (_("stretch tempo"), _before_state, &after));
_editor->commit_reversible_command ();
/* 2nd argument means "update tempo map display after the new map is
@ -3585,8 +3588,9 @@ MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
}
void
MappingLinearDrag::aborted (bool moved)
MappingLinearDrag::aborted (bool /* moved */)
{
_editor->abort_reversible_command ();
_editor->abort_tempo_mapping ();
}
@ -3791,10 +3795,9 @@ MappingTwistDrag::motion (GdkEvent* event, bool first_move)
const double pixel_distance = last_pointer_x() - _drags->current_pointer_x();
const double spp = _editor->get_current_zoom();
const double scaling_factor = 0.4 * (spp / 1000.);
const double scaling_factor = 0.4 * (spp / 1500.);
delta += scaling_factor * pixel_distance;
std::cerr << "pixels: " << pixel_distance << " @ " << spp << " spp SF " << scaling_factor << " => delta " << delta << std::endl;
map->twist_tempi (prev, focus, next, initial_npm + delta);
_editor->mid_tempo_change (Editor::MappingChanged);

View File

@ -915,7 +915,7 @@ private:
class MappingLinearDrag : public Drag
{
public:
MappingLinearDrag (Editor *, ArdourCanvas::Item *, Temporal::TempoMap::WritableSharedPtr&);
MappingLinearDrag (Editor *, ArdourCanvas::Item *, Temporal::TempoMap::WritableSharedPtr&, Temporal::TempoPoint&, Temporal::TempoPoint& after, XMLNode& before_state);
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
void motion (GdkEvent *, bool);
@ -933,7 +933,8 @@ public:
void setup_pointer_offset ();
private:
Temporal::TempoPoint* _tempo;
Temporal::TempoPoint& _tempo;
Temporal::TempoPoint& _after;
double _grab_bpm;
Temporal::TempoMap::WritableSharedPtr map;

View File

@ -2928,6 +2928,11 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
return;
}
if (_cursor_stack.empty() || _cursor_stack.back() != cursors()->time_fx) {
/* Not close enough to a beat line to start any mapping drag */
return;
}
Temporal::TempoMap::WritableSharedPtr map = begin_tempo_mapping ();
/* Decide between a tempo twist drag, which we do if the
@ -2941,33 +2946,20 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
TempoPoint* after = const_cast<TempoPoint*> (map->next_tempo (tempo));
if (!after || dynamic_cast<MusicTimePoint*>(after)) {
/* Drag on the bar, not the cursor: just adjust tempo up or
* down.
*/
_drags->set (new MappingLinearDrag (this, item, map), event);
return;
}
/* Use cursor state to determine if we are close enough to a beat line
* to do a twist. We computed that in the motion handler.
*/
if (_cursor_stack.empty() || _cursor_stack.back() != cursors()->time_fx) {
return;
}
BBT_Argument bbt = map->bbt_at (pointer_time);
bbt = BBT_Argument (bbt.reference(), bbt.round_to_beat ());
/* Create a new marker, or use the under the mouse */
XMLNode* before_state = &map->get_state();
TempoPoint* before;
TempoPoint* focus;
/* Reversible command starts here, must be ended/aborted in drag */
bool stretch = false;
begin_reversible_command (_("map tempo/twist"));
XMLNode* before_state = &map->get_state();
if (!after || dynamic_cast<MusicTimePoint*>(after)) {
stretch = true;
}
BBT_Argument bbt = map->bbt_at (pointer_time);
bbt = BBT_Argument (bbt.reference(), bbt.round_to_beat ());
if (tempo.bbt() < bbt) {
@ -2988,12 +2980,24 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
before = const_cast<TempoPoint*> (map->previous_tempo (tempo));
if (!before) {
delete before_state;
return;
}
focus = &tempo;
}
_drags->set (new MappingTwistDrag (this, item, map, *before, *focus, *after, *before_state), event);
/* Reversible commands start here, must be ended/aborted in drag */
if (stretch) {
begin_reversible_command (_("map tempo/stretch"));
std::cerr << "STRETCH\n";
_drags->set (new MappingLinearDrag (this, item, map, tempo, *focus, *before_state), event);
return;
}
std::cerr << "TWIST\n";
begin_reversible_command (_("map tempo/twist"));
_drags->set (new MappingTwistDrag (this, item, map, *before, *focus, *after, *before_state), event);
}