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.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
61 using namespace Gtkmm2ext;
64 using namespace ARDOUR_UI_UTILS;
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
73 EngineControl::EngineControl ()
74 : ArdourDialog (_("Audio/MIDI Setup"))
77 , input_latency_adjustment (0, 0, 99999, 1)
78 , input_latency (input_latency_adjustment)
79 , output_latency_adjustment (0, 0, 99999, 1)
80 , output_latency (output_latency_adjustment)
81 , input_channels_adjustment (0, 0, 256, 1)
82 , input_channels (input_channels_adjustment)
83 , output_channels_adjustment (0, 0, 256, 1)
84 , output_channels (output_channels_adjustment)
85 , ports_adjustment (128, 8, 1024, 1, 16)
86 , ports_spinner (ports_adjustment)
87 , control_app_button (_("Device Control Panel"))
88 , midi_devices_button (_("Midi Device Setup"))
89 , start_stop_button (_("Stop"))
90 , update_devices_button (_("Refresh Devices"))
91 , lm_measure_label (_("Measure"))
92 , lm_use_button (_("Use results"))
93 , lm_back_button (_("Back to settings ... (ignore results)"))
94 , lm_button_audio (_("Calibrate Audio"))
96 , have_lm_results (false)
98 , midi_back_button (_("Back to settings"))
100 , _desired_sample_rate (0)
101 , started_at_least_once (false)
102 , queue_device_changed (false)
103 , _have_control (true)
106 using namespace Notebook_Helpers;
107 vector<string> backend_names;
109 AttachOptions xopt = AttachOptions (FILL|EXPAND);
112 set_name (X_("AudioMIDISetup"));
114 /* the backend combo is the one thing that is ALWAYS visible */
116 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
118 if (backends.empty()) {
119 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));
121 throw failed_constructor ();
124 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
125 backend_names.push_back ((*b)->name);
128 set_popdown_strings (backend_combo, backend_names);
130 /* setup basic packing characteristics for the table used on the main
131 * tab of the notebook
134 basic_packer.set_spacings (6);
135 basic_packer.set_border_width (12);
136 basic_packer.set_homogeneous (false);
140 basic_hbox.pack_start (basic_packer, false, false);
142 /* latency measurement tab */
144 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
147 lm_table.set_row_spacings (12);
148 lm_table.set_col_spacings (6);
149 lm_table.set_homogeneous (false);
151 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
154 lm_preamble.set_width_chars (60);
155 lm_preamble.set_line_wrap (true);
156 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
158 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
161 Gtk::Label* preamble;
162 preamble = manage (new Label);
163 preamble->set_width_chars (60);
164 preamble->set_line_wrap (true);
165 preamble->set_markup (_("Select two channels below and connect them using a cable."));
167 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
170 label = manage (new Label (_("Output channel")));
171 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
173 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
174 misc_align->add (lm_output_channel_combo);
175 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
178 label = manage (new Label (_("Input channel")));
179 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
181 misc_align = manage (new Alignment (0.0, 0.5));
182 misc_align->add (lm_input_channel_combo);
183 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
186 lm_measure_label.set_padding (10, 10);
187 lm_measure_button.add (lm_measure_label);
188 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
189 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
190 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
192 lm_use_button.set_sensitive (false);
194 /* Increase the default spacing around the labels of these three
200 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
201 l->set_padding (10, 10);
204 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
205 l->set_padding (10, 10);
208 preamble = manage (new Label);
209 preamble->set_width_chars (60);
210 preamble->set_line_wrap (true);
211 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
212 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
215 preamble = manage (new Label);
216 preamble->set_width_chars (60);
217 preamble->set_line_wrap (true);
218 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
219 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
221 ++row; // skip a row in the table
222 ++row; // skip a row in the table
224 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 ++row; // skip a row in the table
227 ++row; // skip a row in the table
229 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
235 lm_vbox.set_border_width (12);
236 lm_vbox.pack_start (lm_table, false, false);
238 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
242 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
243 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
244 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
245 notebook.set_border_width (12);
247 notebook.set_show_tabs (false);
248 notebook.show_all ();
250 notebook.set_name ("SettingsNotebook");
252 /* packup the notebook */
254 get_vbox()->set_border_width (12);
255 get_vbox()->pack_start (notebook);
257 /* need a special function to print "all available channels" when the
258 * channel counts hit zero.
261 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
262 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
264 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
265 midi_devices_button.set_sensitive (false);
266 midi_devices_button.set_name ("generic button");
267 midi_devices_button.set_can_focus(true);
269 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
270 control_app_button.set_name ("generic button");
271 control_app_button.set_can_focus(true);
272 manage_control_app_sensitivity ();
274 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
275 start_stop_button.set_sensitive (false);
276 start_stop_button.set_name ("generic button");
277 start_stop_button.set_can_focus(true);
279 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
280 update_devices_button.set_sensitive (false);
281 update_devices_button.set_name ("generic button");
282 update_devices_button.set_can_focus(true);
284 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
285 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
287 /* Pick up any existing audio setup configuration, if appropriate */
289 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
291 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
292 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
293 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
294 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
297 if (!set_state (*audio_setup)) {
298 set_default_state ();
301 set_default_state ();
304 connect_changed_signals ();
306 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
308 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
309 connect_disconnect_button.set_no_show_all();
314 EngineControl::connect_changed_signals ()
316 backend_combo_connection = backend_combo.signal_changed ().connect (
317 sigc::mem_fun (*this, &EngineControl::backend_changed));
318 driver_combo_connection = driver_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::driver_changed));
320 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
322 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
323 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
324 device_combo_connection = device_combo.signal_changed ().connect (
325 sigc::mem_fun (*this, &EngineControl::device_changed));
326 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
327 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
329 input_device_combo_connection = input_device_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::input_device_changed));
331 output_device_combo_connection = output_device_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::output_device_changed));
334 input_latency_connection = input_latency.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::parameter_changed));
336 output_latency_connection = output_latency.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::parameter_changed));
338 input_channels_connection = input_channels.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::parameter_changed));
340 output_channels_connection = output_channels.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::parameter_changed));
345 EngineControl::block_changed_signals ()
347 if (block_signals++ == 0) {
348 DEBUG_ECONTROL ("Blocking changed signals");
349 backend_combo_connection.block ();
350 driver_combo_connection.block ();
351 sample_rate_combo_connection.block ();
352 buffer_size_combo_connection.block ();
353 device_combo_connection.block ();
354 input_device_combo_connection.block ();
355 output_device_combo_connection.block ();
356 midi_option_combo_connection.block ();
357 input_latency_connection.block ();
358 output_latency_connection.block ();
359 input_channels_connection.block ();
360 output_channels_connection.block ();
365 EngineControl::unblock_changed_signals ()
367 if (--block_signals == 0) {
368 DEBUG_ECONTROL ("Unblocking changed signals");
369 backend_combo_connection.unblock ();
370 driver_combo_connection.unblock ();
371 sample_rate_combo_connection.unblock ();
372 buffer_size_combo_connection.unblock ();
373 device_combo_connection.unblock ();
374 input_device_combo_connection.unblock ();
375 output_device_combo_connection.unblock ();
376 midi_option_combo_connection.unblock ();
377 input_latency_connection.unblock ();
378 output_latency_connection.unblock ();
379 input_channels_connection.unblock ();
380 output_channels_connection.unblock ();
384 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
385 const std::string& reason)
386 : ec (engine_control)
389 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
390 ec.block_changed_signals ();
393 EngineControl::SignalBlocker::~SignalBlocker ()
395 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
396 ec.unblock_changed_signals ();
400 EngineControl::on_show ()
402 ArdourDialog::on_show ();
403 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
404 // re-check _have_control (jackd running) see #6041
408 ok_button->grab_focus();
412 EngineControl::on_response (int response_id)
414 ArdourDialog::on_response (response_id);
416 switch (response_id) {
418 if (push_state_to_backend (true) != 0) {
423 #ifdef PLATFORM_WINDOWS
425 // But if there's no session open, this can produce
426 // a long gap when nothing appears to be happening.
427 // Let's show the splash image while we're waiting.
428 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
429 if ( ARDOUR_UI::instance() ) {
430 if ( !ARDOUR_UI::instance()->session_loaded ) {
431 ARDOUR_UI::instance()->show_splash();
437 case RESPONSE_DELETE_EVENT:
440 ev.type = GDK_BUTTON_PRESS;
442 on_delete_event ((GdkEventAny*) &ev);
451 EngineControl::build_notebook ()
454 AttachOptions xopt = AttachOptions (FILL|EXPAND);
456 /* clear the table */
458 Gtkmm2ext::container_clear (basic_vbox);
459 Gtkmm2ext::container_clear (basic_packer);
461 if (control_app_button.get_parent()) {
462 control_app_button.get_parent()->remove (control_app_button);
465 label = manage (left_aligned_label (_("Audio System:")));
466 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
467 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
469 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
470 engine_status.show();
472 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
473 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
475 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
476 lm_button_audio.set_name ("generic button");
477 lm_button_audio.set_can_focus(true);
480 build_full_control_notebook ();
482 build_no_control_notebook ();
485 basic_vbox.pack_start (basic_hbox, false, false);
488 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
489 basic_vbox.show_all ();
494 EngineControl::build_full_control_notebook ()
496 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
499 using namespace Notebook_Helpers;
501 vector<string> strings;
502 AttachOptions xopt = AttachOptions (FILL|EXPAND);
503 int row = 1; // row zero == backend combo
505 /* start packing it up */
507 if (backend->requires_driver_selection()) {
508 label = manage (left_aligned_label (_("Driver:")));
509 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
510 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
514 if (backend->use_separate_input_and_output_devices()) {
515 label = manage (left_aligned_label (_("Input Device:")));
516 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
517 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
519 label = manage (left_aligned_label (_("Output Device:")));
520 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
521 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
523 // reset so it isn't used in state comparisons
524 device_combo.set_active_text ("");
526 label = manage (left_aligned_label (_("Device:")));
527 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
528 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
530 // reset these so they don't get used in state comparisons
531 input_device_combo.set_active_text ("");
532 output_device_combo.set_active_text ("");
535 label = manage (left_aligned_label (_("Sample rate:")));
536 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
537 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
541 label = manage (left_aligned_label (_("Buffer size:")));
542 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
543 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
544 buffer_size_duration_label.set_alignment (0.0); /* left-align */
545 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
547 /* button spans 2 rows */
549 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
552 input_channels.set_name ("InputChannels");
553 input_channels.set_flags (Gtk::CAN_FOCUS);
554 input_channels.set_digits (0);
555 input_channels.set_wrap (false);
556 output_channels.set_editable (true);
558 if (!ARDOUR::Profile->get_mixbus()) {
559 label = manage (left_aligned_label (_("Input Channels:")));
560 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
561 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
565 output_channels.set_name ("OutputChannels");
566 output_channels.set_flags (Gtk::CAN_FOCUS);
567 output_channels.set_digits (0);
568 output_channels.set_wrap (false);
569 output_channels.set_editable (true);
571 if (!ARDOUR::Profile->get_mixbus()) {
572 label = manage (left_aligned_label (_("Output Channels:")));
573 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
574 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
578 input_latency.set_name ("InputLatency");
579 input_latency.set_flags (Gtk::CAN_FOCUS);
580 input_latency.set_digits (0);
581 input_latency.set_wrap (false);
582 input_latency.set_editable (true);
584 label = manage (left_aligned_label (_("Hardware input latency:")));
585 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
586 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
587 label = manage (left_aligned_label (_("samples")));
588 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
591 output_latency.set_name ("OutputLatency");
592 output_latency.set_flags (Gtk::CAN_FOCUS);
593 output_latency.set_digits (0);
594 output_latency.set_wrap (false);
595 output_latency.set_editable (true);
597 label = manage (left_aligned_label (_("Hardware output latency:")));
598 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
599 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
600 label = manage (left_aligned_label (_("samples")));
601 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
603 /* button spans 2 rows */
605 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
608 label = manage (left_aligned_label (_("MIDI System:")));
609 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
610 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
611 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
612 /* Currently the only backend with dedicated Midi setup is ALSA.
613 * lot of people complain that this is greyed out
614 * "I can't use MIDI, the setup is greyed out"
616 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
622 EngineControl::build_no_control_notebook ()
624 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
627 using namespace Notebook_Helpers;
629 vector<string> strings;
630 AttachOptions xopt = AttachOptions (FILL|EXPAND);
631 int row = 1; // row zero == backend combo
632 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
634 label = manage (new Label);
635 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
636 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
639 if (backend->can_change_sample_rate_when_running()) {
640 label = manage (left_aligned_label (_("Sample rate:")));
641 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
642 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
646 if (backend->can_change_buffer_size_when_running()) {
647 label = manage (left_aligned_label (_("Buffer size:")));
648 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
649 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
650 buffer_size_duration_label.set_alignment (0.0); /* left-align */
651 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
655 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
659 EngineControl::~EngineControl ()
661 ignore_changes = true;
665 EngineControl::disable_latency_tab ()
667 vector<string> empty;
668 set_popdown_strings (lm_output_channel_combo, empty);
669 set_popdown_strings (lm_input_channel_combo, empty);
670 lm_measure_button.set_sensitive (false);
671 lm_use_button.set_sensitive (false);
675 EngineControl::enable_latency_tab ()
677 vector<string> outputs;
678 vector<string> inputs;
680 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
681 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
682 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
684 if (!ARDOUR::AudioEngine::instance()->running()) {
685 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
686 notebook.set_current_page (0);
690 else if (inputs.empty() || outputs.empty()) {
691 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
692 notebook.set_current_page (0);
697 lm_back_button_signal.disconnect();
699 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
702 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
706 set_popdown_strings (lm_output_channel_combo, outputs);
707 lm_output_channel_combo.set_active_text (outputs.front());
708 lm_output_channel_combo.set_sensitive (true);
710 set_popdown_strings (lm_input_channel_combo, inputs);
711 lm_input_channel_combo.set_active_text (inputs.front());
712 lm_input_channel_combo.set_sensitive (true);
714 lm_measure_button.set_sensitive (true);
718 EngineControl::setup_midi_tab_for_backend ()
720 string backend = backend_combo.get_active_text ();
722 Gtkmm2ext::container_clear (midi_vbox);
724 midi_vbox.set_border_width (12);
725 midi_device_table.set_border_width (12);
727 if (backend == "JACK") {
728 setup_midi_tab_for_jack ();
731 midi_vbox.pack_start (midi_device_table, true, true);
732 midi_vbox.pack_start (midi_back_button, false, false);
733 midi_vbox.show_all ();
737 EngineControl::update_sensitivity ()
739 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
741 ok_button->set_sensitive (false);
742 start_stop_button.set_sensitive (false);
747 size_t devices_available = 0;
749 if (backend->use_separate_input_and_output_devices ()) {
750 devices_available += get_popdown_string_count (input_device_combo);
751 devices_available += get_popdown_string_count (output_device_combo);
753 devices_available += get_popdown_string_count (device_combo);
756 if (devices_available == 0) {
758 input_latency.set_sensitive (false);
759 output_latency.set_sensitive (false);
760 input_channels.set_sensitive (false);
761 output_channels.set_sensitive (false);
763 input_latency.set_sensitive (true);
764 output_latency.set_sensitive (true);
765 input_channels.set_sensitive (true);
766 output_channels.set_sensitive (true);
769 if (get_popdown_string_count (buffer_size_combo) > 0) {
770 if (!ARDOUR::AudioEngine::instance()->running()) {
771 buffer_size_combo.set_sensitive (valid);
772 } else if (backend->can_change_sample_rate_when_running()) {
773 buffer_size_combo.set_sensitive (valid || !_have_control);
777 * Currently there is no way to manually stop the
778 * engine in order to re-configure it.
779 * This needs to remain sensitive for now.
781 * (it's also handy to implicily
782 * re-start the engine)
784 buffer_size_combo.set_sensitive (true);
786 buffer_size_combo.set_sensitive (false);
790 buffer_size_combo.set_sensitive (false);
794 if (get_popdown_string_count (sample_rate_combo) > 0) {
795 if (!ARDOUR::AudioEngine::instance()->running()) {
796 sample_rate_combo.set_sensitive (true);
798 sample_rate_combo.set_sensitive (false);
801 sample_rate_combo.set_sensitive (false);
806 start_stop_button.set_sensitive(true);
807 start_stop_button.show();
808 if (ARDOUR::AudioEngine::instance()->running()) {
809 start_stop_button.set_text("Stop");
810 update_devices_button.set_sensitive(false);
812 if (backend->can_request_update_devices()) {
813 update_devices_button.show();
815 update_devices_button.hide();
817 start_stop_button.set_text("Start");
818 update_devices_button.set_sensitive(true);
821 update_devices_button.set_sensitive(false);
822 update_devices_button.hide();
823 start_stop_button.set_sensitive(false);
824 start_stop_button.hide();
827 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
828 input_device_combo.set_sensitive (false);
829 output_device_combo.set_sensitive (false);
830 device_combo.set_sensitive (false);
831 driver_combo.set_sensitive (false);
833 input_device_combo.set_sensitive (true);
834 output_device_combo.set_sensitive (true);
835 device_combo.set_sensitive (true);
836 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
837 driver_combo.set_sensitive (true);
839 driver_combo.set_sensitive (false);
843 if (valid || !_have_control) {
844 ok_button->set_sensitive (true);
846 ok_button->set_sensitive (false);
851 EngineControl::setup_midi_tab_for_jack ()
856 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
858 device->input_latency = a->get_value();
860 device->output_latency = a->get_value();
865 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
866 b->set_active (!b->get_active());
867 device->enabled = b->get_active();
868 refresh_midi_display(device->name);
872 EngineControl::refresh_midi_display (std::string focus)
874 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
878 AttachOptions xopt = AttachOptions (FILL|EXPAND);
881 Gtkmm2ext::container_clear (midi_device_table);
883 midi_device_table.set_spacings (6);
885 l = manage (new Label);
886 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
887 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
888 l->set_alignment (0.5, 0.5);
892 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
893 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
894 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
895 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
897 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
898 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
899 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
900 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
903 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
908 bool enabled = (*p)->enabled;
910 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
911 m->set_name ("midi device");
912 m->set_can_focus (Gtk::CAN_FOCUS);
913 m->add_events (Gdk::BUTTON_RELEASE_MASK);
914 m->set_active (enabled);
915 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
916 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
917 if ((*p)->name == focus) {
921 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
922 s = manage (new Gtk::SpinButton (*a));
923 a->set_value ((*p)->input_latency);
924 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
925 s->set_sensitive (_can_set_midi_latencies && enabled);
926 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
928 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
929 s = manage (new Gtk::SpinButton (*a));
930 a->set_value ((*p)->output_latency);
931 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
932 s->set_sensitive (_can_set_midi_latencies && enabled);
933 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
935 b = manage (new Button (_("Calibrate")));
936 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
937 b->set_sensitive (_can_set_midi_latencies && enabled);
938 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
945 EngineControl::backend_changed ()
947 SignalBlocker blocker (*this, "backend_changed");
948 string backend_name = backend_combo.get_active_text();
949 boost::shared_ptr<ARDOUR::AudioBackend> backend;
951 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
952 /* eh? setting the backend failed... how ? */
953 /* A: stale config contains a backend that does not exist in current build */
957 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
959 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
962 setup_midi_tab_for_backend ();
963 _midi_devices.clear();
965 if (backend->requires_driver_selection()) {
966 if (set_driver_popdown_strings ()) {
970 /* this will change the device text which will cause a call to
971 * device changed which will set up parameters
976 update_midi_options ();
978 connect_disconnect_button.hide();
980 midi_option_changed();
982 started_at_least_once = false;
984 /* changing the backend implies stopping the engine
985 * ARDOUR::AudioEngine() may or may not emit this signal
986 * depending on previous engine state
988 engine_stopped (); // set "active/inactive"
990 if (!ignore_changes) {
991 maybe_display_saved_state ();
996 EngineControl::update_midi_options ()
998 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
999 vector<string> midi_options = backend->enumerate_midi_options();
1001 if (midi_options.size() == 1) {
1002 /* only contains the "none" option */
1003 midi_option_combo.set_sensitive (false);
1005 if (_have_control) {
1006 set_popdown_strings (midi_option_combo, midi_options);
1007 midi_option_combo.set_active_text (midi_options.front());
1008 midi_option_combo.set_sensitive (true);
1010 midi_option_combo.set_sensitive (false);
1016 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1018 if (ARDOUR::Profile->get_mixbus()) {
1022 uint32_t cnt = (uint32_t) sb->get_value();
1024 sb->set_text (_("all available channels"));
1027 snprintf (buf, sizeof (buf), "%d", cnt);
1033 // @return true if there are drivers available
1035 EngineControl::set_driver_popdown_strings ()
1037 DEBUG_ECONTROL ("set_driver_popdown_strings");
1038 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1039 vector<string> drivers = backend->enumerate_drivers();
1041 if (drivers.empty ()) {
1042 // This is an error...?
1046 string current_driver = backend->driver_name ();
1048 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1050 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1053 current_driver = drivers.front ();
1056 set_popdown_strings (driver_combo, drivers);
1058 string_compose ("driver_combo.set_active_text: %1", current_driver));
1059 driver_combo.set_active_text (current_driver);
1064 EngineControl::get_default_device(const string& current_device_name,
1065 const vector<string>& available_devices)
1067 // If the current device is available, use it as default
1068 if (std::find (available_devices.begin (),
1069 available_devices.end (),
1070 current_device_name) != available_devices.end ()) {
1072 return current_device_name;
1075 using namespace ARDOUR;
1077 string default_device_name =
1078 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1080 vector<string>::const_iterator i;
1082 // If there is a "Default" device available, use it
1083 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1084 if (*i == default_device_name) {
1089 string none_device_name =
1090 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1092 // Use the first device that isn't "None"
1093 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1094 if (*i != none_device_name) {
1099 // Use "None" if there are no other available
1100 return available_devices.front();
1103 // @return true if there are devices available
1105 EngineControl::set_device_popdown_strings ()
1107 DEBUG_ECONTROL ("set_device_popdown_strings");
1108 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1109 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1111 /* NOTE: Ardour currently does not display the "available" field of the
1114 * Doing so would require a different GUI widget than the combo
1115 * box/popdown that we currently use, since it has no way to list
1116 * items that are not selectable. Something more like a popup menu,
1117 * which could have unselectable items, would be appropriate.
1120 vector<string> available_devices;
1122 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1123 available_devices.push_back (i->name);
1126 if (available_devices.empty ()) {
1130 set_popdown_strings (device_combo, available_devices);
1132 std::string default_device =
1133 get_default_device(backend->device_name(), available_devices);
1136 string_compose ("set device_combo active text: %1", default_device));
1138 device_combo.set_active_text(default_device);
1142 // @return true if there are input devices available
1144 EngineControl::set_input_device_popdown_strings ()
1146 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1147 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1148 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1150 vector<string> available_devices;
1152 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1153 available_devices.push_back (i->name);
1156 if (available_devices.empty()) {
1160 set_popdown_strings (input_device_combo, available_devices);
1162 std::string default_device =
1163 get_default_device(backend->input_device_name(), available_devices);
1166 string_compose ("set input_device_combo active text: %1", default_device));
1167 input_device_combo.set_active_text(default_device);
1171 // @return true if there are output devices available
1173 EngineControl::set_output_device_popdown_strings ()
1175 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1176 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1177 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1179 vector<string> available_devices;
1181 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1182 available_devices.push_back (i->name);
1185 if (available_devices.empty()) {
1189 set_popdown_strings (output_device_combo, available_devices);
1191 std::string default_device =
1192 get_default_device(backend->output_device_name(), available_devices);
1195 string_compose ("set output_device_combo active text: %1", default_device));
1196 output_device_combo.set_active_text(default_device);
1201 EngineControl::list_devices ()
1203 DEBUG_ECONTROL ("list_devices");
1204 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1207 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1209 bool devices_available = false;
1211 if (backend->use_separate_input_and_output_devices ()) {
1212 bool input_devices_available = set_input_device_popdown_strings ();
1213 bool output_devices_available = set_output_device_popdown_strings ();
1214 devices_available = input_devices_available || output_devices_available;
1216 devices_available = set_device_popdown_strings ();
1219 if (devices_available) {
1222 device_combo.clear();
1223 input_device_combo.clear();
1224 output_device_combo.clear();
1226 update_sensitivity ();
1230 EngineControl::driver_changed ()
1232 SignalBlocker blocker (*this, "driver_changed");
1233 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1236 backend->set_driver (driver_combo.get_active_text());
1239 if (!ignore_changes) {
1240 maybe_display_saved_state ();
1245 EngineControl::get_sample_rates_for_all_devices ()
1247 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1248 ARDOUR::AudioEngine::instance ()->current_backend ();
1249 vector<float> all_rates;
1251 if (backend->use_separate_input_and_output_devices ()) {
1252 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1254 all_rates = backend->available_sample_rates (get_device_name ());
1260 EngineControl::get_default_sample_rates ()
1262 vector<float> rates;
1263 rates.push_back (8000.0f);
1264 rates.push_back (16000.0f);
1265 rates.push_back (32000.0f);
1266 rates.push_back (44100.0f);
1267 rates.push_back (48000.0f);
1268 rates.push_back (88200.0f);
1269 rates.push_back (96000.0f);
1270 rates.push_back (192000.0f);
1271 rates.push_back (384000.0f);
1276 EngineControl::set_samplerate_popdown_strings ()
1278 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1279 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1284 if (_have_control) {
1285 sr = get_sample_rates_for_all_devices ();
1287 sr = get_default_sample_rates ();
1290 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1291 s.push_back (rate_as_string (*x));
1292 if (*x == _desired_sample_rate) {
1297 set_popdown_strings (sample_rate_combo, s);
1300 if (desired.empty ()) {
1301 float new_active_sr = backend->default_sample_rate ();
1303 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1304 new_active_sr = sr.front ();
1307 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1309 sample_rate_combo.set_active_text (desired);
1313 update_sensitivity ();
1317 EngineControl::get_buffer_sizes_for_all_devices ()
1319 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1320 ARDOUR::AudioEngine::instance ()->current_backend ();
1321 vector<uint32_t> all_sizes;
1323 if (backend->use_separate_input_and_output_devices ()) {
1324 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1326 all_sizes = backend->available_buffer_sizes (get_device_name ());
1332 EngineControl::get_default_buffer_sizes ()
1334 vector<uint32_t> sizes;
1335 sizes.push_back (8);
1336 sizes.push_back (16);
1337 sizes.push_back (32);
1338 sizes.push_back (64);
1339 sizes.push_back (128);
1340 sizes.push_back (256);
1341 sizes.push_back (512);
1342 sizes.push_back (1024);
1343 sizes.push_back (2048);
1344 sizes.push_back (4096);
1345 sizes.push_back (8192);
1350 EngineControl::set_buffersize_popdown_strings ()
1352 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1353 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1354 vector<uint32_t> bs;
1357 if (_have_control) {
1358 bs = get_buffer_sizes_for_all_devices ();
1359 } else if (backend->can_change_buffer_size_when_running()) {
1360 bs = get_default_buffer_sizes ();
1363 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1364 s.push_back (bufsize_as_string (*x));
1367 uint32_t previous_size = 0;
1368 if (!buffer_size_combo.get_active_text().empty()) {
1369 previous_size = get_buffer_size ();
1372 set_popdown_strings (buffer_size_combo, s);
1376 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1377 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1380 buffer_size_combo.set_active_text(s.front());
1382 uint32_t period = backend->buffer_size();
1383 if (0 == period && backend->use_separate_input_and_output_devices()) {
1384 period = backend->default_buffer_size(get_input_device_name());
1386 if (0 == period && backend->use_separate_input_and_output_devices()) {
1387 period = backend->default_buffer_size(get_output_device_name());
1389 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1390 period = backend->default_buffer_size(get_device_name());
1393 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1395 show_buffer_duration ();
1397 update_sensitivity ();
1401 EngineControl::device_changed ()
1403 SignalBlocker blocker (*this, "device_changed");
1404 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1407 string device_name_in;
1408 string device_name_out; // only used if backend support separate I/O devices
1410 if (backend->use_separate_input_and_output_devices()) {
1411 device_name_in = get_input_device_name ();
1412 device_name_out = get_output_device_name ();
1414 device_name_in = get_device_name ();
1417 /* we set the backend-device to query various device related intormation.
1418 * This has the side effect that backend->device_name() will match
1419 * the device_name and 'change_device' will never be true.
1420 * so work around this by setting...
1422 if (backend->use_separate_input_and_output_devices()) {
1423 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1424 queue_device_changed = true;
1427 if (device_name_in != backend->device_name()) {
1428 queue_device_changed = true;
1432 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1433 if (backend->use_separate_input_and_output_devices()) {
1434 backend->set_input_device_name (device_name_in);
1435 backend->set_output_device_name (device_name_out);
1437 backend->set_device_name(device_name_in);
1441 /* don't allow programmatic change to combos to cause a
1442 recursive call to this method.
1444 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1446 set_samplerate_popdown_strings ();
1447 set_buffersize_popdown_strings ();
1449 /* TODO set min + max channel counts here */
1451 manage_control_app_sensitivity ();
1454 /* pick up any saved state for this device */
1456 if (!ignore_changes) {
1457 maybe_display_saved_state ();
1462 EngineControl::input_device_changed ()
1464 DEBUG_ECONTROL ("input_device_changed");
1469 EngineControl::output_device_changed ()
1471 DEBUG_ECONTROL ("output_device_changed");
1476 EngineControl::bufsize_as_string (uint32_t sz)
1478 /* Translators: "samples" is always plural here, so no
1479 need for plural+singular forms.
1482 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1487 EngineControl::sample_rate_changed ()
1489 DEBUG_ECONTROL ("sample_rate_changed");
1490 /* reset the strings for buffer size to show the correct msec value
1491 (reflecting the new sample rate).
1494 show_buffer_duration ();
1499 EngineControl::buffer_size_changed ()
1501 DEBUG_ECONTROL ("buffer_size_changed");
1502 show_buffer_duration ();
1506 EngineControl::show_buffer_duration ()
1508 DEBUG_ECONTROL ("show_buffer_duration");
1509 /* buffer sizes - convert from just samples to samples + msecs for
1510 * the displayed string
1513 string bs_text = buffer_size_combo.get_active_text ();
1514 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1515 uint32_t rate = get_rate();
1517 /* Developers: note the hard-coding of a double buffered model
1518 in the (2 * samples) computation of latency. we always start
1519 the audiobackend in this configuration.
1521 /* note to jack1 developers: ardour also always starts the engine
1522 * in async mode (no jack2 --sync option) which adds an extra cycle
1523 * of latency with jack2 (and *3 would be correct)
1524 * The value can also be wrong if jackd is started externally..
1526 * At the time of writing the ALSA backend always uses double-buffering *2,
1527 * The Dummy backend *1, and who knows what ASIO really does :)
1529 * So just display the period size, that's also what
1530 * ARDOUR_UI::update_sample_rate() does for the status bar.
1531 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1532 * but still, that's the buffer period, not [round-trip] latency)
1535 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1536 buffer_size_duration_label.set_text (buf);
1540 EngineControl::midi_option_changed ()
1542 DEBUG_ECONTROL ("midi_option_changed");
1543 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1546 backend->set_midi_option (get_midi_option());
1548 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1550 //_midi_devices.clear(); // TODO merge with state-saved settings..
1551 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1552 std::vector<MidiDeviceSettings> new_devices;
1554 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1555 MidiDeviceSettings mds = find_midi_device (i->name);
1556 if (i->available && !mds) {
1557 uint32_t input_latency = 0;
1558 uint32_t output_latency = 0;
1559 if (_can_set_midi_latencies) {
1560 input_latency = backend->systemic_midi_input_latency (i->name);
1561 output_latency = backend->systemic_midi_output_latency (i->name);
1563 bool enabled = backend->midi_device_enabled (i->name);
1564 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1565 new_devices.push_back (ptr);
1566 } else if (i->available) {
1567 new_devices.push_back (mds);
1570 _midi_devices = new_devices;
1572 if (_midi_devices.empty()) {
1573 midi_devices_button.set_sensitive (false);
1575 midi_devices_button.set_sensitive (true);
1580 EngineControl::parameter_changed ()
1584 EngineControl::State
1585 EngineControl::get_matching_state (
1586 const string& backend,
1587 const string& driver,
1588 const string& device)
1590 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1591 if ((*i)->backend == backend &&
1592 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1600 EngineControl::State
1601 EngineControl::get_matching_state (
1602 const string& backend,
1603 const string& driver,
1604 const string& input_device,
1605 const string& output_device)
1607 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1608 if ((*i)->backend == backend &&
1609 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1617 EngineControl::State
1618 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1620 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1623 if (backend->use_separate_input_and_output_devices ()) {
1624 return get_matching_state (backend_combo.get_active_text(),
1625 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1626 input_device_combo.get_active_text(),
1627 output_device_combo.get_active_text());
1629 return get_matching_state (backend_combo.get_active_text(),
1630 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1631 device_combo.get_active_text());
1635 return get_matching_state (backend_combo.get_active_text(),
1637 device_combo.get_active_text());
1640 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1641 const EngineControl::State& state2)
1643 if (state1->backend == state2->backend &&
1644 state1->driver == state2->driver &&
1645 state1->device == state2->device &&
1646 state1->input_device == state2->input_device &&
1647 state1->output_device == state2->output_device) {
1653 EngineControl::State
1654 EngineControl::save_state ()
1658 if (!_have_control) {
1659 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1663 state.reset(new StateStruct);
1664 state->backend = get_backend ();
1666 state.reset(new StateStruct);
1667 store_state (state);
1670 for (StateList::iterator i = states.begin(); i != states.end();) {
1671 if (equivalent_states (*i, state)) {
1672 i = states.erase(i);
1678 states.push_back (state);
1684 EngineControl::store_state (State state)
1686 state->backend = get_backend ();
1687 state->driver = get_driver ();
1688 state->device = get_device_name ();
1689 state->input_device = get_input_device_name ();
1690 state->output_device = get_output_device_name ();
1691 state->sample_rate = get_rate ();
1692 state->buffer_size = get_buffer_size ();
1693 state->input_latency = get_input_latency ();
1694 state->output_latency = get_output_latency ();
1695 state->input_channels = get_input_channels ();
1696 state->output_channels = get_output_channels ();
1697 state->midi_option = get_midi_option ();
1698 state->midi_devices = _midi_devices;
1702 EngineControl::maybe_display_saved_state ()
1704 if (!_have_control) {
1708 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1711 DEBUG_ECONTROL ("Restoring saved state");
1712 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1714 if (!_desired_sample_rate) {
1715 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1717 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1718 /* call this explicitly because we're ignoring changes to
1719 the controls at this point.
1721 show_buffer_duration ();
1722 input_latency.set_value (state->input_latency);
1723 output_latency.set_value (state->output_latency);
1725 if (!state->midi_option.empty()) {
1726 midi_option_combo.set_active_text (state->midi_option);
1727 _midi_devices = state->midi_devices;
1730 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1735 EngineControl::get_state ()
1737 LocaleGuard lg (X_("C"));
1739 XMLNode* root = new XMLNode ("AudioMIDISetup");
1742 if (!states.empty()) {
1743 XMLNode* state_nodes = new XMLNode ("EngineStates");
1745 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1747 XMLNode* node = new XMLNode ("State");
1749 node->add_property ("backend", (*i)->backend);
1750 node->add_property ("driver", (*i)->driver);
1751 node->add_property ("device", (*i)->device);
1752 node->add_property ("input-device", (*i)->input_device);
1753 node->add_property ("output-device", (*i)->output_device);
1754 node->add_property ("sample-rate", (*i)->sample_rate);
1755 node->add_property ("buffer-size", (*i)->buffer_size);
1756 node->add_property ("input-latency", (*i)->input_latency);
1757 node->add_property ("output-latency", (*i)->output_latency);
1758 node->add_property ("input-channels", (*i)->input_channels);
1759 node->add_property ("output-channels", (*i)->output_channels);
1760 node->add_property ("active", (*i)->active ? "yes" : "no");
1761 node->add_property ("midi-option", (*i)->midi_option);
1763 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1764 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1765 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1766 midi_device_stuff->add_property (X_("name"), (*p)->name);
1767 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1768 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1769 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1770 midi_devices->add_child_nocopy (*midi_device_stuff);
1772 node->add_child_nocopy (*midi_devices);
1774 state_nodes->add_child_nocopy (*node);
1777 root->add_child_nocopy (*state_nodes);
1784 EngineControl::set_default_state ()
1786 vector<string> backend_names;
1787 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1789 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1790 backend_names.push_back ((*b)->name);
1792 backend_combo.set_active_text (backend_names.front());
1794 // We could set default backends per platform etc here
1800 EngineControl::set_state (const XMLNode& root)
1802 XMLNodeList clist, cclist;
1803 XMLNodeConstIterator citer, cciter;
1805 XMLNode* grandchild;
1806 XMLProperty* prop = NULL;
1808 fprintf (stderr, "EngineControl::set_state\n");
1810 if (root.name() != "AudioMIDISetup") {
1814 clist = root.children();
1818 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1822 if (child->name() != "EngineStates") {
1826 cclist = child->children();
1828 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1829 State state (new StateStruct);
1831 grandchild = *cciter;
1833 if (grandchild->name() != "State") {
1837 if ((prop = grandchild->property ("backend")) == 0) {
1840 state->backend = prop->value ();
1842 if ((prop = grandchild->property ("driver")) == 0) {
1845 state->driver = prop->value ();
1847 if ((prop = grandchild->property ("device")) == 0) {
1850 state->device = prop->value ();
1852 if ((prop = grandchild->property ("input-device")) == 0) {
1855 state->input_device = prop->value ();
1857 if ((prop = grandchild->property ("output-device")) == 0) {
1860 state->output_device = prop->value ();
1862 if ((prop = grandchild->property ("sample-rate")) == 0) {
1865 state->sample_rate = atof (prop->value ());
1867 if ((prop = grandchild->property ("buffer-size")) == 0) {
1870 state->buffer_size = atoi (prop->value ());
1872 if ((prop = grandchild->property ("input-latency")) == 0) {
1875 state->input_latency = atoi (prop->value ());
1877 if ((prop = grandchild->property ("output-latency")) == 0) {
1880 state->output_latency = atoi (prop->value ());
1882 if ((prop = grandchild->property ("input-channels")) == 0) {
1885 state->input_channels = atoi (prop->value ());
1887 if ((prop = grandchild->property ("output-channels")) == 0) {
1890 state->output_channels = atoi (prop->value ());
1892 if ((prop = grandchild->property ("active")) == 0) {
1895 state->active = string_is_affirmative (prop->value ());
1897 if ((prop = grandchild->property ("midi-option")) == 0) {
1900 state->midi_option = prop->value ();
1902 state->midi_devices.clear();
1904 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1905 const XMLNodeList mnc = midinode->children();
1906 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1907 if ((*n)->property (X_("name")) == 0
1908 || (*n)->property (X_("enabled")) == 0
1909 || (*n)->property (X_("input-latency")) == 0
1910 || (*n)->property (X_("output-latency")) == 0
1915 MidiDeviceSettings ptr (new MidiDeviceSetting(
1916 (*n)->property (X_("name"))->value (),
1917 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1918 atoi ((*n)->property (X_("input-latency"))->value ()),
1919 atoi ((*n)->property (X_("output-latency"))->value ())
1921 state->midi_devices.push_back (ptr);
1926 /* remove accumulated duplicates (due to bug in ealier version)
1927 * this can be removed again before release
1929 for (StateList::iterator i = states.begin(); i != states.end();) {
1930 if ((*i)->backend == state->backend &&
1931 (*i)->driver == state->driver &&
1932 (*i)->device == state->device) {
1933 i = states.erase(i);
1940 states.push_back (state);
1944 /* now see if there was an active state and switch the setup to it */
1946 // purge states of backend that are not available in this built
1947 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1948 vector<std::string> backend_names;
1950 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1951 backend_names.push_back((*i)->name);
1953 for (StateList::iterator i = states.begin(); i != states.end();) {
1954 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1955 i = states.erase(i);
1961 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1964 return set_current_state (*i);
1971 EngineControl::set_current_state (const State& state)
1973 DEBUG_ECONTROL ("set_current_state");
1975 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1977 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1978 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
1979 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1980 // this shouldn't happen as the invalid backend names should have been
1981 // removed from the list of states.
1985 // now reflect the change in the backend in the GUI so backend_changed will
1986 // do the right thing
1987 backend_combo.set_active_text (state->backend);
1989 if (!state->driver.empty ()) {
1990 if (!backend->requires_driver_selection ()) {
1991 DEBUG_ECONTROL ("Backend should require driver selection");
1992 // A backend has changed from having driver selection to not having
1993 // it or someone has been manually editing a config file and messed
1998 if (backend->set_driver (state->driver) != 0) {
1999 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2000 // Driver names for a backend have changed and the name in the
2001 // config file is now invalid or support for driver is no longer
2002 // included in the backend
2005 // no need to set the driver_combo as backend_changed will use
2006 // backend->driver_name to set the active driver
2009 if (!state->device.empty ()) {
2010 if (backend->set_device_name (state->device) != 0) {
2012 string_compose ("Unable to set device name %1", state->device));
2013 // device is no longer available on the system
2016 // no need to set active device as it will be picked up in
2017 // via backend_changed ()/set_device_popdown_strings
2020 // backend supports separate input/output devices
2021 if (backend->set_input_device_name (state->input_device) != 0) {
2022 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2023 state->input_device));
2024 // input device is no longer available on the system
2028 if (backend->set_output_device_name (state->output_device) != 0) {
2029 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2030 state->input_device));
2031 // output device is no longer available on the system
2034 // no need to set active devices as it will be picked up in via
2035 // backend_changed ()/set_*_device_popdown_strings
2040 // Now restore the state of the rest of the controls
2042 // We don't use a SignalBlocker as set_current_state is currently only
2043 // called from set_state before any signals are connected. If at some point
2044 // a more general named state mechanism is implemented and
2045 // set_current_state is called while signals are connected then a
2046 // SignalBlocker will need to be instantiated before setting these.
2048 device_combo.set_active_text (state->device);
2049 input_device_combo.set_active_text (state->input_device);
2050 output_device_combo.set_active_text (state->output_device);
2051 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2052 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2053 input_latency.set_value (state->input_latency);
2054 output_latency.set_value (state->output_latency);
2055 midi_option_combo.set_active_text (state->midi_option);
2060 EngineControl::push_state_to_backend (bool start)
2062 DEBUG_ECONTROL ("push_state_to_backend");
2063 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2069 /* figure out what is going to change */
2071 bool restart_required = false;
2072 bool was_running = ARDOUR::AudioEngine::instance()->running();
2073 bool change_driver = false;
2074 bool change_device = false;
2075 bool change_rate = false;
2076 bool change_bufsize = false;
2077 bool change_latency = false;
2078 bool change_channels = false;
2079 bool change_midi = false;
2081 uint32_t ochan = get_output_channels ();
2082 uint32_t ichan = get_input_channels ();
2084 if (_have_control) {
2086 if (started_at_least_once) {
2088 /* we can control the backend */
2090 if (backend->requires_driver_selection()) {
2091 if (get_driver() != backend->driver_name()) {
2092 change_driver = true;
2096 if (backend->use_separate_input_and_output_devices()) {
2097 if (get_input_device_name() != backend->input_device_name()) {
2098 change_device = true;
2100 if (get_output_device_name() != backend->output_device_name()) {
2101 change_device = true;
2104 if (get_device_name() != backend->device_name()) {
2105 change_device = true;
2109 if (queue_device_changed) {
2110 change_device = true;
2113 if (get_rate() != backend->sample_rate()) {
2117 if (get_buffer_size() != backend->buffer_size()) {
2118 change_bufsize = true;
2121 if (get_midi_option() != backend->midi_option()) {
2125 /* zero-requested channels means "all available" */
2128 ichan = backend->input_channels();
2132 ochan = backend->output_channels();
2135 if (ichan != backend->input_channels()) {
2136 change_channels = true;
2139 if (ochan != backend->output_channels()) {
2140 change_channels = true;
2143 if (get_input_latency() != backend->systemic_input_latency() ||
2144 get_output_latency() != backend->systemic_output_latency()) {
2145 change_latency = true;
2148 /* backend never started, so we have to force a group
2151 change_device = true;
2152 if (backend->requires_driver_selection()) {
2153 change_driver = true;
2156 change_bufsize = true;
2157 change_channels = true;
2158 change_latency = true;
2164 /* we have no control over the backend, meaning that we can
2165 * only possibly change sample rate and buffer size.
2169 if (get_rate() != backend->sample_rate()) {
2170 change_bufsize = true;
2173 if (get_buffer_size() != backend->buffer_size()) {
2174 change_bufsize = true;
2178 queue_device_changed = false;
2180 if (!_have_control) {
2182 /* We do not have control over the backend, so the best we can
2183 * do is try to change the sample rate and/or bufsize and get
2187 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2191 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2196 backend->set_sample_rate (get_rate());
2199 if (change_bufsize) {
2200 backend->set_buffer_size (get_buffer_size());
2204 if (ARDOUR::AudioEngine::instance()->start ()) {
2205 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2215 /* determine if we need to stop the backend before changing parameters */
2217 if (change_driver || change_device || change_channels || change_latency ||
2218 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2220 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2221 restart_required = true;
2223 restart_required = false;
2228 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2229 /* no changes in any parameters that absolutely require a
2230 * restart, so check those that might be changeable without a
2234 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2235 /* can't do this while running ... */
2236 restart_required = true;
2239 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2240 /* can't do this while running ... */
2241 restart_required = true;
2247 if (restart_required) {
2248 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2255 if (change_driver && backend->set_driver (get_driver())) {
2256 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2259 if (backend->use_separate_input_and_output_devices()) {
2260 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2261 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2264 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2265 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2269 if (change_device && backend->set_device_name (get_device_name())) {
2270 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2274 if (change_rate && backend->set_sample_rate (get_rate())) {
2275 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2278 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2279 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2283 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2284 if (backend->set_input_channels (get_input_channels())) {
2285 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2288 if (backend->set_output_channels (get_output_channels())) {
2289 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2293 if (change_latency) {
2294 if (backend->set_systemic_input_latency (get_input_latency())) {
2295 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2298 if (backend->set_systemic_output_latency (get_output_latency())) {
2299 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2305 backend->set_midi_option (get_midi_option());
2309 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2310 if (_measure_midi) {
2311 if (*p == _measure_midi) {
2312 backend->set_midi_device_enabled ((*p)->name, true);
2314 backend->set_midi_device_enabled ((*p)->name, false);
2318 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2319 if (backend->can_set_systemic_midi_latencies()) {
2320 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2321 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2326 if (start || (was_running && restart_required)) {
2327 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2338 EngineControl::post_push ()
2340 /* get a pointer to the current state object, creating one if
2344 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2347 state = save_state ();
2355 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2356 (*i)->active = false;
2359 /* mark this one active (to be used next time the dialog is
2363 state->active = true;
2365 if (_have_control) { // XXX
2366 manage_control_app_sensitivity ();
2369 /* schedule a redisplay of MIDI ports */
2370 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2375 EngineControl::get_rate () const
2377 float r = atof (sample_rate_combo.get_active_text ());
2378 /* the string may have been translated with an abbreviation for
2379 * thousands, so use a crude heuristic to fix this.
2389 EngineControl::get_buffer_size () const
2391 string txt = buffer_size_combo.get_active_text ();
2394 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2395 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2396 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2404 EngineControl::get_midi_option () const
2406 return midi_option_combo.get_active_text();
2410 EngineControl::get_input_channels() const
2412 if (ARDOUR::Profile->get_mixbus()) {
2413 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2414 if (!backend) return 0;
2415 return backend->input_channels();
2417 return (uint32_t) input_channels_adjustment.get_value();
2421 EngineControl::get_output_channels() const
2423 if (ARDOUR::Profile->get_mixbus()) {
2424 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2425 if (!backend) return 0;
2426 return backend->input_channels();
2428 return (uint32_t) output_channels_adjustment.get_value();
2432 EngineControl::get_input_latency() const
2434 return (uint32_t) input_latency_adjustment.get_value();
2438 EngineControl::get_output_latency() const
2440 return (uint32_t) output_latency_adjustment.get_value();
2444 EngineControl::get_backend () const
2446 return backend_combo.get_active_text ();
2450 EngineControl::get_driver () const
2452 if (driver_combo.get_parent()) {
2453 return driver_combo.get_active_text ();
2460 EngineControl::get_device_name () const
2462 return device_combo.get_active_text ();
2466 EngineControl::get_input_device_name () const
2468 return input_device_combo.get_active_text ();
2472 EngineControl::get_output_device_name () const
2474 return output_device_combo.get_active_text ();
2478 EngineControl::control_app_button_clicked ()
2480 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2486 backend->launch_control_app ();
2490 EngineControl::start_stop_button_clicked ()
2492 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2498 if (ARDOUR::AudioEngine::instance()->running()) {
2499 ARDOUR::AudioEngine::instance()->stop ();
2501 push_state_to_backend (true);
2506 EngineControl::update_devices_button_clicked ()
2508 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2514 if (backend->update_devices()) {
2515 device_list_changed ();
2520 EngineControl::manage_control_app_sensitivity ()
2522 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2528 string appname = backend->control_app_name();
2530 if (appname.empty()) {
2531 control_app_button.set_sensitive (false);
2533 control_app_button.set_sensitive (true);
2538 EngineControl::set_desired_sample_rate (uint32_t sr)
2540 _desired_sample_rate = sr;
2545 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2547 if (page_num == 0) {
2548 cancel_button->set_sensitive (true);
2549 _measure_midi.reset();
2550 update_sensitivity ();
2552 cancel_button->set_sensitive (false);
2553 ok_button->set_sensitive (false);
2556 if (page_num == midi_tab) {
2558 refresh_midi_display ();
2561 if (page_num == latency_tab) {
2564 if (ARDOUR::AudioEngine::instance()->running()) {
2565 // TODO - mark as 'stopped for latency
2566 ARDOUR_UI::instance()->disconnect_from_engine ();
2570 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2572 /* save any existing latency values */
2574 uint32_t il = (uint32_t) input_latency.get_value ();
2575 uint32_t ol = (uint32_t) input_latency.get_value ();
2577 /* reset to zero so that our new test instance
2578 will be clean of any existing latency measures.
2580 NB. this should really be done by the backend
2581 when stated for latency measurement.
2584 input_latency.set_value (0);
2585 output_latency.set_value (0);
2587 push_state_to_backend (false);
2591 input_latency.set_value (il);
2592 output_latency.set_value (ol);
2595 // This should be done in push_state_to_backend()
2596 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2597 disable_latency_tab ();
2600 enable_latency_tab ();
2604 end_latency_detection ();
2605 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2610 /* latency measurement */
2613 EngineControl::check_audio_latency_measurement ()
2615 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2617 if (mtdm->resolve () < 0) {
2618 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2622 if (mtdm->err () > 0.3) {
2628 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2630 if (sample_rate == 0) {
2631 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2632 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2636 int frames_total = mtdm->del();
2637 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2639 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2640 _("Detected roundtrip latency: "),
2641 frames_total, frames_total * 1000.0f/sample_rate,
2642 _("Systemic latency: "),
2643 extra, extra * 1000.0f/sample_rate);
2647 if (mtdm->err () > 0.2) {
2649 strcat (buf, _("(signal detection error)"));
2655 strcat (buf, _("(inverted - bad wiring)"));
2659 lm_results.set_markup (string_compose (results_markup, buf));
2662 have_lm_results = true;
2663 end_latency_detection ();
2664 lm_use_button.set_sensitive (true);
2672 EngineControl::check_midi_latency_measurement ()
2674 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2676 if (!mididm->have_signal () || mididm->latency () == 0) {
2677 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2682 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2684 if (sample_rate == 0) {
2685 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2686 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2690 ARDOUR::framecnt_t frames_total = mididm->latency();
2691 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2692 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2693 _("Detected roundtrip latency: "),
2694 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2695 _("Systemic latency: "),
2696 extra, extra * 1000.0f / sample_rate);
2700 if (!mididm->ok ()) {
2702 strcat (buf, _("(averaging)"));
2706 if (mididm->deviation () > 50.0) {
2708 strcat (buf, _("(too large jitter)"));
2710 } else if (mididm->deviation () > 10.0) {
2712 strcat (buf, _("(large jitter)"));
2716 have_lm_results = true;
2717 end_latency_detection ();
2718 lm_use_button.set_sensitive (true);
2719 lm_results.set_markup (string_compose (results_markup, buf));
2721 } else if (mididm->processed () > 400) {
2722 have_lm_results = false;
2723 end_latency_detection ();
2724 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2728 lm_results.set_markup (string_compose (results_markup, buf));
2734 EngineControl::start_latency_detection ()
2736 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2737 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2739 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2740 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2741 if (_measure_midi) {
2742 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2744 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2746 lm_measure_label.set_text (_("Cancel"));
2747 have_lm_results = false;
2748 lm_use_button.set_sensitive (false);
2749 lm_input_channel_combo.set_sensitive (false);
2750 lm_output_channel_combo.set_sensitive (false);
2756 EngineControl::end_latency_detection ()
2758 latency_timeout.disconnect ();
2759 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2760 lm_measure_label.set_text (_("Measure"));
2761 if (!have_lm_results) {
2762 lm_use_button.set_sensitive (false);
2764 lm_input_channel_combo.set_sensitive (true);
2765 lm_output_channel_combo.set_sensitive (true);
2770 EngineControl::latency_button_clicked ()
2773 start_latency_detection ();
2775 end_latency_detection ();
2780 EngineControl::use_latency_button_clicked ()
2782 if (_measure_midi) {
2783 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2787 ARDOUR::framecnt_t frames_total = mididm->latency();
2788 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2789 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2790 _measure_midi->input_latency = one_way;
2791 _measure_midi->output_latency = one_way;
2792 notebook.set_current_page (midi_tab);
2794 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2800 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2801 one_way = std::max (0., one_way);
2803 input_latency_adjustment.set_value (one_way);
2804 output_latency_adjustment.set_value (one_way);
2806 /* back to settings page */
2807 notebook.set_current_page (0);
2813 EngineControl::on_delete_event (GdkEventAny* ev)
2815 if (notebook.get_current_page() == 2) {
2816 /* currently on latency tab - be sure to clean up */
2817 end_latency_detection ();
2819 return ArdourDialog::on_delete_event (ev);
2823 EngineControl::engine_running ()
2825 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2828 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2829 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2831 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2832 connect_disconnect_button.show();
2834 started_at_least_once = true;
2835 if (_have_control) {
2836 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2838 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2840 update_sensitivity();
2844 EngineControl::engine_stopped ()
2846 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2849 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2850 connect_disconnect_button.show();
2852 if (_have_control) {
2853 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2855 engine_status.set_markup(X_(""));
2858 update_sensitivity();
2862 EngineControl::device_list_changed ()
2864 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2866 midi_option_changed();
2870 EngineControl::connect_disconnect_click()
2872 if (ARDOUR::AudioEngine::instance()->running()) {
2873 ARDOUR_UI::instance()->disconnect_from_engine ();
2875 ARDOUR_UI::instance()->reconnect_to_engine ();
2880 EngineControl::calibrate_audio_latency ()
2882 _measure_midi.reset ();
2883 have_lm_results = false;
2884 lm_use_button.set_sensitive (false);
2885 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2886 notebook.set_current_page (latency_tab);
2890 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2893 have_lm_results = false;
2894 lm_use_button.set_sensitive (false);
2895 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2896 notebook.set_current_page (latency_tab);
2900 EngineControl::configure_midi_devices ()
2902 notebook.set_current_page (midi_tab);