Compare commits

...

32 Commits

Author SHA1 Message Date
nick_m 5fc202b237 probable fix for importing tempo maps that use non-quarter note pulse.
- actually i'm not certain that this is correct,
	  but it works ok Beethoven's fifth.
2017-02-28 03:11:22 +11:00
Ben Loftis 5a8dece2c9 De-cramp the transcoding dialog widgets. 2017-02-27 09:48:37 -06:00
nick_m 80e37a39f4 _group, group.. who cares? 2017-02-28 01:05:39 +11:00
nick_m 85b4c9df9b clicking on curve text does the right thing. 2017-02-27 19:20:50 +11:00
nick_m c95cfb8e69 initial rework of tempo text display (numbers are curve items)
- move tempo numbers to a layer above the curve.

	- the offset of the text box in Marker is horrible here.
	  what to do?
2017-02-27 17:53:31 +11:00
nick_m 03e9225787 fix crash in pinch drag 2017-02-27 17:40:20 +11:00
nick_m 757a72adc0 remove scroll wheel editing nonsense (tempo) 2017-02-27 13:44:23 +11:00
nick_m 3fd874fd9f fix compilation 2017-02-27 13:14:53 +11:00
nick_m cb2a5a96e6 remove 'mouse:' verbose cursor when shift-dragging a curve. 2017-02-27 12:29:55 +11:00
nick_m 1737bc3095 only allow 'ramp to next' if the next tempo is actually different. 2017-02-27 12:00:25 +11:00
nick_m 62bf37d4f7 poor man's display of end tempo for ramps. 2017-02-27 11:59:16 +11:00
nick_m 3f67f6d6a1 harden TempoMap::next_tempo_section () a bit. 2017-02-27 11:41:48 +11:00
nick_m ad84332661 Tempo Marks : set point colour by discontinuity, display non-quarter pulse if we are non-quarter.
- a jump in tempo by more than 1 ntpm results in a red
	 tempo mark pointer.

	- ignore UIConfiguration::get_allow_non_quarter_pulse()
	  when displaying note type in the marker text (only display
	  note type if we are non-quarter).
2017-02-27 11:10:47 +11:00
nick_m adffdc02bd remove commented line 2017-02-27 04:36:48 +11:00
nick_m ba55c3a156 fix tempo marker ramp to next. 2017-02-27 04:22:45 +11:00
nick_m abc4852f03 amend last commit (don't depend on 0.0) 2017-02-27 04:12:13 +11:00
nick_m 553083304b hopefully fix legacy session loading (tempo) 2017-02-27 04:01:11 +11:00
nick_m 4967386374 add right-click 'Ramp to Next' tempo marker menu item. 2017-02-27 03:03:55 +11:00
nick_m 41cf5a364b back to using shift-ctrl for pinch drag. set colours of affected curves. 2017-02-27 02:26:08 +11:00
nick_m 77d837d3b4 add TempoMap::next_tempo_section() 2017-02-27 02:21:05 +11:00
nick_m 5f8e9c8e4a fix TempoMap::frame_at_tempo(). 2017-02-27 01:28:59 +11:00
nick_m 35fdfcd5ef highlight the tempo curve that is to be altered, modify text to suit. 2017-02-26 07:03:02 +11:00
nick_m 206f2601d7 fix verbose cursor display when shift-dragging end tempo. 2017-02-26 06:01:49 +11:00
nick_m be5b7e39f3 restore pinch tempo. it now operates via shift + alt drag on the curve. 2017-02-26 05:39:20 +11:00
nick_m c6bcbaaced remove tempo end drag (the control drag on the curve). a;ter tempo marker drag.
- holding down shift before initiating a tempo mark drag
	  alters the end tempo of the previous one as before, but
	  this is now a separate drag.
	- restore vertical dragging of the tempo mark to alter start/
	  end tempo. shift during the makrker drag alters start tempo.
	  xontrol + shift during the drag alters end tempo.
2017-02-26 05:07:51 +11:00
nick_m da7428a953 remove "Make Ramped" from right click tempo marker menu. 2017-02-26 04:02:59 +11:00
nick_m 9a2dd16df6 fix formatting of bbtruler drag verbose cursor. 2017-02-26 02:52:58 +11:00
nick_m 922e40e0d3 complete changes to tempo type.
- this implements in the intention behind the previous commit.
	  a tempo mark is constant until its end has been changed by a
	  shift-drag on the next marker.
2017-02-26 02:22:19 +11:00
Ben Loftis 30792f89b1 compile fix 2017-02-25 07:04:15 -06:00
nick_m b4fcacadf1 make new (ramped) tempi indidstiguishable from constant to the novice user.
- stretch drag (using shift on the curve) operates on
	  the true meaning of constant. in other words,
	  the only way you can make a tempo ramped is by adjusting the end
	  tempo (shift drag on the *next* mark). from this point onwards.
	  shift-drag the curve will change the start tempo and ctrl-drag
	  the curve will change the end (needs work). to reset the
	  curve to constant, 'make constant' should simply set the end
	  tempo (unimplemented).
2017-02-25 23:32:02 +11:00
nick_m 33cacfcc41 correct (?) behaviour of TempoMap::replace_tempo 2017-02-25 06:59:05 +11:00
nick_m d78039dd85 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)
2017-02-25 05:09:16 +11:00
21 changed files with 1060 additions and 324 deletions

View File

@ -332,6 +332,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void mixer_strip_width_changed ();
void hide_track_in_display (TimeAxisView* tv, bool apply_to_selection = false);
void show_track_in_display (TimeAxisView* tv, bool move_into_view = false);
void tempo_curve_selected (ARDOUR::TempoSection* ts, bool yn);
/* nudge is initiated by transport controls owned by ARDOUR_UI */
@ -1687,6 +1688,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void rename_marker (ArdourMarker *marker);
void toggle_marker_lock_style ();
void toggle_tempo_type ();
void ramp_to_next_tempo ();
void toggle_marker_menu_lock ();
void toggle_marker_menu_glue ();
void marker_menu_hide ();

View File

@ -285,12 +285,12 @@ Editor::import_smf_tempo_map (Evoral::SMF const & smf, framepos_t pos)
Evoral::SMF::Tempo* t = smf.nth_tempo (n);
assert (t);
Tempo tempo (t->tempo(), 4.0);
Tempo tempo (t->tempo(), 32.0 / (double) t->notes_per_note);
Meter meter (t->numerator, t->denominator);
Timecode::BBT_Time bbt; /* 1|1|0 which is correct for the no-meter case */
if (have_initial_meter) {
new_map.add_tempo (tempo, (t->time_pulses/smf.ppqn()) / 4.0, 0, TempoSection::Constant, MusicTime);
new_map.add_tempo (tempo, (t->time_pulses/smf.ppqn()) / 4.0, 0, MusicTime);
if (!(meter == last_meter)) {
bbt = new_map.bbt_at_quarter_note ((t->time_pulses/smf.ppqn()));
new_map.add_meter (meter, t->time_pulses, bbt, 0, MusicTime);
@ -298,7 +298,7 @@ Editor::import_smf_tempo_map (Evoral::SMF const & smf, framepos_t pos)
} else {
new_map.replace_meter (new_map.meter_section_at_frame (0), meter, bbt, pos, AudioTime);
new_map.replace_tempo (new_map.tempo_section_at_frame (0), tempo, 0.0, pos, TempoSection::Constant, AudioTime);
new_map.replace_tempo (new_map.tempo_section_at_frame (0), tempo, 0.0, pos, AudioTime);
have_initial_meter = true;
}

View File

@ -1006,7 +1006,7 @@ 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)
{
return typed_event (item, event, TempoMarkerItem);
}

View File

@ -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();
@ -3429,15 +3431,14 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
} else {
const Tempo tempo (_marker->tempo());
const framepos_t frame = adjusted_current_frame (event) + 1;
const TempoSection::Type type = _real_section->type();
_editor->begin_reversible_command (_("copy tempo mark"));
if (_real_section->position_lock_style() == MusicTime) {
const int32_t divisions = _editor->get_grid_music_divisions (event->button.state);
_real_section = map.add_tempo (tempo, map.exact_qn_at_frame (frame, divisions), 0, type, MusicTime);
_real_section = map.add_tempo (tempo, map.exact_qn_at_frame (frame, divisions), 0, MusicTime);
} else {
_real_section = map.add_tempo (tempo, 0.0, frame, type, AudioTime);
_real_section = map.add_tempo (tempo, 0.0, frame, AudioTime);
}
if (!_real_section) {
@ -3447,13 +3448,19 @@ 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));
if (ArdourKeyboard::indicates_constraint (event->button.state) && ArdourKeyboard::indicates_copy (event->button.state)) {
double new_bpm = max (1.5, _grab_bpm.end_note_types_per_minute() + ((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;
_editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type()), true);
strs << "end:" << fixed << setprecision(3) << new_bpm;
show_verbose_cursor_text (strs.str());
} else if (ArdourKeyboard::indicates_constraint (event->button.state)) {
/* use vertical movement to alter tempo .. should be log */
double new_bpm = max (1.5, _grab_bpm.note_types_per_minute() + ((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()), false);
strs << "start:" << fixed << setprecision(3) << new_bpm;
show_verbose_cursor_text (strs.str());
} else if (_movable && !_real_section->locked_to_meter()) {
@ -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);
@ -3532,12 +3537,11 @@ BBTRulerDrag::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;
_editor->tempo_curve_selected (_tempo, true);
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();
ostringstream sstr;
sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute();
show_verbose_cursor_text (sstr.str());
finished (event, false);
}
void
@ -3588,8 +3592,7 @@ 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();
show_verbose_cursor_text (sstr.str());
}
@ -3605,6 +3608,7 @@ BBTRulerDrag::finished (GdkEvent* event, bool movement_occurred)
XMLNode &after = map.get_state();
_editor->session()->add_command(new MementoCommand<TempoMap>(map, before_state, &after));
_editor->commit_reversible_command ();
_editor->tempo_curve_selected (_tempo, false);
}
void
@ -3615,6 +3619,223 @@ BBTRulerDrag::aborted (bool moved)
}
}
TempoTwistDrag::TempoTwistDrag (Editor* e, ArdourCanvas::Item* i)
: Drag (e, i)
, _grab_qn (0.0)
, _grab_tempo (0.0)
, _tempo (0)
, _next_tempo (0)
, _drag_valid (true)
, 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()));
_next_tempo = map.next_tempo_section (_tempo);
if (_next_tempo) {
if (!map.next_tempo_section (_next_tempo)) {
_drag_valid = false;
finished (event, false);
return;
}
_editor->tempo_curve_selected (_tempo, true);
_editor->tempo_curve_selected (_next_tempo, true);
ostringstream sstr;
sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n";
sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n";
sstr << "start: " << fixed << setprecision(3) << _next_tempo->note_types_per_minute();
show_verbose_cursor_text (sstr.str());
} else {
_drag_valid = false;
}
_grab_tempo = Tempo (_tempo->note_types_per_minute(), _tempo->note_type());
}
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)
{
if (!_next_tempo || !_drag_valid) {
return;
}
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);
}
/* 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 << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute() << "\n";
sstr << "end: " << fixed << setprecision(3) << _tempo->end_note_types_per_minute() << "\n";
sstr << "start: " << fixed << setprecision(3) << _next_tempo->note_types_per_minute();
show_verbose_cursor_text (sstr.str());
}
void
TempoTwistDrag::finished (GdkEvent* event, bool movement_occurred)
{
TempoMap& map (_editor->session()->tempo_map());
if (!movement_occurred || !_drag_valid) {
return;
}
_editor->tempo_curve_selected (_tempo, false);
_editor->tempo_curve_selected (_next_tempo, false);
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()));
_editor->tempo_curve_selected (&map.tempo_section_at_frame (_tempo->frame() - 1), true);
ostringstream sstr;
sstr << "end: " << fixed << setprecision(3) << map.tempo_section_at_frame (_tempo->frame() - 1).end_note_types_per_minute() << "\n";
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 (&map.tempo_section_at_frame (_tempo->frame() - 1), map.frame_at_quarter_note (_grab_qn), pf);
ostringstream sstr;
sstr << "end: " << fixed << setprecision(3) << map.tempo_section_at_frame (_tempo->frame() - 1).end_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 ();
_editor->tempo_curve_selected (&map.tempo_section_at_frame (_tempo->frame() - 1), false);
}
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)

View File

@ -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,64 @@ 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;
ARDOUR::TempoSection* _next_tempo;
bool _drag_valid;
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
{

View File

@ -991,10 +991,13 @@ Editor::build_tempo_marker_menu (TempoMarker* loc, bool can_remove)
MenuList& items = tempo_marker_menu->items();
tempo_marker_menu->set_name ("ArdourContextMenu");
if (loc->tempo().type() == TempoSection::Constant) {
items.push_back (MenuElem (_("Make Ramped"), sigc::mem_fun(*this, &Editor::toggle_tempo_type)));
} else {
items.push_back (MenuElem (_("Make Constant"), sigc::mem_fun(*this, &Editor::toggle_tempo_type)));
if (loc->tempo().type() == TempoSection::Ramp) {
items.push_back (MenuElem (_("Set Constant"), sigc::mem_fun(*this, &Editor::toggle_tempo_type)));
}
TempoSection* next_ts = _session->tempo_map().next_tempo_section (&loc->tempo());
if (next_ts && next_ts->note_types_per_minute() != loc->tempo().end_note_types_per_minute()) {
items.push_back (MenuElem (_("Ramp to Next"), sigc::mem_fun(*this, &Editor::ramp_to_next_tempo)));
}
if (loc->tempo().position_lock_style() == AudioTime && can_remove) {
@ -1415,23 +1418,22 @@ 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();
_session->tempo_map().replace_tempo (*tsp, tempo, pulse, frame, type, pls);
_session->tempo_map().replace_tempo (*tsp, tempo, pulse, frame, pls);
XMLNode &after = _session->tempo_map().get_state();
_session->add_command(new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
commit_reversible_command ();
}
}
/* actally just resets the ts to constant using initial tempo */
void
Editor::toggle_tempo_type ()
{
@ -1445,13 +1447,12 @@ Editor::toggle_tempo_type ()
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() == TempoSection::Ramp) ? TempoSection::Constant : TempoSection::Ramp;
const PositionLockStyle pls = tsp->position_lock_style();
begin_reversible_command (_("change tempo type"));
begin_reversible_command (_("set tempo to constant"));
XMLNode &before = _session->tempo_map().get_state();
_session->tempo_map().replace_tempo (*tsp, tempo, pulse, frame, type, pls);
_session->tempo_map().replace_tempo (*tsp, tempo, pulse, frame, pls);
XMLNode &after = _session->tempo_map().get_state();
_session->add_command(new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
@ -1459,6 +1460,35 @@ Editor::toggle_tempo_type ()
}
}
void
Editor::ramp_to_next_tempo ()
{
TempoMarker* tm;
MeterMarker* mm;
dynamic_cast_marker_object (marker_menu_item->get_data ("marker"), &mm, &tm);
if (tm) {
TempoMap& tmap (_session->tempo_map());
TempoSection* tsp = &tm->tempo();
TempoSection* next_ts = tmap.next_tempo_section (&tm->tempo());
if (next_ts) {
const Tempo tempo (tsp->note_types_per_minute(), tsp->note_type(), next_ts->note_types_per_minute());
const double pulse = tsp->pulse();
const framepos_t frame = tsp->frame();
const PositionLockStyle pls = tsp->position_lock_style();
begin_reversible_command (_("ramp to next tempo"));
XMLNode &before = _session->tempo_map().get_state();
tmap.replace_tempo (*tsp, tempo, pulse, frame, pls);
XMLNode &after = _session->tempo_map().get_state();
_session->add_command(new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
commit_reversible_command ();
}
}
}
void
Editor::toggle_marker_menu_lock ()
{

View File

@ -686,14 +686,25 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case TempoMarkerItem:
{
_drags->set (
new TempoMarkerDrag (
this,
item,
ArdourKeyboard::indicates_copy (event->button.state)
),
event
);
if (ArdourKeyboard::indicates_constraint (event->button.state)) {
_drags->set (
new TempoEndDrag (
this,
item
),
event
);
} else {
_drags->set (
new TempoMarkerDrag (
this,
item,
ArdourKeyboard::indicates_copy (event->button.state)
),
event
);
}
return true;
}
@ -726,6 +737,9 @@ 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)
&& Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
_drags->set (new TempoTwistDrag (this, item), event);
} else if (ArdourKeyboard::indicates_constraint (event->button.state)) {
_drags->set (new BBTRulerDrag (this, item), event);
}

View File

@ -6710,12 +6710,13 @@ 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 {
/* constant tempo */
const Tempo tempo (beats_per_minute, t.note_type());
_session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
_session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
}
XMLNode& after (_session->tempo_map().get_state());

View File

@ -84,6 +84,7 @@ void
Editor::draw_metric_marks (const Metrics& metrics)
{
char buf[64];
TempoSection* prev_ts = 0;
double max_tempo = 0.0;
double min_tempo = DBL_MAX;
@ -91,7 +92,7 @@ Editor::draw_metric_marks (const Metrics& metrics)
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
const MeterSection *ms;
const TempoSection *ts;
TempoSection *ts;
if ((ms = dynamic_cast<const MeterSection*>(*i)) != 0) {
snprintf (buf, sizeof(buf), "%g/%g", ms->divisions_per_bar(), ms->note_divisor ());
@ -102,26 +103,31 @@ Editor::draw_metric_marks (const Metrics& metrics)
metric_marks.push_back (new MeterMarker (*this, *meter_group, UIConfiguration::instance().color ("meter marker"), buf,
*(const_cast<MeterSection*>(ms))));
}
} else if ((ts = dynamic_cast<const TempoSection*>(*i)) != 0) {
if (UIConfiguration::instance().get_allow_non_quarter_pulse()) {
snprintf (buf, sizeof (buf), "%.3f/%.0f", ts->note_types_per_minute(), ts->note_type());
} else {
snprintf (buf, sizeof (buf), "%.3f", ts->note_types_per_minute());
}
} else if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
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 const tc_color = UIConfiguration::instance().color ("tempo curve");
tempo_curves.push_back (new TempoCurve (*this, *tempo_group, UIConfiguration::instance().color ("tempo curve"),
tempo_curves.push_back (new TempoCurve (*this, *tempo_group, tc_color,
*(const_cast<TempoSection*>(ts)), ts->frame(), false));
const std::string tname (X_(""));
if (ts->position_lock_style() == MusicTime) {
metric_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color ("tempo marker music"), buf,
metric_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color ("tempo marker music"), tname,
*(const_cast<TempoSection*>(ts))));
} else {
metric_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color ("tempo marker"), buf,
metric_marks.push_back (new TempoMarker (*this, *tempo_group, UIConfiguration::instance().color ("tempo marker"), tname,
*(const_cast<TempoSection*>(ts))));
}
if (prev_ts && abs (prev_ts->end_note_types_per_minute() - ts->note_types_per_minute()) < 1.0) {
metric_marks.back()->set_points_color (UIConfiguration::instance().color ("tempo marker music"));
} else {
metric_marks.back()->set_points_color (UIConfiguration::instance().color ("tempo marker"));
}
prev_ts = ts;
}
}
@ -201,30 +207,33 @@ Editor::tempometric_position_changed (const PropertyChange& /*ignored*/)
tempo_lines->tempo_map_changed();
}
TempoSection* prev_ts = 0;
double max_tempo = 0.0;
double min_tempo = DBL_MAX;
for (Marks::iterator x = metric_marks.begin(); x != metric_marks.end(); ++x) {
TempoMarker* tempo_marker;
MeterMarker* meter_marker;
const TempoSection *ts;
TempoSection *ts;
const MeterSection *ms;
if ((tempo_marker = dynamic_cast<TempoMarker*> (*x)) != 0) {
if ((ts = &tempo_marker->tempo()) != 0) {
tempo_marker->set_position (ts->frame ());
char buf[64];
if (UIConfiguration::instance().get_allow_non_quarter_pulse()) {
snprintf (buf, sizeof (buf), "%.3f/%.0f", ts->note_types_per_minute(), ts->note_type());
tempo_marker->set_position (ts->frame ());
if (prev_ts && abs (prev_ts->end_note_types_per_minute() - ts->note_types_per_minute()) < 1.0) {
tempo_marker->set_points_color (UIConfiguration::instance().color ("tempo marker music"));
} else {
snprintf (buf, sizeof (buf), "%.3f", ts->note_types_per_minute());
tempo_marker->set_points_color (UIConfiguration::instance().color ("tempo marker"));
}
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());
prev_ts = ts;
}
}
if ((meter_marker = dynamic_cast<MeterMarker*> (*x)) != 0) {
@ -304,6 +313,20 @@ Editor::redisplay_tempo (bool immediate_redraw)
Glib::signal_idle().connect (sigc::bind_return (sigc::bind (sigc::mem_fun (*this, &Editor::redisplay_tempo), true), false));
}
}
void
Editor::tempo_curve_selected (TempoSection* ts, bool yn)
{
for (Curves::iterator x = tempo_curves.begin(); x != tempo_curves.end(); ++x) {
if (&(*x)->tempo() == ts) {
if (yn) {
(*x)->set_color_rgba (UIConfiguration::instance().color ("location marker"));
} else {
(*x)->set_color_rgba (UIConfiguration::instance().color ("tempo curve"));
}
break;
}
}
}
/* computes a grid starting a beat before and ending a beat after leftmost and rightmost respectively */
void
@ -386,7 +409,7 @@ Editor::mouse_add_new_tempo_event (framepos_t frame)
if (pulse > 0.0) {
XMLNode &before = map.get_state();
/* add music-locked ramped (?) tempo using the bpm/note type at frame*/
map.add_tempo (map.tempo_at_frame (frame), pulse, 0, TempoSection::Ramp, MusicTime);
map.add_tempo (map.tempo_at_frame (frame), pulse, 0, MusicTime);
XMLNode &after = map.get_state();
_session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
@ -513,17 +536,15 @@ Editor::edit_tempo_section (TempoSection* section)
Timecode::BBT_Time when;
tempo_dialog.get_bbt_time (when);
const TempoSection::Type ttype (tempo_dialog.get_tempo_type());
begin_reversible_command (_("replace tempo mark"));
XMLNode &before = _session->tempo_map().get_state();
if (tempo_dialog.get_lock_style() == AudioTime) {
framepos_t const f = _session->tempo_map().predict_tempo_position (section, when).second;
_session->tempo_map().replace_tempo (*section, tempo, 0.0, f, ttype, AudioTime);
_session->tempo_map().replace_tempo (*section, tempo, 0.0, f, AudioTime);
} else {
double const p = _session->tempo_map().predict_tempo_position (section, when).first;
_session->tempo_map().replace_tempo (*section, tempo, p, 0, ttype, MusicTime);
_session->tempo_map().replace_tempo (*section, tempo, p, 0, MusicTime);
}
XMLNode &after = _session->tempo_map().get_state();

View File

@ -74,6 +74,7 @@ ArdourMarker::ArdourMarker (PublicEditor& ed, ArdourCanvas::Container& parent, g
, _shown (false)
, _line_shown (false)
, _color (rgba)
, _points_color (rgba)
, _left_label_limit (DBL_MAX)
, _right_label_limit (DBL_MAX)
, _label_offset (0)
@ -485,6 +486,14 @@ ArdourMarker::hide ()
setup_line ();
}
void
ArdourMarker::set_points_color (uint32_t c)
{
_points_color = c;
mark->set_fill_color (_points_color);
mark->set_outline_color (_points_color);
}
void
ArdourMarker::set_color_rgba (uint32_t c)
{

View File

@ -77,6 +77,7 @@ class ArdourMarker : public sigc::trackable
void set_position (framepos_t);
void set_name (const std::string&);
void set_points_color (uint32_t rgba);
void set_color_rgba (uint32_t rgba);
void setup_line ();
@ -123,6 +124,7 @@ class ArdourMarker : public sigc::trackable
bool _line_shown;
double _canvas_height;
uint32_t _color;
uint32_t _points_color;
double _left_label_limit; ///< the number of pixels available to the left of this marker for a label
double _right_label_limit; ///< the number of pixels available to the right of this marker for a label
double _label_offset;

View File

@ -37,7 +37,8 @@ TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint
, _min_tempo (temp.note_types_per_minute())
, _max_tempo (temp.note_types_per_minute())
, _tempo (temp)
, _start_text (0)
, _end_text (0)
{
frame_position = frame;
unit_position = editor.sample_to_pixel (frame);
@ -55,6 +56,18 @@ TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint
points = new ArdourCanvas::Points ();
_curve->set (*points);
_start_text = new ArdourCanvas::Text (group);
_end_text = new ArdourCanvas::Text (group);
_start_text->set_font_description (ARDOUR_UI_UTILS::get_font_for_style (N_("MarkerText")));
_end_text->set_font_description (ARDOUR_UI_UTILS::get_font_for_style (N_("MarkerText")));
_start_text->set_color (RGBA_TO_UINT (255,255,255,255));
_end_text->set_color (RGBA_TO_UINT (255,255,255,255));
char buf[10];
snprintf (buf, sizeof (buf), "%.3f/%.0f", _tempo.note_types_per_minute(), _tempo.note_type());
_start_text->set (buf);
snprintf (buf, sizeof (buf), "%.3f", _tempo.end_note_types_per_minute());
_end_text->set (buf);
set_color_rgba (rgba);
editor.ZoomChanged.connect (sigc::mem_fun (*this, &TempoCurve::reposition));
@ -69,7 +82,7 @@ TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint
//group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_marker_event), group, this));
}
_curve->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_tempo_curve_event), _curve, this));
group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_tempo_curve_event), _curve, this));
}
@ -147,6 +160,23 @@ TempoCurve::set_position (framepos_t frame, framepos_t end_frame)
}
_curve->set (*points);
char buf[10];
snprintf (buf, sizeof (buf), "%.3f/%.0f", _tempo.note_types_per_minute(), _tempo.note_type());
_start_text->set (buf);
snprintf (buf, sizeof (buf), "%.3f", _tempo.end_note_types_per_minute());
_end_text->set (buf);
_start_text->set_position (ArdourCanvas::Duple (10, .5 ));
_end_text->set_position (ArdourCanvas::Duple (editor.sample_to_pixel (end_frame - frame) - _end_text->text_width() - 10, .5 ));
if (_end_text->text_width() + _start_text->text_width() + 20 > editor.sample_to_pixel (end_frame - frame)) {
_start_text->hide();
_end_text->hide();
} else {
_start_text->show();
_end_text->show();
}
}
void
@ -175,7 +205,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 (_color, "selection rect"));
_curve->set_outline_color (_color);
}

