summaryrefslogtreecommitdiff
path: root/gtk2_ardour/ardour_ui.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gtk2_ardour/ardour_ui.cc')
-rw-r--r--gtk2_ardour/ardour_ui.cc481
1 files changed, 253 insertions, 228 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index 33f5a5099e..307eb925b3 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -62,9 +62,8 @@
#include "gtkmm2ext/popup.h"
#include "gtkmm2ext/window_title.h"
-#include "midi++/manager.h"
-
#include "ardour/ardour.h"
+#include "ardour/audio_backend.h"
#include "ardour/audioengine.h"
#include "ardour/audiofilesource.h"
#include "ardour/automation_watch.h"
@@ -162,10 +161,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
/* start of private members */
, _startup (0)
- , engine (0)
, nsm (0)
, _was_dirty (false)
, _mixer_on_top (false)
+ , first_time_engine_run (true)
/* transport */
@@ -207,7 +206,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
, _status_bar_visibility (X_("status-bar"))
, _feedback_exists (false)
-
+ , _audio_midi_setup (0)
{
Gtkmm2ext::init(localedir);
@@ -218,12 +217,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
}
ui_config = new UIConfiguration();
+ _audio_midi_setup = new EngineControl;
editor = 0;
mixer = 0;
meterbridge = 0;
editor = 0;
- engine = 0;
_session_is_new = false;
session_selector_window = 0;
last_key_press_time = 0;
@@ -271,6 +270,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
+ /* handle Audio/MIDI setup when session requires it */
+
+ ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
+
/* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
@@ -369,6 +372,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
_process_thread->init ();
DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
+
+ attach_to_engine ();
}
GlobalPortMatrixWindow*
@@ -380,42 +385,146 @@ ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
return new GlobalPortMatrixWindow (_session, type);
}
-int
-ARDOUR_UI::create_engine ()
+void
+ARDOUR_UI::attach_to_engine ()
{
- // this gets called every time by new_session()
+ AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
+ AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
+ AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
- if (engine) {
- return 0;
+ AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
+
+ ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
+
+ /* if there is only one audio/midi backend, and it does not require setup, get our use of it underway
+ * right here (we need to know the client name and potential session ID
+ * to do this, which is why this is here, rather than in, say,
+ * ARDOUR::init().
+ */
+
+ if (!AudioEngine::instance()->setup_required()) {
+ const AudioBackendInfo* backend = AudioEngine::instance()->available_backends().front();
+ AudioEngine::instance()->set_backend (backend->name, ARDOUR_COMMAND_LINE::backend_client_name, ARDOUR_COMMAND_LINE::backend_session_uuid);
+ AudioEngine::instance()->start ();
}
+}
- loading_message (_("Starting audio engine"));
+void
+ARDOUR_UI::engine_stopped ()
+{
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
+ ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
+ ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
+}
- try {
- engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
+void
+ARDOUR_UI::engine_running ()
+{
+ if (first_time_engine_run) {
+ post_engine();
+ first_time_engine_run = false;
+ }
+
+ ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
+ ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
- } catch (...) {
+ Glib::RefPtr<Action> action;
+ const char* action_name = 0;
- return -1;
+ switch (AudioEngine::instance()->samples_per_cycle()) {
+ case 32:
+ action_name = X_("JACKLatency32");
+ break;
+ case 64:
+ action_name = X_("JACKLatency64");
+ break;
+ case 128:
+ action_name = X_("JACKLatency128");
+ break;
+ case 512:
+ action_name = X_("JACKLatency512");
+ break;
+ case 1024:
+ action_name = X_("JACKLatency1024");
+ break;
+ case 2048:
+ action_name = X_("JACKLatency2048");
+ break;
+ case 4096:
+ action_name = X_("JACKLatency4096");
+ break;
+ case 8192:
+ action_name = X_("JACKLatency8192");
+ break;
+ default:
+ /* XXX can we do anything useful ? */
+ break;
}
- engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
- engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
- engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
+ if (action_name) {
- engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
+ action = ActionManager::get_action (X_("JACK"), action_name);
- ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
+ if (action) {
+ Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
+ ract->set_active ();
+ }
- post_engine ();
+ update_disk_space ();
+ update_cpu_load ();
+ update_sample_rate (AudioEngine::instance()->sample_rate());
+ update_timecode_format ();
+ }
+}
- return 0;
+void
+ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
+{
+ if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
+ /* we can't rely on the original string continuing to exist when we are called
+ again in the GUI thread, so make a copy and note that we need to
+ free it later.
+ */
+ char *copy = strdup (reason);
+ Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
+ return;
+ }
+
+ ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
+ ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
+
+ update_sample_rate (0);
+
+ string msgstr;
+
+ /* if the reason is a non-empty string, it means that the backend was shutdown
+ rather than just Ardour.
+ */
+
+ if (strlen (reason)) {
+ msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
+ } else {
+ msgstr = string_compose (_("\
+JACK has either been shutdown or it\n\
+disconnected %1 because %1\n\
+was not fast enough. Try to restart\n\
+JACK, reconnect and save the session."), PROGRAM_NAME);
+ }
+
+ MessageDialog msg (*editor, msgstr);
+ pop_back_splash (msg);
+ msg.set_keep_above (true);
+ msg.run ();
+
+ if (free_reason) {
+ free (const_cast<char*> (reason));
+ }
}
void
ARDOUR_UI::post_engine ()
{
- /* Things to be done once we create the AudioEngine
+ /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
*/
ARDOUR::init_post_engine ();
@@ -481,25 +590,9 @@ ARDOUR_UI::post_engine ()
Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
#endif
- update_disk_space ();
- update_cpu_load ();
- update_sample_rate (engine->frame_rate());
- update_timecode_format ();
-
Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
Config->map_parameters (pc);
-
- /* now start and maybe save state */
-
- if (do_engine_start () == 0) {
- if (_session && _session_is_new) {
- /* we need to retain initial visual
- settings for a new session
- */
- _session->save_state ("");
- }
- }
}
ARDOUR_UI::~ARDOUR_UI ()
@@ -685,6 +778,7 @@ ARDOUR_UI::startup ()
{
Application* app = Application::instance ();
char *nsm_url;
+
app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
@@ -779,7 +873,7 @@ ARDOUR_UI::check_memory_locking ()
XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
- if (engine->is_realtime() && memory_warning_node == 0) {
+ if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
struct rlimit limits;
int64_t ram;
@@ -919,7 +1013,8 @@ If you still wish to quit, please use the\n\n\
_session = 0;
}
- engine->stop (true);
+ halt_connection.disconnect ();
+ AudioEngine::instance()->stop ();
quit ();
}
@@ -1048,22 +1143,28 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
- if (!engine->connected()) {
+ if (!AudioEngine::instance()->connected()) {
- snprintf (buf, sizeof (buf), "%s", _("disconnected"));
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
} else {
- framecnt_t rate = engine->frame_rate();
+ framecnt_t rate = AudioEngine::instance()->sample_rate();
- if (fmod (rate, 1000.0) != 0.0) {
- snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
- (float) rate/1000.0f,
- (engine->frames_per_cycle() / (float) rate) * 1000.0f);
+ if (rate == 0) {
+ /* no sample rate available */
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
} else {
- snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
- rate/1000,
- (engine->frames_per_cycle() / (float) rate) * 1000.0f);
+
+ if (fmod (rate, 1000.0) != 0.0) {
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
+ (float) rate / 1000.0f,
+ (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
+ } else {
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
+ rate/1000,
+ (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
+ }
}
}
@@ -1133,7 +1234,7 @@ ARDOUR_UI::update_cpu_load ()
should also be changed.
*/
- float const c = engine->get_cpu_load ();
+ float const c = AudioEngine::instance()->get_cpu_load ();
snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
cpu_load_label.set_markup (buf);
}
@@ -1187,6 +1288,11 @@ ARDOUR_UI::update_disk_space()
char buf[64];
framecnt_t fr = _session->frame_rate();
+ if (fr == 0) {
+ /* skip update - no SR available */
+ return;
+ }
+
if (!opt_frames) {
/* Available space is unknown */
snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
@@ -1449,20 +1555,16 @@ ARDOUR_UI::open_recent_session ()
bool
ARDOUR_UI::check_audioengine ()
{
- if (engine) {
- if (!engine->connected()) {
- MessageDialog msg (string_compose (
- _("%1 is not connected to JACK\n"
- "You cannot open or close sessions in this condition"),
- PROGRAM_NAME));
- pop_back_splash (msg);
- msg.run ();
- return false;
- }
- return true;
- } else {
+ if (!AudioEngine::instance()->connected()) {
+ MessageDialog msg (string_compose (
+ _("%1 is not connected to any audio backend.\n"
+ "You cannot open or close sessions in this condition"),
+ PROGRAM_NAME));
+ pop_back_splash (msg);
+ msg.run ();
return false;
}
+ return true;
}
void
@@ -1668,10 +1770,17 @@ ARDOUR_UI::transport_goto_wallclock ()
time (&now);
localtime_r (&now, &tmnow);
+
+ int frame_rate = _session->frame_rate();
+
+ if (frame_rate == 0) {
+ /* no frame rate available */
+ return;
+ }
- frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
- frames += tmnow.tm_min * (60 * _session->frame_rate());
- frames += tmnow.tm_sec * _session->frame_rate();
+ frames = tmnow.tm_hour * (60 * 60 * frame_rate);
+ frames += tmnow.tm_min * (60 * frame_rate);
+ frames += tmnow.tm_sec * frame_rate;
_session->request_locate (frames, _session->transport_rolling ());
@@ -2032,127 +2141,6 @@ ARDOUR_UI::map_transport_state ()
}
void
-ARDOUR_UI::engine_stopped ()
-{
- ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
- ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
- ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
-}
-
-void
-ARDOUR_UI::engine_running ()
-{
- ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
- ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
- ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
-
- Glib::RefPtr<Action> action;
- const char* action_name = 0;
-
- switch (engine->frames_per_cycle()) {
- case 32:
- action_name = X_("JACKLatency32");
- break;
- case 64:
- action_name = X_("JACKLatency64");
- break;
- case 128:
- action_name = X_("JACKLatency128");
- break;
- case 512:
- action_name = X_("JACKLatency512");
- break;
- case 1024:
- action_name = X_("JACKLatency1024");
- break;
- case 2048:
- action_name = X_("JACKLatency2048");
- break;
- case 4096:
- action_name = X_("JACKLatency4096");
- break;
- case 8192:
- action_name = X_("JACKLatency8192");
- break;
- default:
- /* XXX can we do anything useful ? */
- break;
- }
-
- if (action_name) {
-
- action = ActionManager::get_action (X_("JACK"), action_name);
-
- if (action) {
- Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
- ract->set_active ();
- }
- }
-}
-
-void
-ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
-{
- if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
- /* we can't rely on the original string continuing to exist when we are called
- again in the GUI thread, so make a copy and note that we need to
- free it later.
- */
- char *copy = strdup (reason);
- Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
- return;
- }
-
- ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
- ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
-
- update_sample_rate (0);
-
- string msgstr;
-
- /* if the reason is a non-empty string, it means that the backend was shutdown
- rather than just Ardour.
- */
-
- if (strlen (reason)) {
- msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
- } else {
- msgstr = string_compose (_("\
-JACK has either been shutdown or it\n\
-disconnected %1 because %1\n\
-was not fast enough. Try to restart\n\
-JACK, reconnect and save the session."), PROGRAM_NAME);
- }
-
- MessageDialog msg (*editor, msgstr);
- pop_back_splash (msg);
- msg.set_keep_above (true);
- msg.run ();
-
- if (free_reason) {
- free (const_cast<char*> (reason));
- }
-}
-
-int32_t
-ARDOUR_UI::do_engine_start ()
-{
- try {
- engine->start();
- }
-
- catch (...) {
- engine->stop ();
- error << _("Unable to start the session running")
- << endmsg;
- unload_session ();
- return -2;
- }
-
- return 0;
-}
-
-void
ARDOUR_UI::update_clocks ()
{
if (!editor || !editor->dragging_playhead()) {
@@ -2702,10 +2690,6 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
}
}
- if (create_engine ()) {
- break;
- }
-
if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
if (likely_new && !nsm) {
@@ -2801,25 +2785,23 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
int unload_status;
int retval = -1;
- session_loaded = false;
-
- if (!check_audioengine()) {
- return -2;
+ if (_session) {
+ unload_status = unload_session ();
+
+ if (unload_status < 0) {
+ goto out;
+ } else if (unload_status > 0) {
+ retval = 0;
+ goto out;
+ }
}
- unload_status = unload_session ();
-
- if (unload_status < 0) {
- goto out;
- } else if (unload_status > 0) {
- retval = 0;
- goto out;
- }
+ session_loaded = false;
loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
try {
- new_session = new Session (*engine, path, snap_name, 0, mix_template);
+ new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
}
/* this one is special */
@@ -2920,12 +2902,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
Session *new_session;
int x;
- if (!check_audioengine()) {
- return -1;
- }
-
session_loaded = false;
-
x = unload_session ();
if (x < 0) {
@@ -2937,7 +2914,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
_session_is_new = true;
try {
- new_session = new Session (*engine, path, snap_name, &bus_profile);
+ new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
}
catch (...) {
@@ -3832,31 +3809,33 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual
return 1;
}
-
void
-ARDOUR_UI::disconnect_from_jack ()
+ARDOUR_UI::disconnect_from_engine ()
{
- if (engine) {
- if (engine->disconnect_from_jack ()) {
- MessageDialog msg (*editor, _("Could not disconnect from JACK"));
- msg.run ();
- }
-
- update_sample_rate (0);
+ /* drop connection to AudioEngine::Halted so that we don't act
+ * as if the engine unexpectedly shut down
+ */
+ halt_connection.disconnect ();
+
+ if (AudioEngine::instance()->stop ()) {
+ MessageDialog msg (*editor, _("Could not disconnect from JACK"));
+ msg.run ();
+ } else {
+ AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
}
+
+ update_sample_rate (0);
}
void
-ARDOUR_UI::reconnect_to_jack ()
+ARDOUR_UI::reconnect_to_engine ()
{
- if (engine) {
- if (engine->reconnect_to_jack ()) {
- MessageDialog msg (*editor, _("Could not reconnect to JACK"));
- msg.run ();
- }
-
- update_sample_rate (0);
+ if (AudioEngine::instance()->start ()) {
+ MessageDialog msg (*editor, _("Could not reconnect to JACK"));
+ msg.run ();
}
+
+ update_sample_rate (0);
}
void
@@ -4163,3 +4142,49 @@ ARDOUR_UI::reset_route_peak_display (Route* route)
reset_peak_display ();
}
}
+
+void
+ARDOUR_UI::toggle_audio_midi_setup ()
+{
+ Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-audio-midi-setup"));
+ if (!act) {
+ return;
+ }
+
+ Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
+
+ if (tact->get_active()) {
+ launch_audio_midi_setup ();
+ } else {
+ _audio_midi_setup->hide ();
+ }
+}
+
+void
+ARDOUR_UI::launch_audio_midi_setup ()
+{
+ if (!_audio_midi_setup) {
+ _audio_midi_setup = new EngineControl ();
+ }
+
+ _audio_midi_setup->present ();
+}
+
+int
+ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
+{
+ launch_audio_midi_setup ();
+
+ _audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
+
+ int r = _audio_midi_setup->run ();
+
+ switch (r) {
+ case Gtk::RESPONSE_OK:
+ return 0;
+ case Gtk::RESPONSE_APPLY:
+ return 0;
+ default:
+ return -1;
+ }
+}