lots of deep but hard to spot changes to transport control, primarily relating to looping and transitions between loop, play-range and regular roll/stop ; add GUI option for seamless looping control (under Options). Needs to be forward ported to 3.0. Please TEST THE HELL out of this one - changes were deeper and wider than i would like, but did consolidate some of the GUI transport control code in a good way

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@5976 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-10-30 02:52:55 +00:00
parent 2442aa577a
commit 69ac5b3c33
15 changed files with 203 additions and 182 deletions

View File

@ -41,6 +41,7 @@
<Option name="default-narrow_ms" value="0"/>
<Option name="smpte-format" value="6"/>
<Option name="font-scale" value="102400"/>
<Option name="seamless-loop" value="1"/>
</Config>
<extra>
<RulerVisibility smpte="yes" bbt="yes" frames="no" minsec="no" tempo="yes" meter="yes" marker="yes" rangemarker="no" transportmarker="yes" cdmarker="no"/>

View File

@ -549,6 +549,7 @@
</menu>
</menu>
<menu action='MiscOptions'>
<menuitem action='toggle-seamless-loop'/>
<menuitem action='UseOSC'/>
<menuitem action='NewPluginsActive'/>
<menuitem action='LatchedRecordEnable'/>

View File

@ -1449,35 +1449,102 @@ ARDOUR_UI::transport_record (bool roll)
//cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
}
void
void
ARDOUR_UI::transport_roll ()
{
bool rolling;
if (!session) {
return;
}
rolling = session->transport_rolling ();
//cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
if (session->get_play_loop()) {
// session->request_play_loop (false);
auto_loop_button.set_visual_state (1);
roll_button.set_visual_state (1);
} else if (session->get_play_range ()) {
session->request_play_range (false);
play_selection_button.set_visual_state (0);
} else if (rolling) {
session->request_locate (session->last_transport_start(), true);
if (session->is_auditioning()) {
return;
}
switch (Config->get_slave_source()) {
case None:
case JACK:
break;
default:
/* transport controlled by the master */
return;
}
session->request_transport_speed (1.0f);
bool rolling = session->transport_rolling();
bool relocate = true;
if (session->get_play_loop()) {
session->request_play_loop (false, true);
relocate = false;
} else if (session->get_play_range ()) {
session->request_play_range (false, true);
relocate = false;
}
if (rolling) {
if (relocate) {
session->request_locate (session->last_transport_start(), true);
}
} else {
session->request_transport_speed (1.0f);
}
map_transport_state ();
}
void
ARDOUR_UI::transport_loop()
ARDOUR_UI::toggle_roll (bool with_abort)
{
if (!session) {
return;
}
if (session->is_auditioning()) {
session->cancel_audition ();
return;
}
switch (Config->get_slave_source()) {
case None:
case JACK:
break;
default:
/* transport controlled by the master */
return;
}
bool rolling = session->transport_rolling();
bool affect_transport = true;
if (rolling) {
/* drop out of loop/range playback but leave transport rolling */
if (session->get_play_loop()) {
affect_transport = false;
session->request_play_loop (false, true);
} else if (session->get_play_range ()) {
affect_transport = false;
session->request_play_range (false, true);
}
}
if (affect_transport) {
if (rolling) {
session->request_locate (session->last_transport_start(), true);
}
if (rolling) {
session->request_stop (with_abort);
} else {
session->request_transport_speed (1.0f);
}
}
map_transport_state ();
}
void
ARDOUR_UI::toggle_session_auto_loop ()
{
if (session) {
if (session->get_play_loop()) {
@ -1486,10 +1553,14 @@ ARDOUR_UI::transport_loop()
if (looploc) {
session->request_locate (looploc->start(), true);
}
} else {
session->request_play_loop (false);
}
} else {
Location * looploc = session->locations()->auto_loop_location();
if (looploc) {
session->request_play_loop (true);
}
}
else {
session->request_play_loop (true);
}
}
}
@ -1501,10 +1572,6 @@ ARDOUR_UI::transport_play_selection ()
return;
}
if (!session->get_play_range()) {
session->request_stop ();
}
editor->play_selection ();
}
@ -1593,17 +1660,56 @@ ARDOUR_UI::queue_transport_change ()
void
ARDOUR_UI::map_transport_state ()
{
if (!session) {
auto_loop_button.set_visual_state (0);
play_selection_button.set_visual_state (0);
roll_button.set_visual_state (0);
stop_button.set_visual_state (1);
return;
}
float sp = session->transport_speed();
if (sp == 1.0f) {
transport_rolling ();
} else if (sp < 0.0f) {
transport_rewinding ();
} else if (sp > 0.0f) {
transport_forwarding ();
} else {
transport_stopped ();
shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
shuttle_box.queue_draw ();
} else if (sp == 0.0f) {
shuttle_fract = 0;
shuttle_box.queue_draw ();
update_disk_space ();
}
if (sp != 0.0) {
if (session->get_play_range()) {
play_selection_button.set_visual_state (1);
roll_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
} else if (session->get_play_loop ()) {
auto_loop_button.set_visual_state (1);
play_selection_button.set_visual_state (0);
roll_button.set_visual_state (0);
} else {
roll_button.set_visual_state (1);
play_selection_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
}
stop_button.set_visual_state (0);
} else {
stop_button.set_visual_state (1);
roll_button.set_visual_state (0);
play_selection_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
}
}
void

View File

@ -578,11 +578,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
void transport_forward (int option);
void transport_rewind (int option);
void transport_loop ();
void transport_rolling ();
void transport_rewinding ();
void transport_forwarding ();
void transport_stopped ();
void toggle_roll (bool with_abort);
bool _session_is_new;
void connect_to_session (ARDOUR::Session *);
@ -714,6 +710,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
void set_remote_model (ARDOUR::RemoteModel);
void set_denormal_model (ARDOUR::DenormalModel);
void toggle_seamless_loop ();
void toggle_sync_order_keys ();
void toggle_new_plugins_active();
void toggle_StopPluginsWithTransport();

View File

@ -125,66 +125,6 @@ ARDOUR_UI::display_message (const char *prefix, gint prefix_len, RefPtr<TextBuff
#endif
}
void
ARDOUR_UI::transport_stopped ()
{
stop_button.set_visual_state (1);
roll_button.set_visual_state (0);
play_selection_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
shuttle_fract = 0;
shuttle_box.queue_draw ();
update_disk_space ();
}
void
ARDOUR_UI::transport_rolling ()
{
stop_button.set_visual_state (0);
if (session->get_play_range()) {
play_selection_button.set_visual_state (1);
roll_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
} else if (session->get_play_loop ()) {
auto_loop_button.set_visual_state (1);
play_selection_button.set_visual_state (0);
roll_button.set_visual_state (0);
} else {
roll_button.set_visual_state (1);
play_selection_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
}
/* reset shuttle controller */
shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
shuttle_box.queue_draw ();
}
void
ARDOUR_UI::transport_rewinding ()
{
stop_button.set_visual_state (0);
roll_button.set_visual_state (1);
play_selection_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
}
void
ARDOUR_UI::transport_forwarding ()
{
stop_button.set_visual_state (0);
roll_button.set_visual_state (1);
play_selection_button.set_visual_state (0);
auto_loop_button.set_visual_state (0);
}
void
ARDOUR_UI::setup_transport ()
{

View File

@ -156,7 +156,7 @@ ARDOUR_UI::connect_to_session (Session *s)
start_clocking ();
start_blinking ();
transport_stopped ();
map_transport_state ();
second_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::every_second), 1000);
point_one_second_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);

View File

@ -249,10 +249,10 @@ ARDOUR_UI::install_actions ()
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
ActionManager::register_action (transport_actions, X_("ToggleRoll"), _("Start/Stop"), bind (mem_fun (*editor, &PublicEditor::toggle_playback), false));
ActionManager::register_action (transport_actions, X_("ToggleRoll"), _("Start/Stop"), bind (mem_fun (*this, &ARDOUR_UI::toggle_roll), false));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
ActionManager::register_action (transport_actions, X_("ToggleRollForgetCapture"), _("Stop + Forget Capture"), bind (mem_fun(*editor, &PublicEditor::toggle_playback), true));
ActionManager::register_action (transport_actions, X_("ToggleRollForgetCapture"), _("Stop + Forget Capture"), bind (mem_fun(*this, &ARDOUR_UI::toggle_roll), true));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
@ -445,6 +445,8 @@ ARDOUR_UI::install_actions ()
act = ActionManager::register_toggle_action (option_actions, X_("SendMIDIfeedback"), _("Send MIDI feedback"), mem_fun (*this, &ARDOUR_UI::toggle_send_midi_feedback));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_toggle_action (option_actions, X_("toggle-seamless-loop"), _("Seamless Looping"), mem_fun (*this, &ARDOUR_UI::toggle_seamless_loop));
act = ActionManager::register_toggle_action (option_actions, X_("UseOSC"), _("Use OSC"), mem_fun (*this, &ARDOUR_UI::toggle_use_osc));
#ifndef HAVE_LIBLO
act->set_sensitive (false);

