mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 08:14:58 +01:00
rework tempo editing.
most changes are due to a new design where tempo discontinuities at the beginning of a ramped section may be set. this allows easier mapping of live performance, especially in the common case of a ramped ritard before the beginning of a new section. feature summary: holding constraint modifier (shift) while dragging the BBT ruler area drags the tempo lines by changing the start tempo (as before) holding copy modifier (control) while dragging the BBT ruler area drags the tempo lines by changing the end tempo (ahem. not quite there) dragging a tempo mark while holding constraint (shift) will change the previous end tempo to match the marker position *worth trying*. holding constraint and copy modifier (control + shift) while dragging the BBT ruler area attempts to'pinch' or twist the surrounding tempi sp that later ones are not repositioned (currently suffereng from rounding errors)
This commit is contained in:
parent
dd72d2bf65
commit
ccb51a8ddb
11 changed files with 831 additions and 175 deletions
|
|
@ -1006,8 +1006,59 @@ Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
|
|||
}
|
||||
|
||||
bool
|
||||
Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
|
||||
Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* marker)
|
||||
{
|
||||
|
||||
if (event->type == GDK_SCROLL) {
|
||||
|
||||
TempoMap& tmap (session()->tempo_map());
|
||||
bool handled = false;
|
||||
double ntpm_adjust = 2.0;
|
||||
XMLNode* before_state = &tmap.get_state();
|
||||
|
||||
if (ArdourKeyboard::modifier_state_contains (event->scroll.state, ArdourKeyboard::fine_adjust_modifier())) {
|
||||
ntpm_adjust /= 10.0;
|
||||
}
|
||||
|
||||
switch (event->scroll.direction) {
|
||||
|
||||
case GDK_SCROLL_UP:
|
||||
|
||||
if (ArdourKeyboard::indicates_copy (event->scroll.state) && ArdourKeyboard::indicates_constraint (event->scroll.state)) {
|
||||
tmap.gui_change_tempo (&marker->tempo(), marker->tempo().note_types_per_minute() + ntpm_adjust, false);
|
||||
handled = true;
|
||||
} else if (ArdourKeyboard::indicates_copy (event->scroll.state)) {
|
||||
tmap.gui_change_tempo (&marker->tempo(), marker->tempo().end_note_types_per_minute() + ntpm_adjust,true);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GDK_SCROLL_DOWN:
|
||||
|
||||
if (ArdourKeyboard::indicates_copy (event->scroll.state) && ArdourKeyboard::indicates_constraint (event->scroll.state)) {
|
||||
tmap.gui_change_tempo (&marker->tempo(), marker->tempo().note_types_per_minute() - ntpm_adjust, false);
|
||||
handled = true;
|
||||
} else if (ArdourKeyboard::indicates_copy (event->scroll.state)) {
|
||||
tmap.gui_change_tempo (&marker->tempo(), marker->tempo().end_note_types_per_minute() - ntpm_adjust, true);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
begin_reversible_command (_("Change Tempo"));
|
||||
session()->add_command (new MementoCommand<TempoMap>(tmap, before_state, &tmap.get_state()));
|
||||
commit_reversible_command ();
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
return typed_event (item, event, TempoMarkerItem);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3362,7 +3362,8 @@ MeterMarkerDrag::aborted (bool moved)
|
|||
TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
|
||||
: Drag (e, i)
|
||||
, _copy (c)
|
||||
, _grab_bpm (0.0)
|
||||
, _grab_bpm (120.0, 4.0)
|
||||
, _grab_qn (0.0)
|
||||
, before_state (0)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n");
|
||||
|
|
@ -3370,7 +3371,8 @@ TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
|
|||
_marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
|
||||
_real_section = &_marker->tempo();
|
||||
_movable = !_real_section->initial();
|
||||
_grab_bpm = _real_section->note_types_per_minute();
|
||||
_grab_bpm = Tempo (_real_section->note_types_per_minute(), _real_section->note_type(), _real_section->end_note_types_per_minute());
|
||||
_grab_qn = _real_section->pulse() * 4.0;
|
||||
assert (_marker);
|
||||
}
|
||||
|
||||
|
|
@ -3397,6 +3399,7 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
|
|||
if (!_real_section->active()) {
|
||||
return;
|
||||
}
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
|
||||
if (first_move) {
|
||||
|
||||
|
|
@ -3419,7 +3422,6 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
|
|||
swap_grab (&_marker->the_item(), 0, GDK_CURRENT_TIME);
|
||||
_marker->hide();
|
||||
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
/* get current state */
|
||||
before_state = &map.get_state();
|
||||
|
||||
|
|
@ -3449,13 +3451,18 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
|
|||
}
|
||||
|
||||
if (ArdourKeyboard::indicates_constraint (event->button.state)) {
|
||||
/* use vertical movement to alter tempo .. should be log */
|
||||
double new_bpm = max (1.5, _grab_bpm + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0));
|
||||
stringstream strs;
|
||||
_editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type()));
|
||||
strs << new_bpm;
|
||||
show_verbose_cursor_text (strs.str());
|
||||
|
||||
/**
|
||||
adjust the end tempo of the previous ramped marker, or start and end tempo if constant.
|
||||
depending on position lock style, this may or may not move the mark.
|
||||
*/
|
||||
framepos_t const pf = adjusted_current_frame (event, false);
|
||||
map.gui_stretch_tempo_end (&map.tempo_section_at_frame (_real_section->frame() - 1), map.frame_at_quarter_note (_grab_qn), pf);
|
||||
|
||||
ostringstream sstr;
|
||||
sstr << "end: " << fixed << setprecision(3) << map.tempo_section_at_frame (_real_section->frame() - 1).end_note_types_per_minute() << "\n";
|
||||
sstr << "start: " << fixed << setprecision(3) << map.tempo_section_at_frame (_real_section->frame() - 1).note_types_per_minute();
|
||||
show_verbose_cursor_text (sstr.str());
|
||||
} else if (_movable && !_real_section->locked_to_meter()) {
|
||||
framepos_t pf;
|
||||
|
||||
|
|
@ -3468,8 +3475,6 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
|
|||
pf = adjusted_current_frame (event);
|
||||
}
|
||||
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
|
||||
/* snap to beat is 1, snap to bar is -1 (sorry) */
|
||||
const int sub_num = _editor->get_grid_music_divisions (event->button.state);
|
||||
|
||||
|
|
@ -3534,10 +3539,9 @@ BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
|||
_tempo = const_cast<TempoSection*> (&map.tempo_section_at_frame (raw_grab_frame()));
|
||||
ostringstream sstr;
|
||||
|
||||
sstr << "^" << fixed << setprecision(3) << map.tempo_at_frame (adjusted_current_frame (event)).note_types_per_minute() << "\n";
|
||||
sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute();
|
||||
sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute();
|
||||
sstr << "mouse: " << fixed << setprecision(3) << map.tempo_at_frame (adjusted_current_frame (event)).note_types_per_minute() << "\n";
|
||||
show_verbose_cursor_text (sstr.str());
|
||||
finished (event, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3588,8 +3592,8 @@ BBTRulerDrag::motion (GdkEvent* event, bool first_move)
|
|||
_editor->session()->tempo_map().gui_stretch_tempo (_tempo, map.frame_at_quarter_note (_grab_qn), pf);
|
||||
}
|
||||
ostringstream sstr;
|
||||
sstr << "^" << fixed << setprecision(3) << map.tempo_at_frame (pf).note_types_per_minute() << "\n";
|
||||
sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute();
|
||||
sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute();
|
||||
sstr << "mouse: " << fixed << setprecision(3) << map.tempo_at_frame (pf).note_types_per_minute() << "\n";
|
||||
show_verbose_cursor_text (sstr.str());
|
||||
}
|
||||
|
||||
|
|
@ -3615,6 +3619,198 @@ BBTRulerDrag::aborted (bool moved)
|
|||
}
|
||||
}
|
||||
|
||||
TempoTwistDrag::TempoTwistDrag (Editor* e, ArdourCanvas::Item* i)
|
||||
: Drag (e, i)
|
||||
, _grab_qn (0.0)
|
||||
, _grab_tempo (0.0)
|
||||
, _tempo (0)
|
||||
, before_state (0)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Drags, "New TempoTwistDrag\n");
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TempoTwistDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
||||
{
|
||||
Drag::start_grab (event, cursor);
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
_tempo = const_cast<TempoSection*> (&map.tempo_section_at_frame (raw_grab_frame()));
|
||||
_grab_tempo = Tempo (_tempo->note_types_per_minute(), _tempo->note_type());
|
||||
|
||||
ostringstream sstr;
|
||||
sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n";
|
||||
sstr << ">" << fixed << setprecision(3) << _tempo->end_note_types_per_minute();
|
||||
show_verbose_cursor_text (sstr.str());
|
||||
}
|
||||
|
||||
void
|
||||
TempoTwistDrag::setup_pointer_frame_offset ()
|
||||
{
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
const double beat_at_frame = max (0.0, map.beat_at_frame (raw_grab_frame()));
|
||||
const uint32_t divisions = _editor->get_grid_beat_divisions (0);
|
||||
double beat = 0.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);
|
||||
}
|
||||
|
||||
_grab_qn = map.quarter_note_at_beat (beat);
|
||||
|
||||
_pointer_frame_offset = raw_grab_frame() - map.frame_at_quarter_note (_grab_qn);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TempoTwistDrag::motion (GdkEvent* event, bool first_move)
|
||||
{
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
|
||||
if (first_move) {
|
||||
/* get current state */
|
||||
before_state = &map.get_state();
|
||||
_editor->begin_reversible_command (_("twist tempo"));
|
||||
}
|
||||
|
||||
framepos_t pf;
|
||||
|
||||
if (_editor->snap_musical()) {
|
||||
pf = adjusted_current_frame (event, false);
|
||||
} else {
|
||||
pf = adjusted_current_frame (event);
|
||||
}
|
||||
|
||||
if (ArdourKeyboard::indicates_copy (event->button.state)) {
|
||||
/* adjust this and the next tempi to match pointer frame */
|
||||
double new_bpm = max (1.5, _grab_tempo.note_types_per_minute() + ((grab_y() - min (-1.0, current_pointer_y())) / 5.0));
|
||||
|
||||
_editor->session()->tempo_map().gui_twist_tempi (_tempo, new_bpm, map.frame_at_quarter_note (_grab_qn), pf);
|
||||
}
|
||||
ostringstream sstr;
|
||||
sstr << "<" << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n";
|
||||
sstr << ">" << fixed << setprecision(3) << _tempo->end_note_types_per_minute();
|
||||
show_verbose_cursor_text (sstr.str());
|
||||
}
|
||||
|
||||
void
|
||||
TempoTwistDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
{
|
||||
if (!movement_occurred) {
|
||||
return;
|
||||
}
|
||||
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
|
||||
XMLNode &after = map.get_state();
|
||||
_editor->session()->add_command(new MementoCommand<TempoMap>(map, before_state, &after));
|
||||
_editor->commit_reversible_command ();
|
||||
}
|
||||
|
||||
void
|
||||
TempoTwistDrag::aborted (bool moved)
|
||||
{
|
||||
if (moved) {
|
||||
_editor->session()->tempo_map().set_state (*before_state, Stateful::current_state_version);
|
||||
}
|
||||
}
|
||||
|
||||
TempoEndDrag::TempoEndDrag (Editor* e, ArdourCanvas::Item* i)
|
||||
: Drag (e, i)
|
||||
, _grab_qn (0.0)
|
||||
, _tempo (0)
|
||||
, before_state (0)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Drags, "New TempoEndDrag\n");
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TempoEndDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
||||
{
|
||||
Drag::start_grab (event, cursor);
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
_tempo = const_cast<TempoSection*> (&map.tempo_section_at_frame (raw_grab_frame()));
|
||||
|
||||
ostringstream sstr;
|
||||
sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n";
|
||||
sstr << "mouse: " << fixed << setprecision(3) << map.tempo_at_frame (raw_grab_frame()).note_types_per_minute();
|
||||
show_verbose_cursor_text (sstr.str());
|
||||
}
|
||||
|
||||
void
|
||||
TempoEndDrag::setup_pointer_frame_offset ()
|
||||
{
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
const double beat_at_frame = max (0.0, map.beat_at_frame (raw_grab_frame()));
|
||||
const uint32_t divisions = _editor->get_grid_beat_divisions (0);
|
||||
double beat = 0.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);
|
||||
}
|
||||
|
||||
_grab_qn = map.quarter_note_at_beat (beat);
|
||||
|
||||
_pointer_frame_offset = raw_grab_frame() - map.frame_at_quarter_note (_grab_qn);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TempoEndDrag::motion (GdkEvent* event, bool first_move)
|
||||
{
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
|
||||
if (first_move) {
|
||||
/* get current state */
|
||||
before_state = &map.get_state();
|
||||
_editor->begin_reversible_command (_("stretch end tempo"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
framepos_t const pf = adjusted_current_frame (event, false);
|
||||
map.gui_stretch_tempo_end (_tempo, map.frame_at_quarter_note (_grab_qn), pf);
|
||||
|
||||
ostringstream sstr;
|
||||
sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n";
|
||||
sstr << "mouse: " << fixed << setprecision(3) << map.tempo_at_frame (pf).note_types_per_minute();
|
||||
show_verbose_cursor_text (sstr.str());
|
||||
}
|
||||
|
||||
void
|
||||
TempoEndDrag::finished (GdkEvent* event, bool movement_occurred)
|
||||
{
|
||||
if (!movement_occurred) {
|
||||
return;
|
||||
}
|
||||
|
||||
TempoMap& map (_editor->session()->tempo_map());
|
||||
|
||||
XMLNode &after = map.get_state();
|
||||
_editor->session()->add_command(new MementoCommand<TempoMap>(map, before_state, &after));
|
||||
_editor->commit_reversible_command ();
|
||||
}
|
||||
|
||||
void
|
||||
TempoEndDrag::aborted (bool moved)
|
||||
{
|
||||
if (moved) {
|
||||
_editor->session()->tempo_map().set_state (*before_state, Stateful::current_state_version);
|
||||
}
|
||||
}
|
||||
|
||||
CursorDrag::CursorDrag (Editor* e, EditorCursor& c, bool s)
|
||||
: Drag (e, &c.track_canvas_item(), false)
|
||||
|
|
|
|||
|
|
@ -792,7 +792,8 @@ private:
|
|||
|
||||
bool _copy;
|
||||
bool _movable;
|
||||
double _grab_bpm;
|
||||
ARDOUR::Tempo _grab_bpm;
|
||||
double _grab_qn;
|
||||
XMLNode* before_state;
|
||||
};
|
||||
|
||||
|
|
@ -823,6 +824,62 @@ private:
|
|||
XMLNode* before_state;
|
||||
};
|
||||
|
||||
/** tempo curve twist drag */
|
||||
class TempoTwistDrag : public Drag
|
||||
{
|
||||
public:
|
||||
TempoTwistDrag (Editor *, ArdourCanvas::Item *);
|
||||
|
||||
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
|
||||
void motion (GdkEvent *, bool);
|
||||
void finished (GdkEvent *, bool);
|
||||
void aborted (bool);
|
||||
|
||||
bool allow_vertical_autoscroll () const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool y_movement_matters () const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup_pointer_frame_offset ();
|
||||
|
||||
private:
|
||||
double _grab_qn;
|
||||
ARDOUR::Tempo _grab_tempo;
|
||||
ARDOUR::TempoSection* _tempo;
|
||||
XMLNode* before_state;
|
||||
};
|
||||
|
||||
|
||||
/** tempo curve twist drag */
|
||||
class TempoEndDrag : public Drag
|
||||
{
|
||||
public:
|
||||
TempoEndDrag (Editor *, ArdourCanvas::Item *);
|
||||
|
||||
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
|
||||
void motion (GdkEvent *, bool);
|
||||
void finished (GdkEvent *, bool);
|
||||
void aborted (bool);
|
||||
|
||||
bool allow_vertical_autoscroll () const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool y_movement_matters () const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup_pointer_frame_offset ();
|
||||
|
||||
private:
|
||||
double _grab_qn;
|
||||
ARDOUR::TempoSection* _tempo;
|
||||
XMLNode* before_state;
|
||||
};
|
||||
|
||||
/** Drag of the playhead cursor */
|
||||
class CursorDrag : public Drag
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1415,11 +1415,11 @@ Editor::toggle_marker_lock_style ()
|
|||
} else if (tm) {
|
||||
TempoSection* tsp = &tm->tempo();
|
||||
|
||||
const Tempo tempo (tsp->note_types_per_minute(), tsp->note_type());
|
||||
const double pulse = tsp->pulse();
|
||||
const framepos_t frame = tsp->frame();
|
||||
const TempoSection::Type type = tsp->type();
|
||||
const PositionLockStyle pls = (tsp->position_lock_style() == AudioTime) ? MusicTime : AudioTime;
|
||||
const Tempo tempo (tsp->note_types_per_minute(), tsp->note_type(), tsp->end_note_types_per_minute());
|
||||
|
||||
begin_reversible_command (_("change tempo lock style"));
|
||||
XMLNode &before = _session->tempo_map().get_state();
|
||||
|
|
@ -1442,7 +1442,7 @@ Editor::toggle_tempo_type ()
|
|||
if (tm) {
|
||||
TempoSection* tsp = &tm->tempo();
|
||||
|
||||
const Tempo tempo (tsp->note_types_per_minute(), tsp->note_type());
|
||||
const Tempo tempo (tsp->note_types_per_minute(), tsp->note_type(), tsp->end_note_types_per_minute());
|
||||
const double pulse = tsp->pulse();
|
||||
const framepos_t frame = tsp->frame();
|
||||
const TempoSection::Type type = (tsp->type() == TempoSection::Ramp) ? TempoSection::Constant : TempoSection::Ramp;
|
||||
|
|
|
|||
|
|
@ -726,8 +726,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)
|
||||
&& !ArdourKeyboard::indicates_constraint (event->button.state)) {
|
||||
_drags->set (new CursorDrag (this, *playhead_cursor, false), event);
|
||||
} else if (ArdourKeyboard::indicates_constraint (event->button.state) && ArdourKeyboard::indicates_copy (event->button.state)) {
|
||||
_drags->set (new TempoTwistDrag (this, item), event);
|
||||
} else if (ArdourKeyboard::indicates_constraint (event->button.state)) {
|
||||
_drags->set (new BBTRulerDrag (this, item), event);
|
||||
} else if (ArdourKeyboard::indicates_copy (event->button.state)) {
|
||||
_drags->set (new TempoEndDrag ( this, item), event);
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -6710,11 +6710,11 @@ Editor::define_one_bar (framepos_t start, framepos_t end)
|
|||
XMLNode& before (_session->tempo_map().get_state());
|
||||
|
||||
if (do_global) {
|
||||
_session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
|
||||
_session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
|
||||
} else if (t.frame() == start) {
|
||||
_session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
|
||||
_session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
|
||||
} else {
|
||||
const Tempo tempo (beats_per_minute, t.note_type());
|
||||
const Tempo tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
|
||||
_session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ Editor::draw_metric_marks (const Metrics& metrics)
|
|||
char buf[64];
|
||||
double max_tempo = 0.0;
|
||||
double min_tempo = DBL_MAX;
|
||||
const TempoSection *prev_ts = 0;
|
||||
|
||||
remove_metric_marks (); // also clears tempo curves
|
||||
|
||||
|
|
@ -110,10 +111,18 @@ Editor::draw_metric_marks (const Metrics& metrics)
|
|||
}
|
||||
|
||||
max_tempo = max (max_tempo, ts->note_types_per_minute());
|
||||
max_tempo = max (max_tempo, ts->end_note_types_per_minute());
|
||||
min_tempo = min (min_tempo, ts->note_types_per_minute());
|
||||
min_tempo = min (min_tempo, ts->end_note_types_per_minute());
|
||||
uint32_t tc_color = UIConfiguration::instance().color ("tempo curve");
|
||||
|
||||
tempo_curves.push_back (new TempoCurve (*this, *tempo_group, UIConfiguration::instance().color ("tempo curve"),
|
||||
if (prev_ts && abs (prev_ts->end_note_types_per_minute() - ts->note_types_per_minute()) < 2) {
|
||||
tc_color = UIConfiguration::instance().color ("location loop");
|
||||
}
|
||||
|
||||
tempo_curves.push_back (new TempoCurve (*this, *tempo_group, tc_color,
|
||||
*(const_cast<TempoSection*>(ts)), ts->frame(), false));
|
||||
|
||||
if (ts->position_lock_style() == MusicTime) {
|
||||
metric_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color ("tempo marker music"), buf,
|
||||
*(const_cast<TempoSection*>(ts))));
|
||||
|
|
@ -122,6 +131,8 @@ Editor::draw_metric_marks (const Metrics& metrics)
|
|||
*(const_cast<TempoSection*>(ts))));
|
||||
}
|
||||
|
||||
prev_ts = ts;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -224,7 +235,9 @@ Editor::tempometric_position_changed (const PropertyChange& /*ignored*/)
|
|||
tempo_marker->set_name (buf);
|
||||
|
||||
max_tempo = max (max_tempo, ts->note_types_per_minute());
|
||||
max_tempo = max (max_tempo, ts->end_note_types_per_minute());
|
||||
min_tempo = min (min_tempo, ts->note_types_per_minute());
|
||||
min_tempo = min (min_tempo, ts->end_note_types_per_minute());
|
||||
}
|
||||
}
|
||||
if ((meter_marker = dynamic_cast<MeterMarker*> (*x)) != 0) {
|
||||
|
|
@ -250,6 +263,11 @@ Editor::tempometric_position_changed (const PropertyChange& /*ignored*/)
|
|||
(*x)->set_min_tempo (min_tempo);
|
||||
++tmp;
|
||||
if (tmp != tempo_curves.end()) {
|
||||
if (abs ((*tmp)->tempo().note_types_per_minute() - (*x)->tempo().end_note_types_per_minute()) < 2) {
|
||||
(*tmp)->set_color_rgba (UIConfiguration::instance().color ("location loop"));
|
||||
} else {
|
||||
(*tmp)->set_color_rgba (UIConfiguration::instance().color ("tempo curve"));
|
||||
}
|
||||
(*x)->set_position ((*x)->tempo().frame(), (*tmp)->tempo().frame());
|
||||
} else {
|
||||
(*x)->set_position ((*x)->tempo().frame(), UINT32_MAX);
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ void
|
|||
TempoCurve::set_color_rgba (uint32_t c)
|
||||
{
|
||||
_color = c;
|
||||
_curve->set_fill_color (UIConfiguration::instance().color_mod ("tempo curve", "selection rect"));
|
||||
_curve->set_fill_color (UIConfiguration::instance().color_mod (c, "selection rect"));
|
||||
_curve->set_outline_color (_color);
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue