mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 00:04:56 +01:00
tempo mapping: various tweaks and improvements to workflow/Ux
This commit is contained in:
parent
f29557348e
commit
c10b265333
3 changed files with 61 additions and 53 deletions
|
|
@ -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)
|
: Drag (e, i, Temporal::BeatTime)
|
||||||
, _tempo (0)
|
, _tempo (tp)
|
||||||
|
, _after (ap)
|
||||||
, _grab_bpm (0)
|
, _grab_bpm (0)
|
||||||
, map (wmap)
|
, map (wmap)
|
||||||
, _before_state (0)
|
, _before_state (&before)
|
||||||
, _drag_valid (true)
|
, _drag_valid (true)
|
||||||
{
|
{
|
||||||
DEBUG_TRACE (DEBUG::Drags, "New MappingLinearDrag\n");
|
DEBUG_TRACE (DEBUG::Drags, "New MappingLinearDrag\n");
|
||||||
|
|
@ -3493,33 +3494,23 @@ MappingLinearDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
||||||
{
|
{
|
||||||
Drag::start_grab (event, 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();
|
||||||
_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ostringstream sstr;
|
ostringstream sstr;
|
||||||
if (_tempo->continuing()) {
|
if (_tempo.continuing()) {
|
||||||
TempoPoint const * prev = map->previous_tempo (*_tempo);
|
TempoPoint const * prev = map->previous_tempo (_tempo);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
sstr << "end: " << fixed << setprecision(3) << prev->end_note_types_per_minute() << "\n";
|
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());
|
show_verbose_cursor_text (sstr.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MappingLinearDrag::setup_pointer_offset ()
|
MappingLinearDrag::setup_pointer_offset ()
|
||||||
{
|
{
|
||||||
/* get current state */
|
|
||||||
_before_state = &map->get_state();
|
|
||||||
|
|
||||||
Beats grab_qn = max (Beats(), raw_grab_time().beats());
|
Beats grab_qn = max (Beats(), raw_grab_time().beats());
|
||||||
|
|
||||||
uint32_t divisions = _editor->get_grid_beat_divisions (_editor->grid_type());
|
uint32_t divisions = _editor->get_grid_beat_divisions (_editor->grid_type());
|
||||||
|
|
@ -3539,14 +3530,26 @@ MappingLinearDrag::motion (GdkEvent* event, bool first_move)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first_move) {
|
const double pixel_distance = current_pointer_x() - grab_x();
|
||||||
_editor->begin_reversible_command (_("map tempo"));
|
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);
|
_editor->mid_tempo_change (Editor::MappingChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3554,7 +3557,7 @@ void
|
||||||
MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
|
MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||||
{
|
{
|
||||||
if (!_drag_valid) {
|
if (!_drag_valid) {
|
||||||
_editor->abort_tempo_mapping ();
|
aborted (false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3572,7 +3575,7 @@ MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||||
|
|
||||||
XMLNode &after = map->get_state();
|
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 ();
|
_editor->commit_reversible_command ();
|
||||||
|
|
||||||
/* 2nd argument means "update tempo map display after the new map is
|
/* 2nd argument means "update tempo map display after the new map is
|
||||||
|
|
@ -3585,8 +3588,9 @@ MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MappingLinearDrag::aborted (bool moved)
|
MappingLinearDrag::aborted (bool /* moved */)
|
||||||
{
|
{
|
||||||
|
_editor->abort_reversible_command ();
|
||||||
_editor->abort_tempo_mapping ();
|
_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 pixel_distance = last_pointer_x() - _drags->current_pointer_x();
|
||||||
const double spp = _editor->get_current_zoom();
|
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;
|
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);
|
map->twist_tempi (prev, focus, next, initial_npm + delta);
|
||||||
_editor->mid_tempo_change (Editor::MappingChanged);
|
_editor->mid_tempo_change (Editor::MappingChanged);
|
||||||
|
|
|
||||||
|
|
@ -915,7 +915,7 @@ private:
|
||||||
class MappingLinearDrag : public Drag
|
class MappingLinearDrag : public Drag
|
||||||
{
|
{
|
||||||
public:
|
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 start_grab (GdkEvent *, Gdk::Cursor* c = 0);
|
||||||
void motion (GdkEvent *, bool);
|
void motion (GdkEvent *, bool);
|
||||||
|
|
@ -933,7 +933,8 @@ public:
|
||||||
void setup_pointer_offset ();
|
void setup_pointer_offset ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Temporal::TempoPoint* _tempo;
|
Temporal::TempoPoint& _tempo;
|
||||||
|
Temporal::TempoPoint& _after;
|
||||||
double _grab_bpm;
|
double _grab_bpm;
|
||||||
Temporal::TempoMap::WritableSharedPtr map;
|
Temporal::TempoMap::WritableSharedPtr map;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2928,6 +2928,11 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
|
||||||
return;
|
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 ();
|
Temporal::TempoMap::WritableSharedPtr map = begin_tempo_mapping ();
|
||||||
|
|
||||||
/* Decide between a tempo twist drag, which we do if the
|
/* 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));
|
TempoPoint* after = const_cast<TempoPoint*> (map->next_tempo (tempo));
|
||||||
|
|
||||||
if (!after || dynamic_cast<MusicTimePoint*>(after)) {
|
/* Create a new marker, or use the under the mouse */
|
||||||
/* 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 ());
|
|
||||||
|
|
||||||
|
XMLNode* before_state = &map->get_state();
|
||||||
TempoPoint* before;
|
TempoPoint* before;
|
||||||
TempoPoint* focus;
|
TempoPoint* focus;
|
||||||
|
|
||||||
/* Reversible command starts here, must be ended/aborted in drag */
|
bool stretch = false;
|
||||||
|
|
||||||
begin_reversible_command (_("map tempo/twist"));
|
if (!after || dynamic_cast<MusicTimePoint*>(after)) {
|
||||||
XMLNode* before_state = &map->get_state();
|
stretch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BBT_Argument bbt = map->bbt_at (pointer_time);
|
||||||
|
bbt = BBT_Argument (bbt.reference(), bbt.round_to_beat ());
|
||||||
|
|
||||||
if (tempo.bbt() < bbt) {
|
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));
|
before = const_cast<TempoPoint*> (map->previous_tempo (tempo));
|
||||||
|
|
||||||
if (!before) {
|
if (!before) {
|
||||||
|
delete before_state;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
focus = &tempo;
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue