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 #ifdef PLATFORM_WINDOWS
419 // For some reason we don't understand, 'hide()'
420 // needs to get called first in Windows
423 // But if there's no session open, this can produce
424 // a long gap when nothing appears to be happening.
425 // Let's show the splash image while we're waiting.
426 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
427 if ( ARDOUR_UI::instance() ) {
428 if ( !ARDOUR_UI::instance()->session_loaded ) {
429 ARDOUR_UI::instance()->show_splash();
433 push_state_to_backend (true);
436 push_state_to_backend (true);
440 case RESPONSE_DELETE_EVENT:
443 ev.type = GDK_BUTTON_PRESS;
445 on_delete_event ((GdkEventAny*) &ev);
454 EngineControl::build_notebook ()
457 AttachOptions xopt = AttachOptions (FILL|EXPAND);
459 /* clear the table */
461 Gtkmm2ext::container_clear (basic_vbox);
462 Gtkmm2ext::container_clear (basic_packer);
464 if (control_app_button.get_parent()) {
465 control_app_button.get_parent()->remove (control_app_button);
468 label = manage (left_aligned_label (_("Audio System:")));
469 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
470 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
472 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
473 engine_status.show();
475 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
476 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
478 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
479 lm_button_audio.set_name ("generic button");
480 lm_button_audio.set_can_focus(true);
483 build_full_control_notebook ();
485 build_no_control_notebook ();
488 basic_vbox.pack_start (basic_hbox, false, false);
491 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
492 basic_vbox.show_all ();
497 EngineControl::build_full_control_notebook ()
499 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
502 using namespace Notebook_Helpers;
504 vector<string> strings;
505 AttachOptions xopt = AttachOptions (FILL|EXPAND);
506 int row = 1; // row zero == backend combo
508 /* start packing it up */
510 if (backend->requires_driver_selection()) {
511 label = manage (left_aligned_label (_("Driver:")));
512 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
513 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
517 if (backend->use_separate_input_and_output_devices()) {
518 label = manage (left_aligned_label (_("Input Device:")));
519 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
520 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
522 label = manage (left_aligned_label (_("Output Device:")));
523 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
524 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
526 // reset so it isn't used in state comparisons
527 device_combo.set_active_text ("");
529 label = manage (left_aligned_label (_("Device:")));
530 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
531 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
533 // reset these so they don't get used in state comparisons
534 input_device_combo.set_active_text ("");
535 output_device_combo.set_active_text ("");
538 label = manage (left_aligned_label (_("Sample rate:")));
539 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
540 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
544 label = manage (left_aligned_label (_("Buffer size:")));
545 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
546 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
547 buffer_size_duration_label.set_alignment (0.0); /* left-align */
548 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
550 /* button spans 2 rows */
552 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
555 input_channels.set_name ("InputChannels");
556 input_channels.set_flags (Gtk::CAN_FOCUS);
557 input_channels.set_digits (0);
558 input_channels.set_wrap (false);
559 output_channels.set_editable (true);
561 if (!ARDOUR::Profile->get_mixbus()) {
562 label = manage (left_aligned_label (_("Input Channels:")));
563 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
564 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
568 output_channels.set_name ("OutputChannels");
569 output_channels.set_flags (Gtk::CAN_FOCUS);
570 output_channels.set_digits (0);
571 output_channels.set_wrap (false);
572 output_channels.set_editable (true);
574 if (!ARDOUR::Profile->get_mixbus()) {
575 label = manage (left_aligned_label (_("Output Channels:")));
576 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
577 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
581 input_latency.set_name ("InputLatency");
582 input_latency.set_flags (Gtk::CAN_FOCUS);
583 input_latency.set_digits (0);
584 input_latency.set_wrap (false);
585 input_latency.set_editable (true);
587 label = manage (left_aligned_label (_("Hardware input latency:")));
588 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
589 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
590 label = manage (left_aligned_label (_("samples")));
591 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
594 output_latency.set_name ("OutputLatency");
595 output_latency.set_flags (Gtk::CAN_FOCUS);
596 output_latency.set_digits (0);
597 output_latency.set_wrap (false);
598 output_latency.set_editable (true);
600 label = manage (left_aligned_label (_("Hardware output latency:")));
601 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
602 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
603 label = manage (left_aligned_label (_("samples")));
604 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
606 /* button spans 2 rows */
608 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
611 label = manage (left_aligned_label (_("MIDI System:")));
612 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
613 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
614 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
615 /* Currently the only backend with dedicated Midi setup is ALSA.
616 * lot of people complain that this is greyed out
617 * "I can't use MIDI, the setup is greyed out"
619 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
625 EngineControl::build_no_control_notebook ()
627 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
630 using namespace Notebook_Helpers;
632 vector<string> strings;
633 AttachOptions xopt = AttachOptions (FILL|EXPAND);
634 int row = 1; // row zero == backend combo
635 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
637 label = manage (new Label);
638 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
639 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
642 if (backend->can_change_sample_rate_when_running()) {
643 label = manage (left_aligned_label (_("Sample rate:")));
644 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
645 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
649 if (backend->can_change_buffer_size_when_running()) {
650 label = manage (left_aligned_label (_("Buffer size:")));
651 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
652 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
653 buffer_size_duration_label.set_alignment (0.0); /* left-align */
654 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
658 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
662 EngineControl::~EngineControl ()
664 ignore_changes = true;
668 EngineControl::disable_latency_tab ()
670 vector<string> empty;
671 set_popdown_strings (lm_output_channel_combo, empty);
672 set_popdown_strings (lm_input_channel_combo, empty);
673 lm_measure_button.set_sensitive (false);
674 lm_use_button.set_sensitive (false);
678 EngineControl::enable_latency_tab ()
680 vector<string> outputs;
681 vector<string> inputs;
683 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
684 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
685 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
687 if (!ARDOUR::AudioEngine::instance()->running()) {
688 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
689 notebook.set_current_page (0);
693 else if (inputs.empty() || outputs.empty()) {
694 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
695 notebook.set_current_page (0);
700 lm_back_button_signal.disconnect();
702 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
705 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
709 set_popdown_strings (lm_output_channel_combo, outputs);
710 lm_output_channel_combo.set_active_text (outputs.front());
711 lm_output_channel_combo.set_sensitive (true);
713 set_popdown_strings (lm_input_channel_combo, inputs);
714 lm_input_channel_combo.set_active_text (inputs.front());
715 lm_input_channel_combo.set_sensitive (true);
717 lm_measure_button.set_sensitive (true);
721 EngineControl::setup_midi_tab_for_backend ()
723 string backend = backend_combo.get_active_text ();
725 Gtkmm2ext::container_clear (midi_vbox);
727 midi_vbox.set_border_width (12);
728 midi_device_table.set_border_width (12);
730 if (backend == "JACK") {
731 setup_midi_tab_for_jack ();
734 midi_vbox.pack_start (midi_device_table, true, true);
735 midi_vbox.pack_start (midi_back_button, false, false);
736 midi_vbox.show_all ();
740 EngineControl::update_sensitivity ()
742 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
744 ok_button->set_sensitive (false);
745 start_stop_button.set_sensitive (false);
750 size_t devices_available = 0;
752 if (backend->use_separate_input_and_output_devices ()) {
753 devices_available += get_popdown_string_count (input_device_combo);
754 devices_available += get_popdown_string_count (output_device_combo);
756 devices_available += get_popdown_string_count (device_combo);
759 if (devices_available == 0) {
761 input_latency.set_sensitive (false);
762 output_latency.set_sensitive (false);
763 input_channels.set_sensitive (false);
764 output_channels.set_sensitive (false);
766 input_latency.set_sensitive (true);
767 output_latency.set_sensitive (true);
768 input_channels.set_sensitive (true);
769 output_channels.set_sensitive (true);
772 if (get_popdown_string_count (buffer_size_combo) > 0) {
773 if (!ARDOUR::AudioEngine::instance()->running()) {
774 buffer_size_combo.set_sensitive (valid);
775 } else if (backend->can_change_sample_rate_when_running()) {
776 buffer_size_combo.set_sensitive (valid || !_have_control);
780 * Currently there is no way to manually stop the
781 * engine in order to re-configure it.
782 * This needs to remain sensitive for now.
784 * (it's also handy to implicily
785 * re-start the engine)
787 buffer_size_combo.set_sensitive (true);
789 buffer_size_combo.set_sensitive (false);
793 buffer_size_combo.set_sensitive (false);
797 if (get_popdown_string_count (sample_rate_combo) > 0) {
798 if (!ARDOUR::AudioEngine::instance()->running()) {
799 sample_rate_combo.set_sensitive (true);
801 sample_rate_combo.set_sensitive (false);
804 sample_rate_combo.set_sensitive (false);
809 start_stop_button.set_sensitive(true);
810 start_stop_button.show();
811 if (ARDOUR::AudioEngine::instance()->running()) {
812 start_stop_button.set_text("Stop");
813 update_devices_button.set_sensitive(false);
815 if (backend->can_request_update_devices()) {
816 update_devices_button.show();
818 update_devices_button.hide();
820 start_stop_button.set_text("Start");
821 update_devices_button.set_sensitive(true);
824 update_devices_button.set_sensitive(false);
825 update_devices_button.hide();
826 start_stop_button.set_sensitive(false);
827 start_stop_button.hide();
830 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
831 input_device_combo.set_sensitive (false);
832 output_device_combo.set_sensitive (false);
833 device_combo.set_sensitive (false);
834 driver_combo.set_sensitive (false);
836 input_device_combo.set_sensitive (true);
837 output_device_combo.set_sensitive (true);
838 device_combo.set_sensitive (true);
839 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
840 driver_combo.set_sensitive (true);
842 driver_combo.set_sensitive (false);
846 if (valid || !_have_control) {
847 ok_button->set_sensitive (true);
849 ok_button->set_sensitive (false);
854 EngineControl::setup_midi_tab_for_jack ()
859 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
861 device->input_latency = a->get_value();
863 device->output_latency = a->get_value();
868 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
869 b->set_active (!b->get_active());
870 device->enabled = b->get_active();
871 refresh_midi_display(device->name);
875 EngineControl::refresh_midi_display (std::string focus)
877 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
881 AttachOptions xopt = AttachOptions (FILL|EXPAND);
884 Gtkmm2ext::container_clear (midi_device_table);
886 midi_device_table.set_spacings (6);
888 l = manage (new Label);
889 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
890 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
891 l->set_alignment (0.5, 0.5);
895 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
896 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
897 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
898 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
900 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
901 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
902 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
903 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
906 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
911 bool enabled = (*p)->enabled;
913 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
914 m->set_name ("midi device");
915 m->set_can_focus (Gtk::CAN_FOCUS);
916 m->add_events (Gdk::BUTTON_RELEASE_MASK);
917 m->set_active (enabled);
918 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
919 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
920 if ((*p)->name == focus) {
924 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
925 s = manage (new Gtk::SpinButton (*a));
926 a->set_value ((*p)->input_latency);
927 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
928 s->set_sensitive (_can_set_midi_latencies && enabled);
929 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
931 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
932 s = manage (new Gtk::SpinButton (*a));
933 a->set_value ((*p)->output_latency);
934 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
935 s->set_sensitive (_can_set_midi_latencies && enabled);
936 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
938 b = manage (new Button (_("Calibrate")));
939 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
940 b->set_sensitive (_can_set_midi_latencies && enabled);
941 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
948 EngineControl::backend_changed ()
950 SignalBlocker blocker (*this, "backend_changed");
951 string backend_name = backend_combo.get_active_text();
952 boost::shared_ptr<ARDOUR::AudioBackend> backend;
954 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (PROGRAM_NAME), ""))) {
955 /* eh? setting the backend failed... how ? */
956 /* A: stale config contains a backend that does not exist in current build */
960 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
962 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
965 setup_midi_tab_for_backend ();
966 _midi_devices.clear();
968 if (backend->requires_driver_selection()) {
969 if (set_driver_popdown_strings ()) {
973 /* this will change the device text which will cause a call to
974 * device changed which will set up parameters
979 update_midi_options ();
981 connect_disconnect_button.hide();
983 midi_option_changed();
985 started_at_least_once = false;
987 /* changing the backend implies stopping the engine
988 * ARDOUR::AudioEngine() may or may not emit this signal
989 * depending on previous engine state
991 engine_stopped (); // set "active/inactive"
993 if (!ignore_changes) {
994 maybe_display_saved_state ();
999 EngineControl::update_midi_options ()
1001 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1002 vector<string> midi_options = backend->enumerate_midi_options();
1004 if (midi_options.size() == 1) {
1005 /* only contains the "none" option */
1006 midi_option_combo.set_sensitive (false);
1008 if (_have_control) {
1009 set_popdown_strings (midi_option_combo, midi_options);
1010 midi_option_combo.set_active_text (midi_options.front());
1011 midi_option_combo.set_sensitive (true);
1013 midi_option_combo.set_sensitive (false);
1019 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1021 if (ARDOUR::Profile->get_mixbus()) {
1025 uint32_t cnt = (uint32_t) sb->get_value();
1027 sb->set_text (_("all available channels"));
1030 snprintf (buf, sizeof (buf), "%d", cnt);
1036 // @return true if there are drivers available
1038 EngineControl::set_driver_popdown_strings ()
1040 DEBUG_ECONTROL ("set_driver_popdown_strings");
1041 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1042 vector<string> drivers = backend->enumerate_drivers();
1044 if (drivers.empty ()) {
1045 // This is an error...?
1049 string current_driver = backend->driver_name ();
1051 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1053 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1056 current_driver = drivers.front ();
1059 set_popdown_strings (driver_combo, drivers);
1061 string_compose ("driver_combo.set_active_text: %1", current_driver));
1062 driver_combo.set_active_text (current_driver);
1067 EngineControl::get_default_device(const string& current_device_name,
1068 const vector<string>& available_devices)
1070 // If the current device is available, use it as default
1071 if (std::find (available_devices.begin (),
1072 available_devices.end (),
1073 current_device_name) != available_devices.end ()) {
1075 return current_device_name;
1078 using namespace ARDOUR;
1080 string default_device_name =
1081 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1083 vector<string>::const_iterator i;
1085 // If there is a "Default" device available, use it
1086 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1087 if (*i == default_device_name) {
1092 string none_device_name =
1093 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1095 // Use the first device that isn't "None"
1096 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1097 if (*i != none_device_name) {
1102 // Use "None" if there are no other available
1103 return available_devices.front();
1106 // @return true if there are devices available
1108 EngineControl::set_device_popdown_strings ()
1110 DEBUG_ECONTROL ("set_device_popdown_strings");
1111 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1112 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1114 /* NOTE: Ardour currently does not display the "available" field of the
1117 * Doing so would require a different GUI widget than the combo
1118 * box/popdown that we currently use, since it has no way to list
1119 * items that are not selectable. Something more like a popup menu,
1120 * which could have unselectable items, would be appropriate.
1123 vector<string> available_devices;
1125 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1126 available_devices.push_back (i->name);
1129 if (available_devices.empty ()) {
1133 set_popdown_strings (device_combo, available_devices);
1135 std::string default_device =
1136 get_default_device(backend->device_name(), available_devices);
1139 string_compose ("set device_combo active text: %1", default_device));
1141 device_combo.set_active_text(default_device);
1145 // @return true if there are input devices available
1147 EngineControl::set_input_device_popdown_strings ()
1149 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1150 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1151 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1153 vector<string> available_devices;
1155 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1156 available_devices.push_back (i->name);
1159 if (available_devices.empty()) {
1163 set_popdown_strings (input_device_combo, available_devices);
1165 std::string default_device =
1166 get_default_device(backend->input_device_name(), available_devices);
1169 string_compose ("set input_device_combo active text: %1", default_device));
1170 input_device_combo.set_active_text(default_device);
1174 // @return true if there are output devices available
1176 EngineControl::set_output_device_popdown_strings ()
1178 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1179 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1180 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1182 vector<string> available_devices;
1184 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1185 available_devices.push_back (i->name);
1188 if (available_devices.empty()) {
1192 set_popdown_strings (output_device_combo, available_devices);
1194 std::string default_device =
1195 get_default_device(backend->output_device_name(), available_devices);
1198 string_compose ("set output_device_combo active text: %1", default_device));
1199 output_device_combo.set_active_text(default_device);
1204 EngineControl::list_devices ()
1206 DEBUG_ECONTROL ("list_devices");
1207 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1210 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1212 bool devices_available = false;
1214 if (backend->use_separate_input_and_output_devices ()) {
1215 bool input_devices_available = set_input_device_popdown_strings ();
1216 bool output_devices_available = set_output_device_popdown_strings ();
1217 devices_available = input_devices_available || output_devices_available;
1219 devices_available = set_device_popdown_strings ();
1222 if (devices_available) {
1225 device_combo.clear();
1226 input_device_combo.clear();
1227 output_device_combo.clear();
1229 update_sensitivity ();
1233 EngineControl::driver_changed ()
1235 SignalBlocker blocker (*this, "driver_changed");
1236 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1239 backend->set_driver (driver_combo.get_active_text());
1242 if (!ignore_changes) {
1243 maybe_display_saved_state ();
1248 EngineControl::get_sample_rates_for_all_devices ()
1250 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1251 ARDOUR::AudioEngine::instance ()->current_backend ();
1252 vector<float> all_rates;
1254 if (backend->use_separate_input_and_output_devices ()) {
1255 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1257 all_rates = backend->available_sample_rates (get_device_name ());
1263 EngineControl::get_default_sample_rates ()
1265 vector<float> rates;
1266 rates.push_back (8000.0f);
1267 rates.push_back (16000.0f);
1268 rates.push_back (32000.0f);
1269 rates.push_back (44100.0f);
1270 rates.push_back (48000.0f);
1271 rates.push_back (88200.0f);
1272 rates.push_back (96000.0f);
1273 rates.push_back (192000.0f);
1274 rates.push_back (384000.0f);
1279 EngineControl::set_samplerate_popdown_strings ()
1281 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1282 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1287 if (_have_control) {
1288 sr = get_sample_rates_for_all_devices ();
1290 sr = get_default_sample_rates ();
1293 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1294 s.push_back (rate_as_string (*x));
1295 if (*x == _desired_sample_rate) {
1300 set_popdown_strings (sample_rate_combo, s);
1303 if (desired.empty ()) {
1304 float new_active_sr = backend->default_sample_rate ();
1306 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1307 new_active_sr = sr.front ();
1310 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1312 sample_rate_combo.set_active_text (desired);
1316 update_sensitivity ();
1320 EngineControl::get_buffer_sizes_for_all_devices ()
1322 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1323 ARDOUR::AudioEngine::instance ()->current_backend ();
1324 vector<uint32_t> all_sizes;
1326 if (backend->use_separate_input_and_output_devices ()) {
1327 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1329 all_sizes = backend->available_buffer_sizes (get_device_name ());
1335 EngineControl::get_default_buffer_sizes ()
1337 vector<uint32_t> sizes;
1338 sizes.push_back (8);
1339 sizes.push_back (16);
1340 sizes.push_back (32);
1341 sizes.push_back (64);
1342 sizes.push_back (128);
1343 sizes.push_back (256);
1344 sizes.push_back (512);
1345 sizes.push_back (1024);
1346 sizes.push_back (2048);
1347 sizes.push_back (4096);
1348 sizes.push_back (8192);
1353 EngineControl::set_buffersize_popdown_strings ()
1355 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1356 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1357 vector<uint32_t> bs;
1360 if (_have_control) {
1361 bs = get_buffer_sizes_for_all_devices ();
1362 } else if (backend->can_change_buffer_size_when_running()) {
1363 bs = get_default_buffer_sizes ();
1366 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1367 s.push_back (bufsize_as_string (*x));
1370 uint32_t previous_size = 0;
1371 if (!buffer_size_combo.get_active_text().empty()) {
1372 previous_size = get_buffer_size ();
1375 set_popdown_strings (buffer_size_combo, s);
1379 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1380 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1383 buffer_size_combo.set_active_text(s.front());
1385 uint32_t period = backend->buffer_size();
1386 if (0 == period && backend->use_separate_input_and_output_devices()) {
1387 period = backend->default_buffer_size(get_input_device_name());
1389 if (0 == period && backend->use_separate_input_and_output_devices()) {
1390 period = backend->default_buffer_size(get_output_device_name());
1392 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1393 period = backend->default_buffer_size(get_device_name());
1396 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1398 show_buffer_duration ();
1400 update_sensitivity ();
1404 EngineControl::device_changed ()
1406 SignalBlocker blocker (*this, "device_changed");
1407 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1410 string device_name_in;
1411 string device_name_out; // only used if backend support separate I/O devices
1413 if (backend->use_separate_input_and_output_devices()) {
1414 device_name_in = get_input_device_name ();
1415 device_name_out = get_output_device_name ();
1417 device_name_in = get_device_name ();
1420 /* we set the backend-device to query various device related intormation.
1421 * This has the side effect that backend->device_name() will match
1422 * the device_name and 'change_device' will never be true.
1423 * so work around this by setting...
1425 if (backend->use_separate_input_and_output_devices()) {
1426 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1427 queue_device_changed = true;
1430 if (device_name_in != backend->device_name()) {
1431 queue_device_changed = true;
1435 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1436 if (backend->use_separate_input_and_output_devices()) {
1437 backend->set_input_device_name (device_name_in);
1438 backend->set_output_device_name (device_name_out);
1440 backend->set_device_name(device_name_in);
1444 /* don't allow programmatic change to combos to cause a
1445 recursive call to this method.
1447 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1449 set_samplerate_popdown_strings ();
1450 set_buffersize_popdown_strings ();
1452 /* TODO set min + max channel counts here */
1454 manage_control_app_sensitivity ();
1457 /* pick up any saved state for this device */
1459 if (!ignore_changes) {
1460 maybe_display_saved_state ();
1465 EngineControl::input_device_changed ()
1467 DEBUG_ECONTROL ("input_device_changed");
1472 EngineControl::output_device_changed ()
1474 DEBUG_ECONTROL ("output_device_changed");
1479 EngineControl::bufsize_as_string (uint32_t sz)
1481 /* Translators: "samples" is always plural here, so no
1482 need for plural+singular forms.
1485 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1490 EngineControl::sample_rate_changed ()
1492 DEBUG_ECONTROL ("sample_rate_changed");
1493 /* reset the strings for buffer size to show the correct msec value
1494 (reflecting the new sample rate).
1497 show_buffer_duration ();
1502 EngineControl::buffer_size_changed ()
1504 DEBUG_ECONTROL ("buffer_size_changed");
1505 show_buffer_duration ();
1509 EngineControl::show_buffer_duration ()
1511 DEBUG_ECONTROL ("show_buffer_duration");
1512 /* buffer sizes - convert from just samples to samples + msecs for
1513 * the displayed string
1516 string bs_text = buffer_size_combo.get_active_text ();
1517 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1518 uint32_t rate = get_rate();
1520 /* Developers: note the hard-coding of a double buffered model
1521 in the (2 * samples) computation of latency. we always start
1522 the audiobackend in this configuration.
1524 /* note to jack1 developers: ardour also always starts the engine
1525 * in async mode (no jack2 --sync option) which adds an extra cycle
1526 * of latency with jack2 (and *3 would be correct)
1527 * The value can also be wrong if jackd is started externally..
1529 * At the time of writing the ALSA backend always uses double-buffering *2,
1530 * The Dummy backend *1, and who knows what ASIO really does :)
1532 * So just display the period size, that's also what
1533 * ARDOUR_UI::update_sample_rate() does for the status bar.
1534 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1535 * but still, that's the buffer period, not [round-trip] latency)
1538 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1539 buffer_size_duration_label.set_text (buf);
1543 EngineControl::midi_option_changed ()
1545 DEBUG_ECONTROL ("midi_option_changed");
1546 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1549 backend->set_midi_option (get_midi_option());
1551 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1553 //_midi_devices.clear(); // TODO merge with state-saved settings..
1554 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1555 std::vector<MidiDeviceSettings> new_devices;
1557 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1558 MidiDeviceSettings mds = find_midi_device (i->name);
1559 if (i->available && !mds) {
1560 uint32_t input_latency = 0;
1561 uint32_t output_latency = 0;
1562 if (_can_set_midi_latencies) {
1563 input_latency = backend->systemic_midi_input_latency (i->name);
1564 output_latency = backend->systemic_midi_output_latency (i->name);
1566 bool enabled = backend->midi_device_enabled (i->name);
1567 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1568 new_devices.push_back (ptr);
1569 } else if (i->available) {
1570 new_devices.push_back (mds);
1573 _midi_devices = new_devices;
1575 if (_midi_devices.empty()) {
1576 midi_devices_button.set_sensitive (false);
1578 midi_devices_button.set_sensitive (true);
1583 EngineControl::parameter_changed ()
1587 EngineControl::State
1588 EngineControl::get_matching_state (
1589 const string& backend,
1590 const string& driver,
1591 const string& device)
1593 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1594 if ((*i)->backend == backend &&
1595 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1603 EngineControl::State
1604 EngineControl::get_matching_state (
1605 const string& backend,
1606 const string& driver,
1607 const string& input_device,
1608 const string& output_device)
1610 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1611 if ((*i)->backend == backend &&
1612 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1620 EngineControl::State
1621 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1623 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1626 if (backend->use_separate_input_and_output_devices ()) {
1627 return get_matching_state (backend_combo.get_active_text(),
1628 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1629 input_device_combo.get_active_text(),
1630 output_device_combo.get_active_text());
1632 return get_matching_state (backend_combo.get_active_text(),
1633 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1634 device_combo.get_active_text());
1638 return get_matching_state (backend_combo.get_active_text(),
1640 device_combo.get_active_text());
1643 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1644 const EngineControl::State& state2)
1646 if (state1->backend == state2->backend &&
1647 state1->driver == state2->driver &&
1648 state1->device == state2->device &&
1649 state1->input_device == state2->input_device &&
1650 state1->output_device == state2->output_device) {
1656 EngineControl::State
1657 EngineControl::save_state ()
1661 if (!_have_control) {
1662 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1666 state.reset(new StateStruct);
1667 state->backend = get_backend ();
1669 state.reset(new StateStruct);
1670 store_state (state);
1673 for (StateList::iterator i = states.begin(); i != states.end();) {
1674 if (equivalent_states (*i, state)) {
1675 i = states.erase(i);
1681 states.push_back (state);
1687 EngineControl::store_state (State state)
1689 state->backend = get_backend ();
1690 state->driver = get_driver ();
1691 state->device = get_device_name ();
1692 state->input_device = get_input_device_name ();
1693 state->output_device = get_output_device_name ();
1694 state->sample_rate = get_rate ();
1695 state->buffer_size = get_buffer_size ();
1696 state->input_latency = get_input_latency ();
1697 state->output_latency = get_output_latency ();
1698 state->input_channels = get_input_channels ();
1699 state->output_channels = get_output_channels ();
1700 state->midi_option = get_midi_option ();
1701 state->midi_devices = _midi_devices;
1705 EngineControl::maybe_display_saved_state ()
1707 if (!_have_control) {
1711 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1714 DEBUG_ECONTROL ("Restoring saved state");
1715 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1717 if (!_desired_sample_rate) {
1718 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1720 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1721 /* call this explicitly because we're ignoring changes to
1722 the controls at this point.
1724 show_buffer_duration ();
1725 input_latency.set_value (state->input_latency);
1726 output_latency.set_value (state->output_latency);
1728 if (!state->midi_option.empty()) {
1729 midi_option_combo.set_active_text (state->midi_option);
1730 _midi_devices = state->midi_devices;
1733 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1738 EngineControl::get_state ()
1740 LocaleGuard lg (X_("C"));
1742 XMLNode* root = new XMLNode ("AudioMIDISetup");
1745 if (!states.empty()) {
1746 XMLNode* state_nodes = new XMLNode ("EngineStates");
1748 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1750 XMLNode* node = new XMLNode ("State");
1752 node->add_property ("backend", (*i)->backend);
1753 node->add_property ("driver", (*i)->driver);
1754 node->add_property ("device", (*i)->device);
1755 node->add_property ("input-device", (*i)->input_device);
1756 node->add_property ("output-device", (*i)->output_device);
1757 node->add_property ("sample-rate", (*i)->sample_rate);
1758 node->add_property ("buffer-size", (*i)->buffer_size);
1759 node->add_property ("input-latency", (*i)->input_latency);
1760 node->add_property ("output-latency", (*i)->output_latency);
1761 node->add_property ("input-channels", (*i)->input_channels);
1762 node->add_property ("output-channels", (*i)->output_channels);
1763 node->add_property ("active", (*i)->active ? "yes" : "no");
1764 node->add_property ("midi-option", (*i)->midi_option);
1766 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1767 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1768 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1769 midi_device_stuff->add_property (X_("name"), (*p)->name);
1770 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1771 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1772 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1773 midi_devices->add_child_nocopy (*midi_device_stuff);
1775 node->add_child_nocopy (*midi_devices);
1777 state_nodes->add_child_nocopy (*node);
1780 root->add_child_nocopy (*state_nodes);
1787 EngineControl::set_default_state ()
1789 vector<string> backend_names;
1790 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1792 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1793 backend_names.push_back ((*b)->name);
1795 backend_combo.set_active_text (backend_names.front());
1797 // We could set default backends per platform etc here
1803 EngineControl::set_state (const XMLNode& root)
1805 XMLNodeList clist, cclist;
1806 XMLNodeConstIterator citer, cciter;
1808 XMLNode* grandchild;
1809 XMLProperty* prop = NULL;
1811 fprintf (stderr, "EngineControl::set_state\n");
1813 if (root.name() != "AudioMIDISetup") {
1817 clist = root.children();
1821 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1825 if (child->name() != "EngineStates") {
1829 cclist = child->children();
1831 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1832 State state (new StateStruct);
1834 grandchild = *cciter;
1836 if (grandchild->name() != "State") {
1840 if ((prop = grandchild->property ("backend")) == 0) {
1843 state->backend = prop->value ();
1845 if ((prop = grandchild->property ("driver")) == 0) {
1848 state->driver = prop->value ();
1850 if ((prop = grandchild->property ("device")) == 0) {
1853 state->device = prop->value ();
1855 if ((prop = grandchild->property ("input-device")) == 0) {
1858 state->input_device = prop->value ();
1860 if ((prop = grandchild->property ("output-device")) == 0) {
1863 state->output_device = prop->value ();
1865 if ((prop = grandchild->property ("sample-rate")) == 0) {
1868 state->sample_rate = atof (prop->value ());
1870 if ((prop = grandchild->property ("buffer-size")) == 0) {
1873 state->buffer_size = atoi (prop->value ());
1875 if ((prop = grandchild->property ("input-latency")) == 0) {
1878 state->input_latency = atoi (prop->value ());
1880 if ((prop = grandchild->property ("output-latency")) == 0) {
1883 state->output_latency = atoi (prop->value ());
1885 if ((prop = grandchild->property ("input-channels")) == 0) {
1888 state->input_channels = atoi (prop->value ());
1890 if ((prop = grandchild->property ("output-channels")) == 0) {
1893 state->output_channels = atoi (prop->value ());
1895 if ((prop = grandchild->property ("active")) == 0) {
1898 state->active = string_is_affirmative (prop->value ());
1900 if ((prop = grandchild->property ("midi-option")) == 0) {
1903 state->midi_option = prop->value ();
1905 state->midi_devices.clear();
1907 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1908 const XMLNodeList mnc = midinode->children();
1909 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1910 if ((*n)->property (X_("name")) == 0
1911 || (*n)->property (X_("enabled")) == 0
1912 || (*n)->property (X_("input-latency")) == 0
1913 || (*n)->property (X_("output-latency")) == 0
1918 MidiDeviceSettings ptr (new MidiDeviceSetting(
1919 (*n)->property (X_("name"))->value (),
1920 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1921 atoi ((*n)->property (X_("input-latency"))->value ()),
1922 atoi ((*n)->property (X_("output-latency"))->value ())
1924 state->midi_devices.push_back (ptr);
1929 /* remove accumulated duplicates (due to bug in ealier version)
1930 * this can be removed again before release
1932 for (StateList::iterator i = states.begin(); i != states.end();) {
1933 if ((*i)->backend == state->backend &&
1934 (*i)->driver == state->driver &&
1935 (*i)->device == state->device) {
1936 i = states.erase(i);
1943 states.push_back (state);
1947 /* now see if there was an active state and switch the setup to it */
1949 // purge states of backend that are not available in this built
1950 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1951 vector<std::string> backend_names;
1953 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1954 backend_names.push_back((*i)->name);
1956 for (StateList::iterator i = states.begin(); i != states.end();) {
1957 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1958 i = states.erase(i);
1964 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1967 return set_current_state (*i);
1974 EngineControl::set_current_state (const State& state)
1976 DEBUG_ECONTROL ("set_current_state");
1978 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1980 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1981 state->backend, downcase (PROGRAM_NAME), ""))) {
1982 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1983 // this shouldn't happen as the invalid backend names should have been
1984 // removed from the list of states.
1988 // now reflect the change in the backend in the GUI so backend_changed will
1989 // do the right thing
1990 backend_combo.set_active_text (state->backend);
1992 if (!state->driver.empty ()) {
1993 if (!backend->requires_driver_selection ()) {
1994 DEBUG_ECONTROL ("Backend should require driver selection");
1995 // A backend has changed from having driver selection to not having
1996 // it or someone has been manually editing a config file and messed
2001 if (backend->set_driver (state->driver) != 0) {
2002 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2003 // Driver names for a backend have changed and the name in the
2004 // config file is now invalid or support for driver is no longer
2005 // included in the backend
2008 // no need to set the driver_combo as backend_changed will use
2009 // backend->driver_name to set the active driver
2012 if (!state->device.empty ()) {
2013 if (backend->set_device_name (state->device) != 0) {
2015 string_compose ("Unable to set device name %1", state->device));
2016 // device is no longer available on the system
2019 // no need to set active device as it will be picked up in
2020 // via backend_changed ()/set_device_popdown_strings
2023 // backend supports separate input/output devices
2024 if (backend->set_input_device_name (state->input_device) != 0) {
2025 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2026 state->input_device));
2027 // input device is no longer available on the system
2031 if (backend->set_output_device_name (state->output_device) != 0) {
2032 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2033 state->input_device));
2034 // output device is no longer available on the system
2037 // no need to set active devices as it will be picked up in via
2038 // backend_changed ()/set_*_device_popdown_strings
2043 // Now restore the state of the rest of the controls
2045 // We don't use a SignalBlocker as set_current_state is currently only
2046 // called from set_state before any signals are connected. If at some point
2047 // a more general named state mechanism is implemented and
2048 // set_current_state is called while signals are connected then a
2049 // SignalBlocker will need to be instantiated before setting these.
2051 device_combo.set_active_text (state->device);
2052 input_device_combo.set_active_text (state->input_device);
2053 output_device_combo.set_active_text (state->output_device);
2054 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2055 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2056 input_latency.set_value (state->input_latency);
2057 output_latency.set_value (state->output_latency);
2058 midi_option_combo.set_active_text (state->midi_option);
2063 EngineControl::push_state_to_backend (bool start)
2065 DEBUG_ECONTROL ("push_state_to_backend");
2066 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2072 /* figure out what is going to change */
2074 bool restart_required = false;
2075 bool was_running = ARDOUR::AudioEngine::instance()->running();
2076 bool change_driver = false;
2077 bool change_device = false;
2078 bool change_rate = false;
2079 bool change_bufsize = false;
2080 bool change_latency = false;
2081 bool change_channels = false;
2082 bool change_midi = false;
2084 uint32_t ochan = get_output_channels ();
2085 uint32_t ichan = get_input_channels ();
2087 if (_have_control) {
2089 if (started_at_least_once) {
2091 /* we can control the backend */
2093 if (backend->requires_driver_selection()) {
2094 if (get_driver() != backend->driver_name()) {
2095 change_driver = true;
2099 if (backend->use_separate_input_and_output_devices()) {
2100 if (get_input_device_name() != backend->input_device_name()) {
2101 change_device = true;
2103 if (get_output_device_name() != backend->output_device_name()) {
2104 change_device = true;
2107 if (get_device_name() != backend->device_name()) {
2108 change_device = true;
2112 if (queue_device_changed) {
2113 change_device = true;
2116 if (get_rate() != backend->sample_rate()) {
2120 if (get_buffer_size() != backend->buffer_size()) {
2121 change_bufsize = true;
2124 if (get_midi_option() != backend->midi_option()) {
2128 /* zero-requested channels means "all available" */
2131 ichan = backend->input_channels();
2135 ochan = backend->output_channels();
2138 if (ichan != backend->input_channels()) {
2139 change_channels = true;
2142 if (ochan != backend->output_channels()) {
2143 change_channels = true;
2146 if (get_input_latency() != backend->systemic_input_latency() ||
2147 get_output_latency() != backend->systemic_output_latency()) {
2148 change_latency = true;
2151 /* backend never started, so we have to force a group
2154 change_device = true;
2155 if (backend->requires_driver_selection()) {
2156 change_driver = true;
2159 change_bufsize = true;
2160 change_channels = true;
2161 change_latency = true;
2167 /* we have no control over the backend, meaning that we can
2168 * only possibly change sample rate and buffer size.
2172 if (get_rate() != backend->sample_rate()) {
2173 change_bufsize = true;
2176 if (get_buffer_size() != backend->buffer_size()) {
2177 change_bufsize = true;
2181 queue_device_changed = false;
2183 if (!_have_control) {
2185 /* We do not have control over the backend, so the best we can
2186 * do is try to change the sample rate and/or bufsize and get
2190 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2194 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2199 backend->set_sample_rate (get_rate());
2202 if (change_bufsize) {
2203 backend->set_buffer_size (get_buffer_size());
2207 if (ARDOUR::AudioEngine::instance()->start ()) {
2208 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2218 /* determine if we need to stop the backend before changing parameters */
2220 if (change_driver || change_device || change_channels || change_latency ||
2221 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2223 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2224 restart_required = true;
2226 restart_required = false;
2231 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2232 /* no changes in any parameters that absolutely require a
2233 * restart, so check those that might be changeable without a
2237 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2238 /* can't do this while running ... */
2239 restart_required = true;
2242 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2243 /* can't do this while running ... */
2244 restart_required = true;
2250 if (restart_required) {
2251 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2258 if (change_driver && backend->set_driver (get_driver())) {
2259 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2262 if (backend->use_separate_input_and_output_devices()) {
2263 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2264 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2267 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2268 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2272 if (change_device && backend->set_device_name (get_device_name())) {
2273 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2277 if (change_rate && backend->set_sample_rate (get_rate())) {
2278 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2281 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2282 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2286 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2287 if (backend->set_input_channels (get_input_channels())) {
2288 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2291 if (backend->set_output_channels (get_output_channels())) {
2292 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2296 if (change_latency) {
2297 if (backend->set_systemic_input_latency (get_input_latency())) {
2298 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2301 if (backend->set_systemic_output_latency (get_output_latency())) {
2302 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2308 backend->set_midi_option (get_midi_option());
2312 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2313 if (_measure_midi) {
2314 if (*p == _measure_midi) {
2315 backend->set_midi_device_enabled ((*p)->name, true);
2317 backend->set_midi_device_enabled ((*p)->name, false);
2321 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2322 if (backend->can_set_systemic_midi_latencies()) {
2323 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2324 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2329 if (start || (was_running && restart_required)) {
2330 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2341 EngineControl::post_push ()
2343 /* get a pointer to the current state object, creating one if
2347 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2350 state = save_state ();
2358 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2359 (*i)->active = false;
2362 /* mark this one active (to be used next time the dialog is
2366 state->active = true;
2368 if (_have_control) { // XXX
2369 manage_control_app_sensitivity ();
2372 /* schedule a redisplay of MIDI ports */
2373 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2378 EngineControl::get_rate () const
2380 float r = atof (sample_rate_combo.get_active_text ());
2381 /* the string may have been translated with an abbreviation for
2382 * thousands, so use a crude heuristic to fix this.
2392 EngineControl::get_buffer_size () const
2394 string txt = buffer_size_combo.get_active_text ();
2397 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2398 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2399 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2407 EngineControl::get_midi_option () const
2409 return midi_option_combo.get_active_text();
2413 EngineControl::get_input_channels() const
2415 if (ARDOUR::Profile->get_mixbus()) {
2416 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2417 if (!backend) return 0;
2418 return backend->input_channels();
2420 return (uint32_t) input_channels_adjustment.get_value();
2424 EngineControl::get_output_channels() const
2426 if (ARDOUR::Profile->get_mixbus()) {
2427 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2428 if (!backend) return 0;
2429 return backend->input_channels();
2431 return (uint32_t) output_channels_adjustment.get_value();
2435 EngineControl::get_input_latency() const
2437 return (uint32_t) input_latency_adjustment.get_value();
2441 EngineControl::get_output_latency() const
2443 return (uint32_t) output_latency_adjustment.get_value();
2447 EngineControl::get_backend () const
2449 return backend_combo.get_active_text ();
2453 EngineControl::get_driver () const
2455 if (driver_combo.get_parent()) {
2456 return driver_combo.get_active_text ();
2463 EngineControl::get_device_name () const
2465 return device_combo.get_active_text ();
2469 EngineControl::get_input_device_name () const
2471 return input_device_combo.get_active_text ();
2475 EngineControl::get_output_device_name () const
2477 return output_device_combo.get_active_text ();
2481 EngineControl::control_app_button_clicked ()
2483 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2489 backend->launch_control_app ();
2493 EngineControl::start_stop_button_clicked ()
2495 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2501 if (ARDOUR::AudioEngine::instance()->running()) {
2502 ARDOUR::AudioEngine::instance()->stop ();
2504 push_state_to_backend (true);
2509 EngineControl::update_devices_button_clicked ()
2511 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2517 if (backend->update_devices()) {
2518 device_list_changed ();
2523 EngineControl::manage_control_app_sensitivity ()
2525 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2531 string appname = backend->control_app_name();
2533 if (appname.empty()) {
2534 control_app_button.set_sensitive (false);
2536 control_app_button.set_sensitive (true);
2541 EngineControl::set_desired_sample_rate (uint32_t sr)
2543 _desired_sample_rate = sr;
2548 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2550 if (page_num == 0) {
2551 cancel_button->set_sensitive (true);
2552 _measure_midi.reset();
2553 update_sensitivity ();
2555 cancel_button->set_sensitive (false);
2556 ok_button->set_sensitive (false);
2559 if (page_num == midi_tab) {
2561 refresh_midi_display ();
2564 if (page_num == latency_tab) {
2567 if (ARDOUR::AudioEngine::instance()->running()) {
2568 // TODO - mark as 'stopped for latency
2569 ARDOUR_UI::instance()->disconnect_from_engine ();
2573 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2575 /* save any existing latency values */
2577 uint32_t il = (uint32_t) input_latency.get_value ();
2578 uint32_t ol = (uint32_t) input_latency.get_value ();
2580 /* reset to zero so that our new test instance
2581 will be clean of any existing latency measures.
2583 NB. this should really be done by the backend
2584 when stated for latency measurement.
2587 input_latency.set_value (0);
2588 output_latency.set_value (0);
2590 push_state_to_backend (false);
2594 input_latency.set_value (il);
2595 output_latency.set_value (ol);
2598 // This should be done in push_state_to_backend()
2599 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2600 disable_latency_tab ();
2603 enable_latency_tab ();
2607 end_latency_detection ();
2608 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2613 /* latency measurement */
2616 EngineControl::check_audio_latency_measurement ()
2618 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2620 if (mtdm->resolve () < 0) {
2621 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2625 if (mtdm->err () > 0.3) {
2631 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2633 if (sample_rate == 0) {
2634 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2635 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2639 int frames_total = mtdm->del();
2640 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2642 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2643 _("Detected roundtrip latency: "),
2644 frames_total, frames_total * 1000.0f/sample_rate,
2645 _("Systemic latency: "),
2646 extra, extra * 1000.0f/sample_rate);
2650 if (mtdm->err () > 0.2) {
2652 strcat (buf, _("(signal detection error)"));
2658 strcat (buf, _("(inverted - bad wiring)"));
2662 lm_results.set_markup (string_compose (results_markup, buf));
2665 have_lm_results = true;
2666 end_latency_detection ();
2667 lm_use_button.set_sensitive (true);
2675 EngineControl::check_midi_latency_measurement ()
2677 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2679 if (!mididm->have_signal () || mididm->latency () == 0) {
2680 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2685 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2687 if (sample_rate == 0) {
2688 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2689 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2693 ARDOUR::framecnt_t frames_total = mididm->latency();
2694 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2695 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2696 _("Detected roundtrip latency: "),
2697 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2698 _("Systemic latency: "),
2699 extra, extra * 1000.0f / sample_rate);
2703 if (!mididm->ok ()) {
2705 strcat (buf, _("(averaging)"));
2709 if (mididm->deviation () > 50.0) {
2711 strcat (buf, _("(too large jitter)"));
2713 } else if (mididm->deviation () > 10.0) {
2715 strcat (buf, _("(large jitter)"));
2719 have_lm_results = true;
2720 end_latency_detection ();
2721 lm_use_button.set_sensitive (true);
2722 lm_results.set_markup (string_compose (results_markup, buf));
2724 } else if (mididm->processed () > 400) {
2725 have_lm_results = false;
2726 end_latency_detection ();
2727 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2731 lm_results.set_markup (string_compose (results_markup, buf));
2737 EngineControl::start_latency_detection ()
2739 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2740 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2742 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2743 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2744 if (_measure_midi) {
2745 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2747 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2749 lm_measure_label.set_text (_("Cancel"));
2750 have_lm_results = false;
2751 lm_use_button.set_sensitive (false);
2752 lm_input_channel_combo.set_sensitive (false);
2753 lm_output_channel_combo.set_sensitive (false);
2759 EngineControl::end_latency_detection ()
2761 latency_timeout.disconnect ();
2762 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2763 lm_measure_label.set_text (_("Measure"));
2764 if (!have_lm_results) {
2765 lm_use_button.set_sensitive (false);
2767 lm_input_channel_combo.set_sensitive (true);
2768 lm_output_channel_combo.set_sensitive (true);
2773 EngineControl::latency_button_clicked ()
2776 start_latency_detection ();
2778 end_latency_detection ();
2783 EngineControl::use_latency_button_clicked ()
2785 if (_measure_midi) {
2786 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2790 ARDOUR::framecnt_t frames_total = mididm->latency();
2791 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2792 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2793 _measure_midi->input_latency = one_way;
2794 _measure_midi->output_latency = one_way;
2795 notebook.set_current_page (midi_tab);
2797 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2803 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2804 one_way = std::max (0., one_way);
2806 input_latency_adjustment.set_value (one_way);
2807 output_latency_adjustment.set_value (one_way);
2809 /* back to settings page */
2810 notebook.set_current_page (0);
2816 EngineControl::on_delete_event (GdkEventAny* ev)
2818 if (notebook.get_current_page() == 2) {
2819 /* currently on latency tab - be sure to clean up */
2820 end_latency_detection ();
2822 return ArdourDialog::on_delete_event (ev);
2826 EngineControl::engine_running ()
2828 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2831 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2832 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2834 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2835 connect_disconnect_button.show();
2837 started_at_least_once = true;
2838 if (_have_control) {
2839 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2841 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2843 update_sensitivity();
2847 EngineControl::engine_stopped ()
2849 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2852 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2853 connect_disconnect_button.show();
2855 if (_have_control) {
2856 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2858 engine_status.set_markup(X_(""));
2861 update_sensitivity();
2865 EngineControl::device_list_changed ()
2867 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2869 midi_option_changed();
2873 EngineControl::connect_disconnect_click()
2875 if (ARDOUR::AudioEngine::instance()->running()) {
2876 ARDOUR_UI::instance()->disconnect_from_engine ();
2878 ARDOUR_UI::instance()->reconnect_to_engine ();
2883 EngineControl::calibrate_audio_latency ()
2885 _measure_midi.reset ();
2886 have_lm_results = false;
2887 lm_use_button.set_sensitive (false);
2888 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2889 notebook.set_current_page (latency_tab);
2893 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2896 have_lm_results = false;
2897 lm_use_button.set_sensitive (false);
2898 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2899 notebook.set_current_page (latency_tab);
2903 EngineControl::configure_midi_devices ()
2905 notebook.set_current_page (midi_tab);