View File

@ -11,6 +11,7 @@
#include "canvas/types.h"
#include "canvas/framed_curve.h"
#include "canvas/text.h"
namespace ARDOUR {
class TempoSection;
@ -68,6 +69,8 @@ private:
TempoCurve (TempoCurve const &);
TempoCurve & operator= (TempoCurve const &);
ARDOUR::TempoSection& _tempo;
ArdourCanvas::Text *_start_text;
ArdourCanvas::Text *_end_text;
};
#endif /* __gtk_ardour_tempo_curve_h__ */

View File

@ -274,6 +274,7 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
get_vbox()->pack_start (*vbox, false, false);
progress_box = manage (new VBox);
progress_box->set_spacing(6);
progress_box->pack_start (progress_label, false, false);
progress_box->pack_start (pbar, false, false);
progress_box->pack_start (abort_button, false, false);

View File

@ -54,7 +54,9 @@ class LIBARDOUR_API Tempo {
* @param type Note Type (default `4': quarter note)
*/
Tempo (double npm, double type=4.0) // defaulting to quarter note
: _note_types_per_minute (npm), _note_type(type) {}
: _note_types_per_minute (npm), _note_type (type), _end_note_types_per_minute (npm) {}
Tempo (double start_npm, double type, double end_npm)
: _note_types_per_minute (start_npm), _note_type (type), _end_note_types_per_minute (end_npm) {}
double note_types_per_minute () const { return _note_types_per_minute; }
double note_types_per_minute (double note_type) const { return (_note_types_per_minute / _note_type) * note_type; }
@ -63,6 +65,14 @@ class LIBARDOUR_API Tempo {
double quarter_notes_per_minute () const { return note_types_per_minute (4.0); }
double pulses_per_minute () const { return note_types_per_minute (1.0); }
double end_note_types_per_minute () const { return _end_note_types_per_minute; }
double end_note_types_per_minute (double note_type) const { return (_end_note_types_per_minute / _note_type) * note_type; }
void set_end_note_types_per_minute (double npm) { _end_note_types_per_minute = npm; }
double end_quarter_notes_per_minute () const { return end_note_types_per_minute (4.0); }
double end_pulses_per_minute () const { return end_note_types_per_minute (1.0); }
/** audio samples per note type.
* if you want an instantaneous value for this, use TempoMap::frames_per_quarter_note_at() instead.
* @param sr samplerate
@ -81,6 +91,7 @@ class LIBARDOUR_API Tempo {
protected:
double _note_types_per_minute;
double _note_type;
double _end_note_types_per_minute;
};
/** Meter, or time signature (beats per bar, and which note type is a beat). */
@ -189,8 +200,8 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
Constant,
};
TempoSection (const double& pulse, const double& minute, double qpm, double note_type, Type tempo_type, PositionLockStyle pls, framecnt_t sr)
: MetricSection (pulse, minute, pls, true, sr), Tempo (qpm, note_type), _type (tempo_type), _c (0.0), _active (true), _locked_to_meter (false) {}
TempoSection (const double& pulse, const double& minute, Tempo tempo, PositionLockStyle pls, framecnt_t sr)
: MetricSection (pulse, minute, pls, true, sr), Tempo (tempo), _c (0.0), _active (true), _locked_to_meter (false) {}
TempoSection (const XMLNode&, const framecnt_t sample_rate);
@ -201,8 +212,7 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
double c () const { return _c; }
void set_c (double c) { _c = c; }
void set_type (Type type);
Type type () const { return _type; }
Type type () const { if (note_types_per_minute() == end_note_types_per_minute()) { return Constant; } else { return Ramp; } }
bool active () const { return _active; }
void set_active (bool yn) { _active = yn; }
@ -226,6 +236,7 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
framepos_t frame_at_pulse (const double& pulse) const;
Timecode::BBT_Time legacy_bbt () { return _legacy_bbt; }
bool legacy_end () { return _legacy_end; }
private:
@ -253,11 +264,11 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
this enables us to keep the tempo change at the same relative
position within the bar if/when the meter changes.
*/
Type _type;
double _c;
bool _active;
bool _locked_to_meter;
Timecode::BBT_Time _legacy_bbt;
bool _legacy_end;
};
typedef std::list<MetricSection*> Metrics;
@ -329,7 +340,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
BBTPoint (const MeterSection& m, const Tempo& t, framepos_t f,
uint32_t b, uint32_t e, double func_c)
: frame (f), meter (m.divisions_per_bar(), m.note_divisor()), tempo (t.note_types_per_minute(), t.note_type()), c (func_c), bar (b), beat (e) {}
: frame (f), meter (m.divisions_per_bar(), m.note_divisor()), tempo (t.note_types_per_minute(), t.note_type(), t.end_note_types_per_minute()), c (func_c), bar (b), beat (e) {}
Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
operator Timecode::BBT_Time() const { return bbt(); }
@ -356,12 +367,14 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
const MeterSection& meter_section_at_frame (framepos_t frame) const;
const MeterSection& meter_section_at_beat (double beat) const;
TempoSection* next_tempo_section (TempoSection*) const;
/** add a tempo section locked to pls. ignored values will be set in recompute_tempi()
* @param pulse pulse position of new section. ignored if pls == AudioTime
* @param frame frame position of new section. ignored if pls == MusicTime
* @param type type of new tempo section (Ramp, Constant)
*/
TempoSection* add_tempo (const Tempo&, const double& pulse, const framepos_t& frame, TempoSection::Type type, PositionLockStyle pls);
TempoSection* add_tempo (const Tempo&, const double& pulse, const framepos_t& frame, PositionLockStyle pls);
/** add a meter section locked to pls.. ignored values will be set in recompute_meters()
* @param meter the Meter to be added
@ -381,8 +394,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
void remove_tempo (const TempoSection&, bool send_signal);
void remove_meter (const MeterSection&, bool send_signal);
void replace_tempo (TempoSection&, const Tempo&, const double& pulse, const framepos_t& frame
, TempoSection::Type type, PositionLockStyle pls);
void replace_tempo (TempoSection&, const Tempo&, const double& pulse, const framepos_t& frame, PositionLockStyle pls);
void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where, framepos_t frame, PositionLockStyle pls);
@ -407,8 +419,8 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
Metrics::const_iterator metrics_end() { return _metrics.end(); }
void change_existing_tempo_at (framepos_t, double bpm, double note_type);
void change_initial_tempo (double bpm, double note_type);
void change_existing_tempo_at (framepos_t, double bpm, double note_type, double end_ntpm);
void change_initial_tempo (double ntpm, double note_type, double end_ntpm);
void insert_time (framepos_t, framecnt_t);
bool remove_time (framepos_t where, framecnt_t amount); //returns true if anything was moved
@ -488,14 +500,17 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
void gui_set_tempo_position (TempoSection*, const framepos_t& frame, const int& sub_num);
void gui_set_meter_position (MeterSection*, const framepos_t& frame);
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
void gui_stretch_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame);
bool gui_change_tempo (TempoSection*, const Tempo& bpm, bool change_end);
void gui_stretch_tempo (TempoSection* tempo, const framepos_t frame, const framepos_t end_frame);
void gui_stretch_tempo_end (TempoSection* tempo, const framepos_t frame, const framepos_t end_frame);
bool gui_twist_tempi (TempoSection* first, const Tempo& bpm, const framepos_t frame, const framepos_t end_frame);
std::pair<double, framepos_t> predict_tempo_position (TempoSection* section, const Timecode::BBT_Time& bbt);
bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt);
PBD::Signal1<void,const PBD::PropertyChange&> MetricPositionChanged;
void fix_legacy_session();
void fix_legacy_end_session();
private:
@ -573,7 +588,7 @@ private:
void do_insert (MetricSection* section);
TempoSection* add_tempo_locked (const Tempo&, double pulse, double minute
, TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter = false);
, PositionLockStyle pls, bool recompute, bool locked_to_meter = false);
MeterSection* add_meter_locked (const Meter&, double beat, const Timecode::BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute);

View File

@ -1474,7 +1474,7 @@ LuaBindings::common (lua_State* L)
.endClass ()
.beginClass <Tempo> ("Tempo")
.addConstructor <void (*) (double, double)> ()
.addConstructor <void (*) (double, double, double)> ()
.addFunction ("note_type", &Tempo::note_type)
.addFunction ("note_types_per_minute", (double (Tempo::*)() const)&Tempo::note_types_per_minute)
.addFunction ("quarter_notes_per_minute", &Tempo::quarter_notes_per_minute)

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ FrameposPlusBeatsTest::singleTempoTest ()
Meter meter (4, 4);
map.replace_meter (map.first_meter(), meter, BBT_Time (1, 1, 0), 0, AudioTime);
map.replace_tempo (map.first_tempo(), tempo, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempo, 0.0, 0, AudioTime);
/* Add 1 beat to beat 3 of the first bar */
framepos_t r = map.framepos_plus_qn (frames_per_beat * 2, Evoral::Beats(1));
@ -63,9 +63,9 @@ FrameposPlusBeatsTest::doubleTempoTest ()
*/
Tempo tempoA (120, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240, 4.0);
map.add_tempo (tempoB, 12.0 / tempoA.note_type(), 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 12.0 / tempoA.note_type(), 0, MusicTime);
/* Now some tests */
@ -116,9 +116,9 @@ FrameposPlusBeatsTest::doubleTempoWithMeterTest ()
*/
Tempo tempoA (120, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240, 4.0);
map.add_tempo (tempoB, 12.0 / tempoA.note_type(), 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 12.0 / tempoA.note_type(), 0, MusicTime);
Meter meterB (3, 8);
map.add_meter (meterB, 12.0, BBT_Time (4, 1, 0), 0, MusicTime);
@ -173,9 +173,9 @@ FrameposPlusBeatsTest::doubleTempoWithComplexMeterTest ()
*/
Tempo tempoA (120, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240, 4.0);
map.add_tempo (tempoB, 12.0 / 4.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 12.0 / 4.0, 0, MusicTime);
Meter meterB (5, 8);
map.add_meter (meterB, 9.0, BBT_Time (4, 1, 0), 0, MusicTime);
/* Now some tests */

View File

@ -21,7 +21,7 @@ FramewalkToBeatsTest::singleTempoTest ()
Meter meter (4, 4);
map.replace_meter (map.meter_section_at_frame (0), meter, BBT_Time (1, 1, 0), 0, AudioTime);
map.replace_tempo (map.tempo_section_at_frame (0), tempo, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.tempo_section_at_frame (0), tempo, 0.0, 0, AudioTime);
/* Walk 1 beats-worth of frames from beat 3 */
double r = map.framewalk_to_qn (frames_per_beat * 2, frames_per_beat * 1).to_double();
@ -71,9 +71,9 @@ FramewalkToBeatsTest::doubleTempoTest ()
*/
Tempo tempoA (120);
map.replace_tempo (map.tempo_section_at_frame (0), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.tempo_section_at_frame (0), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240);
map.add_tempo (tempoB, 12.0 / tempoB.note_type(), 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 12.0 / tempoB.note_type(), 0, MusicTime);
/* Now some tests */
@ -127,11 +127,11 @@ FramewalkToBeatsTest::tripleTempoTest ()
*/
Tempo tempoA (120, 4.0);
map.replace_tempo (map.tempo_section_at_frame (0), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.tempo_section_at_frame (0), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240, 4.0);
map.add_tempo (tempoB, 4.0 / tempoB.note_type(), 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 4.0 / tempoB.note_type(), 0, MusicTime);
Tempo tempoC (160, 4.0);
map.add_tempo (tempoC, 8.0 / tempoB.note_type(), 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoC, 8.0 / tempoB.note_type(), 0, MusicTime);
/* Walk from 1|3 to 4|1 */
double r = map.framewalk_to_qn (2 * 24e3, (2 * 24e3) + (4 * 12e3) + (4 * 18e3)).to_double();
@ -151,7 +151,7 @@ FramewalkToBeatsTest::singleTempoMeterTest ()
Meter meter (7, 8);
map.replace_meter (map.meter_section_at_frame (0), meter, BBT_Time (1, 1, 0), 0, AudioTime);
map.replace_tempo (map.tempo_section_at_frame (0), tempo, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.tempo_section_at_frame (0), tempo, 0.0, 0, AudioTime);
/* Walk 1 qn beats-worth of frames from beat 3 */
double r = map.framewalk_to_qn (frames_per_beat * 2, frames_per_beat * 1).to_double();

View File

@ -48,7 +48,7 @@ class TestSlaveSessionProxy : public ISlaveSessionProxy {
meter (4.0, 4.0)
{
_tempo_map = new TempoMap (FRAME_RATE);
_tempo_map->add_tempo (tempo, 0.0, 0, TempoSection::Constant, AudioTime);
_tempo_map->add_tempo (tempo, 0.0, 0, AudioTime);
_tempo_map->add_meter (meter, 0.0, Timecode::BBT_Time(1, 1, 0), 0, AudioTime);
}

View File

@ -36,9 +36,9 @@ TempoTest::recomputeMapTest48 ()
*/
Tempo tempoA (120.0, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240.0, 4.0);
map.add_tempo (tempoB, 3.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 3.0, 0, MusicTime);
Meter meterB (3, 4);
map.add_meter (meterB, 12.0, BBT_Time (4, 1, 0), 0, MusicTime);
//map.dump (map._metrics, std::cout);
@ -134,9 +134,9 @@ TempoTest::recomputeMapTest44 ()
*/
Tempo tempoA (120.0, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240.0, 4.0);
map.add_tempo (tempoB, 3.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 3.0, 0, MusicTime);
Meter meterB (3, 4);
map.add_meter (meterB, 12.0, BBT_Time (4, 1, 0), 288e3, MusicTime);
@ -234,21 +234,21 @@ TempoTest::qnDistanceTestConstant ()
*/
Tempo tempoA (120.0, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
/* should have no effect on pulse */
Tempo tempoB (120.0, 4.0);
map.add_tempo (tempoB, 2.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 2.0, 0, MusicTime);
/* equivalent to pulse 3.0 @ 120 bpm*/
Tempo tempoC (240.0, 4.0);
map.add_tempo (tempoC, 0.0, 6 * sampling_rate, TempoSection::Constant, AudioTime);
map.add_tempo (tempoC, 0.0, 6 * sampling_rate, AudioTime);
Tempo tempoD (90.4, 4.0);
map.add_tempo (tempoD, 9.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoD, 9.0, 0, MusicTime);
Tempo tempoE (110.6, 4.0);
map.add_tempo (tempoE, 12.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoE, 12.0, 0, MusicTime);
Tempo tempoF (123.7, 4.0);
map.add_tempo (tempoF, 15.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoF, 15.0, 0, MusicTime);
Tempo tempoG (111.8, 4.0);
map.add_tempo (tempoG, 0.0, (framepos_t) 2 * 60 * sampling_rate, TempoSection::Constant, AudioTime);
map.add_tempo (tempoG, 0.0, (framepos_t) 2 * 60 * sampling_rate, AudioTime);
Meter meterB (3, 4);
map.add_meter (meterB, 12.0, BBT_Time (4, 1, 0), 288e3, MusicTime);
@ -313,23 +313,24 @@ TempoTest::qnDistanceTestRamp ()
*/
Tempo tempoA (120.2, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Ramp, AudioTime);
Tempo tempoB (240.5, 4.0);
map.add_tempo (tempoB, 3.0, 0, TempoSection::Ramp, MusicTime);
Tempo tempoA (120.2, 4.0, 240.5);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
Tempo tempoB (240.5, 4.0, 130.1);
map.add_tempo (tempoB, 3.0, 0, MusicTime);
Tempo tempoC (130.1, 4.0);
map.add_tempo (tempoC, 0.0, 6 * sampling_rate, TempoSection::Ramp, AudioTime);
Tempo tempoD (90.3, 4.0);
map.add_tempo (tempoD, 9.0, 0, TempoSection::Ramp, MusicTime);
Tempo tempoE (110.7, 4.0);
map.add_tempo (tempoE, 12.0, 0, TempoSection::Ramp, MusicTime);
Tempo tempoF (123.9, 4.0);
map.add_tempo (tempoF, 15.0, 0, TempoSection::Ramp, MusicTime);
Tempo tempoC (130.1, 4.0, 90.3);
map.add_tempo (tempoC, 0.0, 6 * sampling_rate, AudioTime);
Tempo tempoD (90.3, 4.0, 110.7);
map.add_tempo (tempoD, 9.0, 0, MusicTime);
Tempo tempoE (110.7, 4.0, 123.9);
map.add_tempo (tempoE, 12.0, 0, MusicTime);
Tempo tempoF (123.9, 4.0, 111.8);
map.add_tempo (tempoF, 15.0, 0, MusicTime);
Tempo tempoG (111.8, 4.0);
map.add_tempo (tempoG, 0.0, (framepos_t) 2 * 60 * sampling_rate, TempoSection::Ramp, AudioTime);
map.add_tempo (tempoG, 0.0, (framepos_t) 2 * 60 * sampling_rate, AudioTime);
Meter meterB (3, 4);
map.add_meter (meterB, 4.0, BBT_Time (2, 1, 0), 288e3, AudioTime);
map.dump (std::cout);
map.recompute_map (map._metrics, 1);
list<MetricSection*>::iterator i = map._metrics.begin();
@ -367,10 +368,10 @@ TempoTest::rampTest48 ()
TempoMap map (sampling_rate);
Meter meterA (4, 4);
Tempo tempoA (77.0, 4.0);
Tempo tempoA (77.0, 4.0, 217.0);
Tempo tempoB (217.0, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Ramp, AudioTime);
map.add_tempo (tempoB, 0.0, (framepos_t) 60 * sampling_rate, TempoSection::Ramp, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
map.add_tempo (tempoB, 0.0, (framepos_t) 60 * sampling_rate, AudioTime);
map.replace_meter (map.first_meter(), meterA, BBT_Time (1, 1, 0), 0, AudioTime);
/*
@ -429,10 +430,10 @@ TempoTest::rampTest44 ()
TempoMap map (sampling_rate);
Meter meterA (4, 4);
Tempo tempoA (77.0, 4.0);
Tempo tempoA (77.0, 4.0, 217.0);
Tempo tempoB (217.0, 4.0);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Ramp, AudioTime);
map.add_tempo (tempoB, 0.0, (framepos_t) 60 * sampling_rate, TempoSection::Ramp, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
map.add_tempo (tempoB, 0.0, (framepos_t) 60 * sampling_rate, AudioTime);
map.replace_meter (map.first_meter(), meterA, BBT_Time (1, 1, 0), 0, AudioTime);
/*
@ -491,15 +492,15 @@ TempoTest::tempoAtPulseTest ()
TempoMap map (sampling_rate);
Meter meterA (4, 8);
Tempo tempoA (80.0, 8.0);
Tempo tempoB (160.0, 3.0);
Tempo tempoA (80.0, 8.0, 160.0);
Tempo tempoB (160.0, 3.0, 123.0);
Tempo tempoC (123.0, 4.0);
map.replace_meter (map.first_meter(), meterA, BBT_Time (1, 1, 0), 0, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Ramp, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
map.add_tempo (tempoB, 20.0, 0, TempoSection::Ramp, MusicTime);
map.add_tempo (tempoC, 30.0, 0, TempoSection::Ramp, MusicTime);
map.add_tempo (tempoB, 20.0, 0, MusicTime);
map.add_tempo (tempoC, 30.0, 0, MusicTime);
TempoSection* tA = 0;
TempoSection* tB = 0;
@ -569,13 +570,13 @@ TempoTest::tempoFundamentalsTest ()
Tempo tempoE (123.0, 3.0);
map.replace_meter (map.first_meter(), meterA, BBT_Time (1, 1, 0), 0, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, TempoSection::Constant, AudioTime);
map.replace_tempo (map.first_tempo(), tempoA, 0.0, 0, AudioTime);
map.add_tempo (tempoB, 20.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoC, 30.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoB, 20.0, 0, MusicTime);
map.add_tempo (tempoC, 30.0, 0, MusicTime);
map.add_tempo (tempoD, 40.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoE, 50.0, 0, TempoSection::Constant, MusicTime);
map.add_tempo (tempoD, 40.0, 0, MusicTime);
map.add_tempo (tempoE, 50.0, 0, MusicTime);
TempoSection* tA = 0;
TempoSection* tB = 0;