2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , lm_measure_label (_("Measure"))
91 , lm_use_button (_("Use results"))
92 , lm_back_button (_("Back to settings ... (ignore results)"))
93 , lm_button_audio (_("Calibrate Audio"))
95 , have_lm_results (false)
97 , midi_back_button (_("Back to settings"))
99 , _desired_sample_rate (0)
100 , started_at_least_once (false)
101 , queue_device_changed (false)
102 , _have_control (true)
105 using namespace Notebook_Helpers;
106 vector<string> backend_names;
108 AttachOptions xopt = AttachOptions (FILL|EXPAND);
111 set_name (X_("AudioMIDISetup"));
113 /* the backend combo is the one thing that is ALWAYS visible */
115 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
117 if (backends.empty()) {
118 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
120 throw failed_constructor ();
123 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
124 backend_names.push_back ((*b)->name);
127 set_popdown_strings (backend_combo, backend_names);
129 /* setup basic packing characteristics for the table used on the main
130 * tab of the notebook
133 basic_packer.set_spacings (6);
134 basic_packer.set_border_width (12);
135 basic_packer.set_homogeneous (false);
139 basic_hbox.pack_start (basic_packer, false, false);
141 /* latency measurement tab */
143 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
146 lm_table.set_row_spacings (12);
147 lm_table.set_col_spacings (6);
148 lm_table.set_homogeneous (false);
150 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
153 lm_preamble.set_width_chars (60);
154 lm_preamble.set_line_wrap (true);
155 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
157 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
160 Gtk::Label* preamble;
161 preamble = manage (new Label);
162 preamble->set_width_chars (60);
163 preamble->set_line_wrap (true);
164 preamble->set_markup (_("Select two channels below and connect them using a cable."));
166 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
169 label = manage (new Label (_("Output channel")));
170 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
172 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
173 misc_align->add (lm_output_channel_combo);
174 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
177 label = manage (new Label (_("Input channel")));
178 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
180 misc_align = manage (new Alignment (0.0, 0.5));
181 misc_align->add (lm_input_channel_combo);
182 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
185 lm_measure_label.set_padding (10, 10);
186 lm_measure_button.add (lm_measure_label);
187 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
188 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
189 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
191 lm_use_button.set_sensitive (false);
193 /* Increase the default spacing around the labels of these three
199 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
200 l->set_padding (10, 10);
203 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
204 l->set_padding (10, 10);
207 preamble = manage (new Label);
208 preamble->set_width_chars (60);
209 preamble->set_line_wrap (true);
210 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
211 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
214 preamble = manage (new Label);
215 preamble->set_width_chars (60);
216 preamble->set_line_wrap (true);
217 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
218 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220 ++row; // skip a row in the table
221 ++row; // skip a row in the table
223 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 ++row; // skip a row in the table
226 ++row; // skip a row in the table
228 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
234 lm_vbox.set_border_width (12);
235 lm_vbox.pack_start (lm_table, false, false);
237 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
241 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
242 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
243 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
244 notebook.set_border_width (12);
246 notebook.set_show_tabs (false);
247 notebook.show_all ();
249 notebook.set_name ("SettingsNotebook");
251 /* packup the notebook */
253 get_vbox()->set_border_width (12);
254 get_vbox()->pack_start (notebook);
256 /* need a special function to print "all available channels" when the
257 * channel counts hit zero.
260 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
261 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
263 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
264 midi_devices_button.set_sensitive (false);
265 midi_devices_button.set_name ("generic button");
266 midi_devices_button.set_can_focus(true);
268 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
269 control_app_button.set_name ("generic button");
270 control_app_button.set_can_focus(true);
271 manage_control_app_sensitivity ();
273 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
274 start_stop_button.set_sensitive (false);
275 start_stop_button.set_name ("generic button");
276 start_stop_button.set_can_focus(true);
278 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
279 update_devices_button.set_sensitive (false);
280 update_devices_button.set_name ("generic button");
281 update_devices_button.set_can_focus(true);
283 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
284 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
286 /* Pick up any existing audio setup configuration, if appropriate */
288 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
290 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
291 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
292 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
293 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
296 if (!set_state (*audio_setup)) {
297 set_default_state ();
300 set_default_state ();
303 connect_changed_signals ();
305 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
307 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
308 connect_disconnect_button.set_no_show_all();
313 EngineControl::connect_changed_signals ()
315 backend_combo_connection = backend_combo.signal_changed ().connect (
316 sigc::mem_fun (*this, &EngineControl::backend_changed));
317 driver_combo_connection = driver_combo.signal_changed ().connect (
318 sigc::mem_fun (*this, &EngineControl::driver_changed));
319 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
320 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
321 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
322 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
323 device_combo_connection = device_combo.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::device_changed));
325 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
328 input_device_combo_connection = input_device_combo.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::input_device_changed));
330 output_device_combo_connection = output_device_combo.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::output_device_changed));
333 input_latency_connection = input_latency.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::parameter_changed));
335 output_latency_connection = output_latency.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::parameter_changed));
337 input_channels_connection = input_channels.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::parameter_changed));
339 output_channels_connection = output_channels.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::parameter_changed));
344 EngineControl::block_changed_signals ()
346 if (block_signals++ == 0) {
347 DEBUG_ECONTROL ("Blocking changed signals");
348 backend_combo_connection.block ();
349 driver_combo_connection.block ();
350 sample_rate_combo_connection.block ();
351 buffer_size_combo_connection.block ();
352 device_combo_connection.block ();
353 input_device_combo_connection.block ();
354 output_device_combo_connection.block ();
355 midi_option_combo_connection.block ();
356 input_latency_connection.block ();
357 output_latency_connection.block ();
358 input_channels_connection.block ();
359 output_channels_connection.block ();
364 EngineControl::unblock_changed_signals ()
366 if (--block_signals == 0) {
367 DEBUG_ECONTROL ("Unblocking changed signals");
368 backend_combo_connection.unblock ();
369 driver_combo_connection.unblock ();
370 sample_rate_combo_connection.unblock ();
371 buffer_size_combo_connection.unblock ();
372 device_combo_connection.unblock ();
373 input_device_combo_connection.unblock ();
374 output_device_combo_connection.unblock ();
375 midi_option_combo_connection.unblock ();
376 input_latency_connection.unblock ();
377 output_latency_connection.unblock ();
378 input_channels_connection.unblock ();
379 output_channels_connection.unblock ();
383 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
384 const std::string& reason)
385 : ec (engine_control)
388 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
389 ec.block_changed_signals ();
392 EngineControl::SignalBlocker::~SignalBlocker ()
394 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
395 ec.unblock_changed_signals ();
399 EngineControl::on_show ()
401 ArdourDialog::on_show ();
402 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
403 // re-check _have_control (jackd running) see #6041
407 ok_button->grab_focus();
411 EngineControl::on_response (int response_id)
413 ArdourDialog::on_response (response_id);
415 switch (response_id) {
417 if (push_state_to_backend (true) != 0) {
422 #ifdef PLATFORM_WINDOWS
424 // But if there's no session open, this can produce
425 // a long gap when nothing appears to be happening.
426 // Let's show the splash image while we're waiting.
427 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
428 if ( ARDOUR_UI::instance() ) {
429 if ( !ARDOUR_UI::instance()->session_loaded ) {
430 ARDOUR_UI::instance()->show_splash();
436 case RESPONSE_DELETE_EVENT:
439 ev.type = GDK_BUTTON_PRESS;
441 on_delete_event ((GdkEventAny*) &ev);
444 case RESPONSE_CANCEL:
445 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
446 ARDOUR_UI::instance()->check_audioengine (*this);
455 EngineControl::build_notebook ()
458 AttachOptions xopt = AttachOptions (FILL|EXPAND);
460 /* clear the table */
462 Gtkmm2ext::container_clear (basic_vbox);
463 Gtkmm2ext::container_clear (basic_packer);
465 if (control_app_button.get_parent()) {
466 control_app_button.get_parent()->remove (control_app_button);
469 label = manage (left_aligned_label (_("Audio System:")));
470 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
471 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
473 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
474 engine_status.show();
476 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
477 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
479 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
480 lm_button_audio.set_name ("generic button");
481 lm_button_audio.set_can_focus(true);
484 build_full_control_notebook ();
486 build_no_control_notebook ();
489 basic_vbox.pack_start (basic_hbox, false, false);
492 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
493 basic_vbox.show_all ();
498 EngineControl::build_full_control_notebook ()
500 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
503 using namespace Notebook_Helpers;
505 vector<string> strings;
506 AttachOptions xopt = AttachOptions (FILL|EXPAND);
507 int row = 1; // row zero == backend combo
509 /* start packing it up */
511 if (backend->requires_driver_selection()) {
512 label = manage (left_aligned_label (_("Driver:")));
513 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
514 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
518 if (backend->use_separate_input_and_output_devices()) {
519 label = manage (left_aligned_label (_("Input Device:")));
520 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
521 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
523 label = manage (left_aligned_label (_("Output Device:")));
524 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
525 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
527 // reset so it isn't used in state comparisons
528 device_combo.set_active_text ("");
530 label = manage (left_aligned_label (_("Device:")));
531 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
532 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
534 // reset these so they don't get used in state comparisons
535 input_device_combo.set_active_text ("");
536 output_device_combo.set_active_text ("");
539 label = manage (left_aligned_label (_("Sample rate:")));
540 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
541 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
545 label = manage (left_aligned_label (_("Buffer size:")));
546 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
547 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
548 buffer_size_duration_label.set_alignment (0.0); /* left-align */
549 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
551 /* button spans 2 rows */
553 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
556 input_channels.set_name ("InputChannels");
557 input_channels.set_flags (Gtk::CAN_FOCUS);
558 input_channels.set_digits (0);
559 input_channels.set_wrap (false);
560 output_channels.set_editable (true);
562 if (!ARDOUR::Profile->get_mixbus()) {
563 label = manage (left_aligned_label (_("Input Channels:")));
564 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
565 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
569 output_channels.set_name ("OutputChannels");
570 output_channels.set_flags (Gtk::CAN_FOCUS);
571 output_channels.set_digits (0);
572 output_channels.set_wrap (false);
573 output_channels.set_editable (true);
575 if (!ARDOUR::Profile->get_mixbus()) {
576 label = manage (left_aligned_label (_("Output Channels:")));
577 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
578 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
582 input_latency.set_name ("InputLatency");
583 input_latency.set_flags (Gtk::CAN_FOCUS);
584 input_latency.set_digits (0);
585 input_latency.set_wrap (false);
586 input_latency.set_editable (true);
588 label = manage (left_aligned_label (_("Hardware input latency:")));
589 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
590 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
591 label = manage (left_aligned_label (_("samples")));
592 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
595 output_latency.set_name ("OutputLatency");
596 output_latency.set_flags (Gtk::CAN_FOCUS);
597 output_latency.set_digits (0);
598 output_latency.set_wrap (false);
599 output_latency.set_editable (true);
601 label = manage (left_aligned_label (_("Hardware output latency:")));
602 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
603 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
604 label = manage (left_aligned_label (_("samples")));
605 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
607 /* button spans 2 rows */
609 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
612 label = manage (left_aligned_label (_("MIDI System:")));
613 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
614 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
615 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
616 /* Currently the only backend with dedicated Midi setup is ALSA.
617 * lot of people complain that this is greyed out
618 * "I can't use MIDI, the setup is greyed out"
620 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
626 EngineControl::build_no_control_notebook ()
628 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
631 using namespace Notebook_Helpers;
633 vector<string> strings;
634 AttachOptions xopt = AttachOptions (FILL|EXPAND);
635 int row = 1; // row zero == backend combo
636 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
638 label = manage (new Label);
639 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
640 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
643 if (backend->can_change_sample_rate_when_running()) {
644 label = manage (left_aligned_label (_("Sample rate:")));
645 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
646 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
650 if (backend->can_change_buffer_size_when_running()) {
651 label = manage (left_aligned_label (_("Buffer size:")));
652 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
653 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
654 buffer_size_duration_label.set_alignment (0.0); /* left-align */
655 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
659 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
663 EngineControl::~EngineControl ()
665 ignore_changes = true;
669 EngineControl::disable_latency_tab ()
671 vector<string> empty;
672 set_popdown_strings (lm_output_channel_combo, empty);
673 set_popdown_strings (lm_input_channel_combo, empty);
674 lm_measure_button.set_sensitive (false);
675 lm_use_button.set_sensitive (false);
679 EngineControl::enable_latency_tab ()
681 vector<string> outputs;
682 vector<string> inputs;
684 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
685 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
686 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
688 if (!ARDOUR::AudioEngine::instance()->running()) {
689 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
690 notebook.set_current_page (0);
694 else if (inputs.empty() || outputs.empty()) {
695 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
696 notebook.set_current_page (0);
701 lm_back_button_signal.disconnect();
703 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
706 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
710 set_popdown_strings (lm_output_channel_combo, outputs);
711 lm_output_channel_combo.set_active_text (outputs.front());
712 lm_output_channel_combo.set_sensitive (true);
714 set_popdown_strings (lm_input_channel_combo, inputs);
715 lm_input_channel_combo.set_active_text (inputs.front());
716 lm_input_channel_combo.set_sensitive (true);
718 lm_measure_button.set_sensitive (true);
722 EngineControl::setup_midi_tab_for_backend ()
724 string backend = backend_combo.get_active_text ();
726 Gtkmm2ext::container_clear (midi_vbox);
728 midi_vbox.set_border_width (12);
729 midi_device_table.set_border_width (12);
731 if (backend == "JACK") {
732 setup_midi_tab_for_jack ();
735 midi_vbox.pack_start (midi_device_table, true, true);
736 midi_vbox.pack_start (midi_back_button, false, false);
737 midi_vbox.show_all ();
741 EngineControl::update_sensitivity ()
743 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
745 ok_button->set_sensitive (false);
746 start_stop_button.set_sensitive (false);
751 size_t devices_available = 0;
753 if (backend->use_separate_input_and_output_devices ()) {
754 devices_available += get_popdown_string_count (input_device_combo);
755 devices_available += get_popdown_string_count (output_device_combo);
757 devices_available += get_popdown_string_count (device_combo);
760 if (devices_available == 0) {
762 input_latency.set_sensitive (false);
763 output_latency.set_sensitive (false);
764 input_channels.set_sensitive (false);
765 output_channels.set_sensitive (false);
767 input_latency.set_sensitive (true);
768 output_latency.set_sensitive (true);
769 input_channels.set_sensitive (true);
770 output_channels.set_sensitive (true);
773 if (get_popdown_string_count (buffer_size_combo) > 0) {
774 if (!ARDOUR::AudioEngine::instance()->running()) {
775 buffer_size_combo.set_sensitive (valid);
776 } else if (backend->can_change_sample_rate_when_running()) {
777 buffer_size_combo.set_sensitive (valid || !_have_control);
781 * Currently there is no way to manually stop the
782 * engine in order to re-configure it.
783 * This needs to remain sensitive for now.
785 * (it's also handy to implicily
786 * re-start the engine)
788 buffer_size_combo.set_sensitive (true);
790 buffer_size_combo.set_sensitive (false);
794 buffer_size_combo.set_sensitive (false);
798 if (get_popdown_string_count (sample_rate_combo) > 0) {
799 if (!ARDOUR::AudioEngine::instance()->running()) {
800 sample_rate_combo.set_sensitive (true);
802 sample_rate_combo.set_sensitive (false);
805 sample_rate_combo.set_sensitive (false);
810 start_stop_button.set_sensitive(true);
811 start_stop_button.show();
812 if (ARDOUR::AudioEngine::instance()->running()) {
813 start_stop_button.set_text("Stop");
814 update_devices_button.set_sensitive(false);
816 if (backend->can_request_update_devices()) {
817 update_devices_button.show();
819 update_devices_button.hide();
821 start_stop_button.set_text("Start");
822 update_devices_button.set_sensitive(true);
825 update_devices_button.set_sensitive(false);
826 update_devices_button.hide();
827 start_stop_button.set_sensitive(false);
828 start_stop_button.hide();
831 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
832 input_device_combo.set_sensitive (false);
833 output_device_combo.set_sensitive (false);
834 device_combo.set_sensitive (false);
835 driver_combo.set_sensitive (false);
837 input_device_combo.set_sensitive (true);
838 output_device_combo.set_sensitive (true);
839 device_combo.set_sensitive (true);
840 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
841 driver_combo.set_sensitive (true);
843 driver_combo.set_sensitive (false);
847 if (valid || !_have_control) {
848 ok_button->set_sensitive (true);
850 ok_button->set_sensitive (false);
855 EngineControl::setup_midi_tab_for_jack ()
860 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
862 device->input_latency = a->get_value();
864 device->output_latency = a->get_value();
869 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
870 b->set_active (!b->get_active());
871 device->enabled = b->get_active();
872 refresh_midi_display(device->name);
876 EngineControl::refresh_midi_display (std::string focus)
878 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
882 AttachOptions xopt = AttachOptions (FILL|EXPAND);
885 Gtkmm2ext::container_clear (midi_device_table);
887 midi_device_table.set_spacings (6);
889 l = manage (new Label);
890 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
891 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
892 l->set_alignment (0.5, 0.5);
896 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
897 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
898 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
899 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
901 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
902 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
903 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
904 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
907 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
912 bool enabled = (*p)->enabled;
914 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
915 m->set_name ("midi device");
916 m->set_can_focus (Gtk::CAN_FOCUS);
917 m->add_events (Gdk::BUTTON_RELEASE_MASK);
918 m->set_active (enabled);
919 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
920 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
921 if ((*p)->name == focus) {
925 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
926 s = manage (new Gtk::SpinButton (*a));
927 a->set_value ((*p)->input_latency);
928 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
929 s->set_sensitive (_can_set_midi_latencies && enabled);
930 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
932 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
933 s = manage (new Gtk::SpinButton (*a));
934 a->set_value ((*p)->output_latency);
935 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
936 s->set_sensitive (_can_set_midi_latencies && enabled);
937 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
939 b = manage (new Button (_("Calibrate")));
940 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
941 b->set_sensitive (_can_set_midi_latencies && enabled);
942 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
949 EngineControl::backend_changed ()
951 SignalBlocker blocker (*this, "backend_changed");
952 string backend_name = backend_combo.get_active_text();
953 boost::shared_ptr<ARDOUR::AudioBackend> backend;
955 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
956 /* eh? setting the backend failed... how ? */
957 /* A: stale config contains a backend that does not exist in current build */
961 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
963 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
966 setup_midi_tab_for_backend ();
967 _midi_devices.clear();
969 if (backend->requires_driver_selection()) {
970 if (set_driver_popdown_strings ()) {
974 /* this will change the device text which will cause a call to
975 * device changed which will set up parameters
980 update_midi_options ();
982 connect_disconnect_button.hide();
984 midi_option_changed();
986 started_at_least_once = false;
988 /* changing the backend implies stopping the engine
989 * ARDOUR::AudioEngine() may or may not emit this signal
990 * depending on previous engine state
992 engine_stopped (); // set "active/inactive"
994 if (!ignore_changes) {
995 maybe_display_saved_state ();
1000 EngineControl::update_midi_options ()
1002 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1003 vector<string> midi_options = backend->enumerate_midi_options();
1005 if (midi_options.size() == 1) {
1006 /* only contains the "none" option */
1007 midi_option_combo.set_sensitive (false);
1009 if (_have_control) {
1010 set_popdown_strings (midi_option_combo, midi_options);
1011 midi_option_combo.set_active_text (midi_options.front());
1012 midi_option_combo.set_sensitive (true);
1014 midi_option_combo.set_sensitive (false);
1020 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1022 if (ARDOUR::Profile->get_mixbus()) {
1026 uint32_t cnt = (uint32_t) sb->get_value();
1028 sb->set_text (_("all available channels"));
1031 snprintf (buf, sizeof (buf), "%d", cnt);
1037 // @return true if there are drivers available
1039 EngineControl::set_driver_popdown_strings ()
1041 DEBUG_ECONTROL ("set_driver_popdown_strings");
1042 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1043 vector<string> drivers = backend->enumerate_drivers();
1045 if (drivers.empty ()) {
1046 // This is an error...?
1050 string current_driver = backend->driver_name ();
1052 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1054 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1057 current_driver = drivers.front ();
1060 set_popdown_strings (driver_combo, drivers);
1062 string_compose ("driver_combo.set_active_text: %1", current_driver));
1063 driver_combo.set_active_text (current_driver);
1068 EngineControl::get_default_device(const string& current_device_name,
1069 const vector<string>& available_devices)
1071 // If the current device is available, use it as default
1072 if (std::find (available_devices.begin (),
1073 available_devices.end (),
1074 current_device_name) != available_devices.end ()) {
1076 return current_device_name;
1079 using namespace ARDOUR;
1081 string default_device_name =
1082 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1084 vector<string>::const_iterator i;
1086 // If there is a "Default" device available, use it
1087 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1088 if (*i == default_device_name) {
1093 string none_device_name =
1094 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1096 // Use the first device that isn't "None"
1097 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1098 if (*i != none_device_name) {
1103 // Use "None" if there are no other available
1104 return available_devices.front();
1107 // @return true if there are devices available
1109 EngineControl::set_device_popdown_strings ()
1111 DEBUG_ECONTROL ("set_device_popdown_strings");
1112 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1113 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1115 /* NOTE: Ardour currently does not display the "available" field of the
1118 * Doing so would require a different GUI widget than the combo
1119 * box/popdown that we currently use, since it has no way to list
1120 * items that are not selectable. Something more like a popup menu,
1121 * which could have unselectable items, would be appropriate.
1124 vector<string> available_devices;
1126 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1127 available_devices.push_back (i->name);
1130 if (available_devices.empty ()) {
1134 set_popdown_strings (device_combo, available_devices);
1136 std::string default_device =
1137 get_default_device(backend->device_name(), available_devices);
1140 string_compose ("set device_combo active text: %1", default_device));
1142 device_combo.set_active_text(default_device);
1146 // @return true if there are input devices available
1148 EngineControl::set_input_device_popdown_strings ()
1150 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1151 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1152 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1154 vector<string> available_devices;
1156 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1157 available_devices.push_back (i->name);
1160 if (available_devices.empty()) {
1164 set_popdown_strings (input_device_combo, available_devices);
1166 std::string default_device =
1167 get_default_device(backend->input_device_name(), available_devices);
1170 string_compose ("set input_device_combo active text: %1", default_device));
1171 input_device_combo.set_active_text(default_device);
1175 // @return true if there are output devices available
1177 EngineControl::set_output_device_popdown_strings ()
1179 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1180 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1181 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1183 vector<string> available_devices;
1185 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1186 available_devices.push_back (i->name);
1189 if (available_devices.empty()) {
1193 set_popdown_strings (output_device_combo, available_devices);
1195 std::string default_device =
1196 get_default_device(backend->output_device_name(), available_devices);
1199 string_compose ("set output_device_combo active text: %1", default_device));
1200 output_device_combo.set_active_text(default_device);
1205 EngineControl::list_devices ()
1207 DEBUG_ECONTROL ("list_devices");
1208 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1211 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1213 bool devices_available = false;
1215 if (backend->use_separate_input_and_output_devices ()) {
1216 bool input_devices_available = set_input_device_popdown_strings ();
1217 bool output_devices_available = set_output_device_popdown_strings ();
1218 devices_available = input_devices_available || output_devices_available;
1220 devices_available = set_device_popdown_strings ();
1223 if (devices_available) {
1226 device_combo.clear();
1227 input_device_combo.clear();
1228 output_device_combo.clear();
1230 update_sensitivity ();
1234 EngineControl::driver_changed ()
1236 SignalBlocker blocker (*this, "driver_changed");
1237 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1240 backend->set_driver (driver_combo.get_active_text());
1243 if (!ignore_changes) {
1244 maybe_display_saved_state ();
1249 EngineControl::get_sample_rates_for_all_devices ()
1251 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1252 ARDOUR::AudioEngine::instance ()->current_backend ();
1253 vector<float> all_rates;
1255 if (backend->use_separate_input_and_output_devices ()) {
1256 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1258 all_rates = backend->available_sample_rates (get_device_name ());
1264 EngineControl::get_default_sample_rates ()
1266 vector<float> rates;
1267 rates.push_back (8000.0f);
1268 rates.push_back (16000.0f);
1269 rates.push_back (32000.0f);
1270 rates.push_back (44100.0f);
1271 rates.push_back (48000.0f);
1272 rates.push_back (88200.0f);
1273 rates.push_back (96000.0f);
1274 rates.push_back (192000.0f);
1275 rates.push_back (384000.0f);
1280 EngineControl::set_samplerate_popdown_strings ()
1282 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1283 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1288 if (_have_control) {
1289 sr = get_sample_rates_for_all_devices ();
1291 sr = get_default_sample_rates ();
1294 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1295 s.push_back (rate_as_string (*x));
1296 if (*x == _desired_sample_rate) {
1301 set_popdown_strings (sample_rate_combo, s);
1304 if (desired.empty ()) {
1305 float new_active_sr = backend->default_sample_rate ();
1307 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1308 new_active_sr = sr.front ();
1311 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1313 sample_rate_combo.set_active_text (desired);
1317 update_sensitivity ();
1321 EngineControl::get_buffer_sizes_for_all_devices ()
1323 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1324 ARDOUR::AudioEngine::instance ()->current_backend ();
1325 vector<uint32_t> all_sizes;
1327 if (backend->use_separate_input_and_output_devices ()) {
1328 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1330 all_sizes = backend->available_buffer_sizes (get_device_name ());
1336 EngineControl::get_default_buffer_sizes ()
1338 vector<uint32_t> sizes;
1339 sizes.push_back (8);
1340 sizes.push_back (16);
1341 sizes.push_back (32);
1342 sizes.push_back (64);
1343 sizes.push_back (128);
1344 sizes.push_back (256);
1345 sizes.push_back (512);
1346 sizes.push_back (1024);
1347 sizes.push_back (2048);
1348 sizes.push_back (4096);
1349 sizes.push_back (8192);
1354 EngineControl::set_buffersize_popdown_strings ()
1356 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1357 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1358 vector<uint32_t> bs;
1361 if (_have_control) {
1362 bs = get_buffer_sizes_for_all_devices ();
1363 } else if (backend->can_change_buffer_size_when_running()) {
1364 bs = get_default_buffer_sizes ();
1367 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1368 s.push_back (bufsize_as_string (*x));
1371 uint32_t previous_size = 0;
1372 if (!buffer_size_combo.get_active_text().empty()) {
1373 previous_size = get_buffer_size ();
1376 set_popdown_strings (buffer_size_combo, s);
1380 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1381 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1384 buffer_size_combo.set_active_text(s.front());
1386 uint32_t period = backend->buffer_size();
1387 if (0 == period && backend->use_separate_input_and_output_devices()) {
1388 period = backend->default_buffer_size(get_input_device_name());
1390 if (0 == period && backend->use_separate_input_and_output_devices()) {
1391 period = backend->default_buffer_size(get_output_device_name());
1393 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1394 period = backend->default_buffer_size(get_device_name());
1397 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1399 show_buffer_duration ();
1401 update_sensitivity ();
1405 EngineControl::device_changed ()
1407 SignalBlocker blocker (*this, "device_changed");
1408 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1411 string device_name_in;
1412 string device_name_out; // only used if backend support separate I/O devices
1414 if (backend->use_separate_input_and_output_devices()) {
1415 device_name_in = get_input_device_name ();
1416 device_name_out = get_output_device_name ();
1418 device_name_in = get_device_name ();
1421 /* we set the backend-device to query various device related intormation.
1422 * This has the side effect that backend->device_name() will match
1423 * the device_name and 'change_device' will never be true.
1424 * so work around this by setting...
1426 if (backend->use_separate_input_and_output_devices()) {
1427 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1428 queue_device_changed = true;
1431 if (device_name_in != backend->device_name()) {
1432 queue_device_changed = true;
1436 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1437 if (backend->use_separate_input_and_output_devices()) {
1438 backend->set_input_device_name (device_name_in);
1439 backend->set_output_device_name (device_name_out);
1441 backend->set_device_name(device_name_in);
1445 /* don't allow programmatic change to combos to cause a
1446 recursive call to this method.
1448 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1450 set_samplerate_popdown_strings ();
1451 set_buffersize_popdown_strings ();
1453 /* TODO set min + max channel counts here */
1455 manage_control_app_sensitivity ();
1458 /* pick up any saved state for this device */
1460 if (!ignore_changes) {
1461 maybe_display_saved_state ();
1466 EngineControl::input_device_changed ()
1468 DEBUG_ECONTROL ("input_device_changed");
1473 EngineControl::output_device_changed ()
1475 DEBUG_ECONTROL ("output_device_changed");
1480 EngineControl::bufsize_as_string (uint32_t sz)
1482 /* Translators: "samples" is always plural here, so no
1483 need for plural+singular forms.
1486 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1491 EngineControl::sample_rate_changed ()
1493 DEBUG_ECONTROL ("sample_rate_changed");
1494 /* reset the strings for buffer size to show the correct msec value
1495 (reflecting the new sample rate).
1498 show_buffer_duration ();
1503 EngineControl::buffer_size_changed ()
1505 DEBUG_ECONTROL ("buffer_size_changed");
1506 show_buffer_duration ();
1510 EngineControl::show_buffer_duration ()
1512 DEBUG_ECONTROL ("show_buffer_duration");
1513 /* buffer sizes - convert from just samples to samples + msecs for
1514 * the displayed string
1517 string bs_text = buffer_size_combo.get_active_text ();
1518 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1519 uint32_t rate = get_rate();
1521 /* Developers: note the hard-coding of a double buffered model
1522 in the (2 * samples) computation of latency. we always start
1523 the audiobackend in this configuration.
1525 /* note to jack1 developers: ardour also always starts the engine
1526 * in async mode (no jack2 --sync option) which adds an extra cycle
1527 * of latency with jack2 (and *3 would be correct)
1528 * The value can also be wrong if jackd is started externally..
1530 * At the time of writing the ALSA backend always uses double-buffering *2,
1531 * The Dummy backend *1, and who knows what ASIO really does :)
1533 * So just display the period size, that's also what
1534 * ARDOUR_UI::update_sample_rate() does for the status bar.
1535 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1536 * but still, that's the buffer period, not [round-trip] latency)
1539 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1540 buffer_size_duration_label.set_text (buf);
1544 EngineControl::midi_option_changed ()
1546 DEBUG_ECONTROL ("midi_option_changed");
1547 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1550 backend->set_midi_option (get_midi_option());
1552 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1554 //_midi_devices.clear(); // TODO merge with state-saved settings..
1555 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1556 std::vector<MidiDeviceSettings> new_devices;
1558 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1559 MidiDeviceSettings mds = find_midi_device (i->name);
1560 if (i->available && !mds) {
1561 uint32_t input_latency = 0;
1562 uint32_t output_latency = 0;
1563 if (_can_set_midi_latencies) {
1564 input_latency = backend->systemic_midi_input_latency (i->name);
1565 output_latency = backend->systemic_midi_output_latency (i->name);
1567 bool enabled = backend->midi_device_enabled (i->name);
1568 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1569 new_devices.push_back (ptr);
1570 } else if (i->available) {
1571 new_devices.push_back (mds);
1574 _midi_devices = new_devices;
1576 if (_midi_devices.empty()) {
1577 midi_devices_button.set_sensitive (false);
1579 midi_devices_button.set_sensitive (true);
1584 EngineControl::parameter_changed ()
1588 EngineControl::State
1589 EngineControl::get_matching_state (
1590 const string& backend,
1591 const string& driver,
1592 const string& device)
1594 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1595 if ((*i)->backend == backend &&
1596 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1604 EngineControl::State
1605 EngineControl::get_matching_state (
1606 const string& backend,
1607 const string& driver,
1608 const string& input_device,
1609 const string& output_device)
1611 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1612 if ((*i)->backend == backend &&
1613 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1621 EngineControl::State
1622 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1624 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1627 if (backend->use_separate_input_and_output_devices ()) {
1628 return get_matching_state (backend_combo.get_active_text(),
1629 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1630 input_device_combo.get_active_text(),
1631 output_device_combo.get_active_text());
1633 return get_matching_state (backend_combo.get_active_text(),
1634 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1635 device_combo.get_active_text());
1639 return get_matching_state (backend_combo.get_active_text(),
1641 device_combo.get_active_text());
1644 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1645 const EngineControl::State& state2)
1647 if (state1->backend == state2->backend &&
1648 state1->driver == state2->driver &&
1649 state1->device == state2->device &&
1650 state1->input_device == state2->input_device &&
1651 state1->output_device == state2->output_device) {
1657 EngineControl::State
1658 EngineControl::save_state ()
1662 if (!_have_control) {
1663 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1667 state.reset(new StateStruct);
1668 state->backend = get_backend ();
1670 state.reset(new StateStruct);
1671 store_state (state);
1674 for (StateList::iterator i = states.begin(); i != states.end();) {
1675 if (equivalent_states (*i, state)) {
1676 i = states.erase(i);
1682 states.push_back (state);
1688 EngineControl::store_state (State state)
1690 state->backend = get_backend ();
1691 state->driver = get_driver ();
1692 state->device = get_device_name ();
1693 state->input_device = get_input_device_name ();
1694 state->output_device = get_output_device_name ();
1695 state->sample_rate = get_rate ();
1696 state->buffer_size = get_buffer_size ();
1697 state->input_latency = get_input_latency ();
1698 state->output_latency = get_output_latency ();
1699 state->input_channels = get_input_channels ();
1700 state->output_channels = get_output_channels ();
1701 state->midi_option = get_midi_option ();
1702 state->midi_devices = _midi_devices;
1706 EngineControl::maybe_display_saved_state ()
1708 if (!_have_control) {
1712 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1715 DEBUG_ECONTROL ("Restoring saved state");
1716 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1718 if (!_desired_sample_rate) {
1719 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1721 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1722 /* call this explicitly because we're ignoring changes to
1723 the controls at this point.
1725 show_buffer_duration ();
1726 input_latency.set_value (state->input_latency);
1727 output_latency.set_value (state->output_latency);
1729 if (!state->midi_option.empty()) {
1730 midi_option_combo.set_active_text (state->midi_option);
1731 _midi_devices = state->midi_devices;
1734 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1739 EngineControl::get_state ()
1741 LocaleGuard lg (X_("C"));
1743 XMLNode* root = new XMLNode ("AudioMIDISetup");
1746 if (!states.empty()) {
1747 XMLNode* state_nodes = new XMLNode ("EngineStates");
1749 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1751 XMLNode* node = new XMLNode ("State");
1753 node->add_property ("backend", (*i)->backend);
1754 node->add_property ("driver", (*i)->driver);
1755 node->add_property ("device", (*i)->device);
1756 node->add_property ("input-device", (*i)->input_device);
1757 node->add_property ("output-device", (*i)->output_device);
1758 node->add_property ("sample-rate", (*i)->sample_rate);
1759 node->add_property ("buffer-size", (*i)->buffer_size);
1760 node->add_property ("input-latency", (*i)->input_latency);
1761 node->add_property ("output-latency", (*i)->output_latency);
1762 node->add_property ("input-channels", (*i)->input_channels);
1763 node->add_property ("output-channels", (*i)->output_channels);
1764 node->add_property ("active", (*i)->active ? "yes" : "no");
1765 node->add_property ("midi-option", (*i)->midi_option);
1767 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1768 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1769 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1770 midi_device_stuff->add_property (X_("name"), (*p)->name);
1771 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1772 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1773 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1774 midi_devices->add_child_nocopy (*midi_device_stuff);
1776 node->add_child_nocopy (*midi_devices);
1778 state_nodes->add_child_nocopy (*node);
1781 root->add_child_nocopy (*state_nodes);
1788 EngineControl::set_default_state ()
1790 vector<string> backend_names;
1791 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1793 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1794 backend_names.push_back ((*b)->name);
1796 backend_combo.set_active_text (backend_names.front());
1798 // We could set default backends per platform etc here
1804 EngineControl::set_state (const XMLNode& root)
1806 XMLNodeList clist, cclist;
1807 XMLNodeConstIterator citer, cciter;
1809 XMLNode* grandchild;
1810 XMLProperty* prop = NULL;
1812 fprintf (stderr, "EngineControl::set_state\n");
1814 if (root.name() != "AudioMIDISetup") {
1818 clist = root.children();
1822 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1826 if (child->name() != "EngineStates") {
1830 cclist = child->children();
1832 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1833 State state (new StateStruct);
1835 grandchild = *cciter;
1837 if (grandchild->name() != "State") {
1841 if ((prop = grandchild->property ("backend")) == 0) {
1844 state->backend = prop->value ();
1846 if ((prop = grandchild->property ("driver")) == 0) {
1849 state->driver = prop->value ();
1851 if ((prop = grandchild->property ("device")) == 0) {
1854 state->device = prop->value ();
1856 if ((prop = grandchild->property ("input-device")) == 0) {
1859 state->input_device = prop->value ();
1861 if ((prop = grandchild->property ("output-device")) == 0) {
1864 state->output_device = prop->value ();
1866 if ((prop = grandchild->property ("sample-rate")) == 0) {
1869 state->sample_rate = atof (prop->value ());
1871 if ((prop = grandchild->property ("buffer-size")) == 0) {
1874 state->buffer_size = atoi (prop->value ());
1876 if ((prop = grandchild->property ("input-latency")) == 0) {
1879 state->input_latency = atoi (prop->value ());
1881 if ((prop = grandchild->property ("output-latency")) == 0) {
1884 state->output_latency = atoi (prop->value ());
1886 if ((prop = grandchild->property ("input-channels")) == 0) {
1889 state->input_channels = atoi (prop->value ());
1891 if ((prop = grandchild->property ("output-channels")) == 0) {
1894 state->output_channels = atoi (prop->value ());
1896 if ((prop = grandchild->property ("active")) == 0) {
1899 state->active = string_is_affirmative (prop->value ());
1901 if ((prop = grandchild->property ("midi-option")) == 0) {
1904 state->midi_option = prop->value ();
1906 state->midi_devices.clear();
1908 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1909 const XMLNodeList mnc = midinode->children();
1910 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1911 if ((*n)->property (X_("name")) == 0
1912 || (*n)->property (X_("enabled")) == 0
1913 || (*n)->property (X_("input-latency")) == 0
1914 || (*n)->property (X_("output-latency")) == 0
1919 MidiDeviceSettings ptr (new MidiDeviceSetting(
1920 (*n)->property (X_("name"))->value (),
1921 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1922 atoi ((*n)->property (X_("input-latency"))->value ()),
1923 atoi ((*n)->property (X_("output-latency"))->value ())
1925 state->midi_devices.push_back (ptr);
1930 /* remove accumulated duplicates (due to bug in ealier version)
1931 * this can be removed again before release
1933 for (StateList::iterator i = states.begin(); i != states.end();) {
1934 if ((*i)->backend == state->backend &&
1935 (*i)->driver == state->driver &&
1936 (*i)->device == state->device) {
1937 i = states.erase(i);
1944 states.push_back (state);
1948 /* now see if there was an active state and switch the setup to it */
1950 // purge states of backend that are not available in this built
1951 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1952 vector<std::string> backend_names;
1954 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1955 backend_names.push_back((*i)->name);
1957 for (StateList::iterator i = states.begin(); i != states.end();) {
1958 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1959 i = states.erase(i);
1965 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1968 return set_current_state (*i);
1975 EngineControl::set_current_state (const State& state)
1977 DEBUG_ECONTROL ("set_current_state");
1979 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1981 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1982 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
1983 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1984 // this shouldn't happen as the invalid backend names should have been
1985 // removed from the list of states.
1989 // now reflect the change in the backend in the GUI so backend_changed will
1990 // do the right thing
1991 backend_combo.set_active_text (state->backend);
1993 if (!state->driver.empty ()) {
1994 if (!backend->requires_driver_selection ()) {
1995 DEBUG_ECONTROL ("Backend should require driver selection");
1996 // A backend has changed from having driver selection to not having
1997 // it or someone has been manually editing a config file and messed
2002 if (backend->set_driver (state->driver) != 0) {
2003 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2004 // Driver names for a backend have changed and the name in the
2005 // config file is now invalid or support for driver is no longer
2006 // included in the backend
2009 // no need to set the driver_combo as backend_changed will use
2010 // backend->driver_name to set the active driver
2013 if (!state->device.empty ()) {
2014 if (backend->set_device_name (state->device) != 0) {
2016 string_compose ("Unable to set device name %1", state->device));
2017 // device is no longer available on the system
2020 // no need to set active device as it will be picked up in
2021 // via backend_changed ()/set_device_popdown_strings
2024 // backend supports separate input/output devices
2025 if (backend->set_input_device_name (state->input_device) != 0) {
2026 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2027 state->input_device));
2028 // input device is no longer available on the system
2032 if (backend->set_output_device_name (state->output_device) != 0) {
2033 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2034 state->input_device));
2035 // output device is no longer available on the system
2038 // no need to set active devices as it will be picked up in via
2039 // backend_changed ()/set_*_device_popdown_strings
2044 // Now restore the state of the rest of the controls
2046 // We don't use a SignalBlocker as set_current_state is currently only
2047 // called from set_state before any signals are connected. If at some point
2048 // a more general named state mechanism is implemented and
2049 // set_current_state is called while signals are connected then a
2050 // SignalBlocker will need to be instantiated before setting these.
2052 device_combo.set_active_text (state->device);
2053 input_device_combo.set_active_text (state->input_device);
2054 output_device_combo.set_active_text (state->output_device);
2055 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2056 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2057 input_latency.set_value (state->input_latency);
2058 output_latency.set_value (state->output_latency);
2059 midi_option_combo.set_active_text (state->midi_option);
2064 EngineControl::push_state_to_backend (bool start)
2066 DEBUG_ECONTROL ("push_state_to_backend");
2067 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2073 /* figure out what is going to change */
2075 bool restart_required = false;
2076 bool was_running = ARDOUR::AudioEngine::instance()->running();
2077 bool change_driver = false;
2078 bool change_device = false;
2079 bool change_rate = false;
2080 bool change_bufsize = false;
2081 bool change_latency = false;
2082 bool change_channels = false;
2083 bool change_midi = false;
2085 uint32_t ochan = get_output_channels ();
2086 uint32_t ichan = get_input_channels ();
2088 if (_have_control) {
2090 if (started_at_least_once) {
2092 /* we can control the backend */
2094 if (backend->requires_driver_selection()) {
2095 if (get_driver() != backend->driver_name()) {
2096 change_driver = true;
2100 if (backend->use_separate_input_and_output_devices()) {
2101 if (get_input_device_name() != backend->input_device_name()) {
2102 change_device = true;
2104 if (get_output_device_name() != backend->output_device_name()) {
2105 change_device = true;
2108 if (get_device_name() != backend->device_name()) {
2109 change_device = true;
2113 if (queue_device_changed) {
2114 change_device = true;
2117 if (get_rate() != backend->sample_rate()) {
2121 if (get_buffer_size() != backend->buffer_size()) {
2122 change_bufsize = true;
2125 if (get_midi_option() != backend->midi_option()) {
2129 /* zero-requested channels means "all available" */
2132 ichan = backend->input_channels();
2136 ochan = backend->output_channels();
2139 if (ichan != backend->input_channels()) {
2140 change_channels = true;
2143 if (ochan != backend->output_channels()) {
2144 change_channels = true;
2147 if (get_input_latency() != backend->systemic_input_latency() ||
2148 get_output_latency() != backend->systemic_output_latency()) {
2149 change_latency = true;
2152 /* backend never started, so we have to force a group
2155 change_device = true;
2156 if (backend->requires_driver_selection()) {
2157 change_driver = true;
2160 change_bufsize = true;
2161 change_channels = true;
2162 change_latency = true;
2168 /* we have no control over the backend, meaning that we can
2169 * only possibly change sample rate and buffer size.
2173 if (get_rate() != backend->sample_rate()) {
2174 change_bufsize = true;
2177 if (get_buffer_size() != backend->buffer_size()) {
2178 change_bufsize = true;
2182 queue_device_changed = false;
2184 if (!_have_control) {
2186 /* We do not have control over the backend, so the best we can
2187 * do is try to change the sample rate and/or bufsize and get
2191 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2195 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2200 backend->set_sample_rate (get_rate());
2203 if (change_bufsize) {
2204 backend->set_buffer_size (get_buffer_size());
2208 if (ARDOUR::AudioEngine::instance()->start ()) {
2209 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2219 /* determine if we need to stop the backend before changing parameters */
2221 if (change_driver || change_device || change_channels || change_latency ||
2222 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2224 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2225 restart_required = true;
2227 restart_required = false;
2232 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2233 /* no changes in any parameters that absolutely require a
2234 * restart, so check those that might be changeable without a
2238 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2239 /* can't do this while running ... */
2240 restart_required = true;
2243 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2244 /* can't do this while running ... */
2245 restart_required = true;
2251 if (restart_required) {
2252 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2259 if (change_driver && backend->set_driver (get_driver())) {
2260 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2263 if (backend->use_separate_input_and_output_devices()) {
2264 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2265 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2268 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2269 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2273 if (change_device && backend->set_device_name (get_device_name())) {
2274 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2278 if (change_rate && backend->set_sample_rate (get_rate())) {
2279 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2282 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2283 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2287 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2288 if (backend->set_input_channels (get_input_channels())) {
2289 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2292 if (backend->set_output_channels (get_output_channels())) {
2293 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2297 if (change_latency) {
2298 if (backend->set_systemic_input_latency (get_input_latency())) {
2299 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2302 if (backend->set_systemic_output_latency (get_output_latency())) {
2303 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2309 backend->set_midi_option (get_midi_option());
2313 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2314 if (_measure_midi) {
2315 if (*p == _measure_midi) {
2316 backend->set_midi_device_enabled ((*p)->name, true);
2318 backend->set_midi_device_enabled ((*p)->name, false);
2322 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2323 if (backend->can_set_systemic_midi_latencies()) {
2324 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2325 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2330 if (start || (was_running && restart_required)) {
2331 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2342 EngineControl::post_push ()
2344 /* get a pointer to the current state object, creating one if
2348 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2351 state = save_state ();
2359 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2360 (*i)->active = false;
2363 /* mark this one active (to be used next time the dialog is
2367 state->active = true;
2369 if (_have_control) { // XXX
2370 manage_control_app_sensitivity ();
2373 /* schedule a redisplay of MIDI ports */
2374 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2379 EngineControl::get_rate () const
2381 float r = atof (sample_rate_combo.get_active_text ());
2382 /* the string may have been translated with an abbreviation for
2383 * thousands, so use a crude heuristic to fix this.
2393 EngineControl::get_buffer_size () const
2395 string txt = buffer_size_combo.get_active_text ();
2398 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2399 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2400 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2408 EngineControl::get_midi_option () const
2410 return midi_option_combo.get_active_text();
2414 EngineControl::get_input_channels() const
2416 if (ARDOUR::Profile->get_mixbus()) {
2417 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2418 if (!backend) return 0;
2419 return backend->input_channels();
2421 return (uint32_t) input_channels_adjustment.get_value();
2425 EngineControl::get_output_channels() const
2427 if (ARDOUR::Profile->get_mixbus()) {
2428 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2429 if (!backend) return 0;
2430 return backend->input_channels();
2432 return (uint32_t) output_channels_adjustment.get_value();
2436 EngineControl::get_input_latency() const
2438 return (uint32_t) input_latency_adjustment.get_value();
2442 EngineControl::get_output_latency() const
2444 return (uint32_t) output_latency_adjustment.get_value();
2448 EngineControl::get_backend () const
2450 return backend_combo.get_active_text ();
2454 EngineControl::get_driver () const
2456 if (driver_combo.get_parent()) {
2457 return driver_combo.get_active_text ();
2464 EngineControl::get_device_name () const
2466 return device_combo.get_active_text ();
2470 EngineControl::get_input_device_name () const
2472 return input_device_combo.get_active_text ();
2476 EngineControl::get_output_device_name () const
2478 return output_device_combo.get_active_text ();
2482 EngineControl::control_app_button_clicked ()
2484 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2490 backend->launch_control_app ();
2494 EngineControl::start_stop_button_clicked ()
2496 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2502 if (ARDOUR::AudioEngine::instance()->running()) {
2503 ARDOUR::AudioEngine::instance()->stop ();
2505 push_state_to_backend (true);
2510 EngineControl::update_devices_button_clicked ()
2512 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2518 if (backend->update_devices()) {
2519 device_list_changed ();
2524 EngineControl::manage_control_app_sensitivity ()
2526 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2532 string appname = backend->control_app_name();
2534 if (appname.empty()) {
2535 control_app_button.set_sensitive (false);
2537 control_app_button.set_sensitive (true);
2542 EngineControl::set_desired_sample_rate (uint32_t sr)
2544 _desired_sample_rate = sr;
2549 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2551 if (page_num == 0) {
2552 cancel_button->set_sensitive (true);
2553 _measure_midi.reset();
2554 update_sensitivity ();
2556 cancel_button->set_sensitive (false);
2557 ok_button->set_sensitive (false);
2560 if (page_num == midi_tab) {
2562 refresh_midi_display ();
2565 if (page_num == latency_tab) {
2568 if (ARDOUR::AudioEngine::instance()->running()) {
2569 // TODO - mark as 'stopped for latency
2570 ARDOUR_UI::instance()->disconnect_from_engine ();
2574 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2576 /* save any existing latency values */
2578 uint32_t il = (uint32_t) input_latency.get_value ();
2579 uint32_t ol = (uint32_t) input_latency.get_value ();
2581 /* reset to zero so that our new test instance
2582 will be clean of any existing latency measures.
2584 NB. this should really be done by the backend
2585 when stated for latency measurement.
2588 input_latency.set_value (0);
2589 output_latency.set_value (0);
2591 push_state_to_backend (false);
2595 input_latency.set_value (il);
2596 output_latency.set_value (ol);
2599 // This should be done in push_state_to_backend()
2600 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2601 disable_latency_tab ();
2604 enable_latency_tab ();
2608 end_latency_detection ();
2609 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2614 /* latency measurement */
2617 EngineControl::check_audio_latency_measurement ()
2619 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2621 if (mtdm->resolve () < 0) {
2622 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2626 if (mtdm->err () > 0.3) {
2632 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2634 if (sample_rate == 0) {
2635 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2636 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2640 int frames_total = mtdm->del();
2641 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2643 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2644 _("Detected roundtrip latency: "),
2645 frames_total, frames_total * 1000.0f/sample_rate,
2646 _("Systemic latency: "),
2647 extra, extra * 1000.0f/sample_rate);
2651 if (mtdm->err () > 0.2) {
2653 strcat (buf, _("(signal detection error)"));
2659 strcat (buf, _("(inverted - bad wiring)"));
2663 lm_results.set_markup (string_compose (results_markup, buf));
2666 have_lm_results = true;
2667 end_latency_detection ();
2668 lm_use_button.set_sensitive (true);
2676 EngineControl::check_midi_latency_measurement ()
2678 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2680 if (!mididm->have_signal () || mididm->latency () == 0) {
2681 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2686 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2688 if (sample_rate == 0) {
2689 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2690 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2694 ARDOUR::framecnt_t frames_total = mididm->latency();
2695 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2696 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2697 _("Detected roundtrip latency: "),
2698 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2699 _("Systemic latency: "),
2700 extra, extra * 1000.0f / sample_rate);
2704 if (!mididm->ok ()) {
2706 strcat (buf, _("(averaging)"));
2710 if (mididm->deviation () > 50.0) {
2712 strcat (buf, _("(too large jitter)"));
2714 } else if (mididm->deviation () > 10.0) {
2716 strcat (buf, _("(large jitter)"));
2720 have_lm_results = true;
2721 end_latency_detection ();
2722 lm_use_button.set_sensitive (true);
2723 lm_results.set_markup (string_compose (results_markup, buf));
2725 } else if (mididm->processed () > 400) {
2726 have_lm_results = false;
2727 end_latency_detection ();
2728 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2732 lm_results.set_markup (string_compose (results_markup, buf));
2738 EngineControl::start_latency_detection ()
2740 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2741 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2743 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2744 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2745 if (_measure_midi) {
2746 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2748 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2750 lm_measure_label.set_text (_("Cancel"));
2751 have_lm_results = false;
2752 lm_use_button.set_sensitive (false);
2753 lm_input_channel_combo.set_sensitive (false);
2754 lm_output_channel_combo.set_sensitive (false);
2760 EngineControl::end_latency_detection ()
2762 latency_timeout.disconnect ();
2763 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2764 lm_measure_label.set_text (_("Measure"));
2765 if (!have_lm_results) {
2766 lm_use_button.set_sensitive (false);
2768 lm_input_channel_combo.set_sensitive (true);
2769 lm_output_channel_combo.set_sensitive (true);
2774 EngineControl::latency_button_clicked ()
2777 start_latency_detection ();
2779 end_latency_detection ();
2784 EngineControl::use_latency_button_clicked ()
2786 if (_measure_midi) {
2787 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2791 ARDOUR::framecnt_t frames_total = mididm->latency();
2792 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2793 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2794 _measure_midi->input_latency = one_way;
2795 _measure_midi->output_latency = one_way;
2796 notebook.set_current_page (midi_tab);
2798 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2804 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2805 one_way = std::max (0., one_way);
2807 input_latency_adjustment.set_value (one_way);
2808 output_latency_adjustment.set_value (one_way);
2810 /* back to settings page */
2811 notebook.set_current_page (0);
2817 EngineControl::on_delete_event (GdkEventAny* ev)
2819 if (notebook.get_current_page() == 2) {
2820 /* currently on latency tab - be sure to clean up */
2821 end_latency_detection ();
2823 return ArdourDialog::on_delete_event (ev);
2827 EngineControl::engine_running ()
2829 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2832 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2833 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2835 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2836 connect_disconnect_button.show();
2838 started_at_least_once = true;
2839 if (_have_control) {
2840 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2842 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2844 update_sensitivity();
2848 EngineControl::engine_stopped ()
2850 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2853 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2854 connect_disconnect_button.show();
2856 if (_have_control) {
2857 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2859 engine_status.set_markup(X_(""));
2862 update_sensitivity();
2866 EngineControl::device_list_changed ()
2868 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2870 midi_option_changed();
2874 EngineControl::connect_disconnect_click()
2876 if (ARDOUR::AudioEngine::instance()->running()) {
2877 ARDOUR_UI::instance()->disconnect_from_engine ();
2879 ARDOUR_UI::instance()->reconnect_to_engine ();
2884 EngineControl::calibrate_audio_latency ()
2886 _measure_midi.reset ();
2887 have_lm_results = false;
2888 lm_use_button.set_sensitive (false);
2889 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2890 notebook.set_current_page (latency_tab);
2894 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2897 have_lm_results = false;
2898 lm_use_button.set_sensitive (false);
2899 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2900 notebook.set_current_page (latency_tab);
2904 EngineControl::configure_midi_devices ()
2906 notebook.set_current_page (midi_tab);