View File

@ -70,6 +70,12 @@ ARDOUR_UI::toggle_use_osc ()
ActionManager::toggle_config_state ("options", "UseOSC", &Configuration::set_use_osc, &Configuration::get_use_osc);
}
void
ARDOUR_UI::toggle_seamless_loop ()
{
ActionManager::toggle_config_state ("options", "toggle-seamless-loop", &Configuration::set_seamless_loop, &Configuration::get_seamless_loop);
}
void
ARDOUR_UI::toggle_send_midi_feedback ()
{
@ -371,22 +377,6 @@ ARDOUR_UI::toggle_click ()
ActionManager::toggle_config_state ("Transport", "ToggleClick", &Configuration::set_clicking, &Configuration::get_clicking);
}
void
ARDOUR_UI::toggle_session_auto_loop ()
{
if (session) {
if (session->get_play_loop()) {
if (session->transport_rolling()) {
transport_roll();
} else {
session->request_play_loop (false);
}
} else {
session->request_play_loop (true);
}
}
}
void
ARDOUR_UI::unset_dual_punch ()
{
@ -1170,6 +1160,9 @@ ARDOUR_UI::parameter_changed (const char* parameter_name)
ActionManager::map_some_state ("options", "UseOSC", &Configuration::get_use_osc);
} else if (PARAM_IS ("seamless-loop")) {
ActionManager::map_some_state ("options", "toggle-seamless-loop", &Configuration::get_seamless_loop);
} else if (PARAM_IS ("mmc-control")) {
ActionManager::map_some_state ("options", "UseMMC", &Configuration::get_mmc_control);

View File

@ -194,7 +194,6 @@ class Editor : public PublicEditor
void separate_region_from_punch ();
void separate_region_from_loop ();
void separate_regions_using_location (ARDOUR::Location&);
void toggle_playback (bool with_abort);
void transition_to_rolling (bool forward);
/* undo related */

View File

@ -2385,34 +2385,6 @@ Editor::transition_to_rolling (bool fwd)
session->request_transport_speed (fwd ? 1.0f : -1.0f);
}
void
Editor::toggle_playback (bool with_abort)
{
if (!session) {
return;
}
switch (Config->get_slave_source()) {
case None:
case JACK:
break;
default:
/* transport controlled by the master */
return;
}
if (session->is_auditioning()) {
session->cancel_audition ();
return;
}
if (session->transport_rolling()) {
session->request_stop (with_abort);
} else {
session->request_transport_speed (1.0f);
}
}
void
Editor::play_from_start ()
{

View File

@ -109,7 +109,6 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
virtual bool show_waveforms_recording() const = 0;
virtual void new_region_from_selection () = 0;
virtual void separate_region_from_selection () = 0;
virtual void toggle_playback (bool with_abort) = 0;
virtual void transition_to_rolling (bool fwd) = 0;
virtual nframes64_t unit_to_frame (double unit) const = 0;
// XXX remove me when libardour goes nframes64_t

View File

@ -155,8 +155,8 @@ class Session : public PBD::StatefulDestructible
Type type;
Action action;
nframes_t action_frame;
nframes_t target_frame;
nframes_t action_frame;
nframes_t target_frame;
float speed;
union {
@ -374,7 +374,7 @@ class Session : public PBD::StatefulDestructible
void request_stop (bool abort = false);
void request_locate (nframes_t frame, bool with_roll = false);
void request_play_loop (bool yn);
void request_play_loop (bool yn, bool leave_rolling = false);
bool get_play_loop () const { return play_loop; }
nframes_t last_transport_start() const { return _last_roll_location; }
@ -926,7 +926,7 @@ class Session : public PBD::StatefulDestructible
void set_audio_range (list<AudioRange>&);
void set_music_range (list<MusicRange>&);
void request_play_range (bool yn);
void request_play_range (bool yn, bool leave_rolling = false);
bool get_play_range () const { return _play_range; }
/* favorite dirs */
@ -1453,7 +1453,7 @@ class Session : public PBD::StatefulDestructible
void change_midi_ports ();
int use_config_midi_ports ();
void set_play_loop (bool yn);
void set_play_loop (bool yn, bool leave_rolling);
void overwrite_some_buffers (Diskstream*);
void flush_all_redirects ();
int micro_locate (nframes_t distance);
@ -1735,7 +1735,7 @@ class Session : public PBD::StatefulDestructible
list<AudioRange> current_audio_range;
bool _play_range;
void set_play_range (bool yn);
void set_play_range (bool yn, bool leave_rolling);
void setup_auto_play ();
/* main outs */

View File

@ -2720,7 +2720,7 @@ IO::build_legal_port_name (bool in)
{
const int name_size = jack_port_name_size();
int limit;
char* suffix;
const char* suffix;
int maxports;
/* note that if "in" or "out" are translated it will break a session

View File

@ -317,7 +317,7 @@ Session::process_event (Event* ev)
switch (ev->type) {
case Event::SetLoop:
set_play_loop (ev->yes_or_no);
set_play_loop (ev->yes_or_no, (ev->speed == 1.0f));
break;
case Event::AutoLoop:
@ -432,7 +432,7 @@ Session::process_event (Event* ev)
break;
case Event::SetPlayRange:
set_play_range (ev->yes_or_no);
set_play_range (ev->yes_or_no, (ev->speed == 1.0f));
break;
default:

View File

@ -66,9 +66,8 @@ Session::request_slave_source (SlaveSource src)
if (src == JACK) {
/* could set_seamless_loop() be disposed of entirely?*/
Config->set_seamless_loop (false);
} else {
Config->set_seamless_loop (true);
}
}
ev->slave = src;
queue_event (ev);
}
@ -110,7 +109,7 @@ Session::force_locate (nframes_t target_frame, bool with_roll)
}
void
Session::request_play_loop (bool yn)
Session::request_play_loop (bool yn, bool leave_rolling)
{
Event* ev;
Location *location = _locations.auto_loop_location();
@ -121,14 +120,14 @@ Session::request_play_loop (bool yn)
return;
}
ev = new Event (Event::SetLoop, Event::Add, Event::Immediate, 0, 0.0, yn);
ev = new Event (Event::SetLoop, Event::Add, Event::Immediate, 0, (leave_rolling ? 1.0 : 0.0), yn);
queue_event (ev);
if (!yn && Config->get_seamless_loop() && transport_rolling()) {
if (!leave_rolling && !yn && Config->get_seamless_loop() && transport_rolling()) {
// request an immediate locate to refresh the diskstreams
// after disabling looping
request_locate (_transport_frame-1, false);
}
}
}
void
@ -535,31 +534,35 @@ Session::check_declick_out ()
}
void
Session::set_play_loop (bool yn)
Session::set_play_loop (bool yn, bool leave_rolling)
{
/* Called from event-handling context */
Location *loc;
if (yn == play_loop) {
return;
}
if ((actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
return;
}
set_dirty();
if (yn && Config->get_seamless_loop() && synced_to_jack()) {
warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n"
"Recommend changing the configured options")
<< endmsg;
return;
}
if ((play_loop = yn)) {
if (loc) {
set_play_range (false, true);
if (Config->get_seamless_loop()) {
// set all diskstreams to use internal looping
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
@ -602,6 +605,8 @@ Session::set_play_loop (bool yn)
}
}
TransportStateChange ();
}
void
@ -755,7 +760,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
// cancel looping directly, this is called from event handling context
set_play_loop (false);
set_play_loop (false, false);
}
else if (al && _transport_frame == al->start()) {
if (with_loop) {
@ -1124,27 +1129,33 @@ Session::set_audio_range (list<AudioRange>& range)
}
void
Session::request_play_range (bool yn)
Session::request_play_range (bool yn, bool leave_rolling)
{
Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, 0.0f, yn);
Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, (leave_rolling ? 1.0 : 0.0), yn);
queue_event (ev);
}
void
Session::set_play_range (bool yn)
Session::set_play_range (bool yn, bool leave_rolling)
{
/* Called from event-processing context */
if (_play_range != yn) {
_play_range = yn;
setup_auto_play ();
if (!_play_range) {
/* stop transport */
Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
merge_event (ev);
}
if (yn) {
/* cancel loop play */
set_play_loop (false, true);
}
_play_range = yn;
setup_auto_play ();
if (!_play_range && !leave_rolling) {
/* stop transport */
Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
merge_event (ev);
}
TransportStateChange ();
}
void
@ -1196,7 +1207,7 @@ Session::setup_auto_play ()
}
} else if (sz == 1) {
ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f);
merge_event (ev);