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);
445 case RESPONSE_CANCEL:
446 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
447 ARDOUR_UI::instance()->check_audioengine ();
456 EngineControl::build_notebook ()
459 AttachOptions xopt = AttachOptions (FILL|EXPAND);
461 /* clear the table */
463 Gtkmm2ext::container_clear (basic_vbox);
464 Gtkmm2ext::container_clear (basic_packer);
466 if (control_app_button.get_parent()) {
467 control_app_button.get_parent()->remove (control_app_button);
470 label = manage (left_aligned_label (_("Audio System:")));
471 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
472 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
474 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
475 engine_status.show();
477 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
478 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
480 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
481 lm_button_audio.set_name ("generic button");
482 lm_button_audio.set_can_focus(true);
485 build_full_control_notebook ();
487 build_no_control_notebook ();
490 basic_vbox.pack_start (basic_hbox, false, false);
493 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
494 basic_vbox.show_all ();
499 EngineControl::build_full_control_notebook ()
501 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
504 using namespace Notebook_Helpers;
506 vector<string> strings;
507 AttachOptions xopt = AttachOptions (FILL|EXPAND);
508 int row = 1; // row zero == backend combo
510 /* start packing it up */
512 if (backend->requires_driver_selection()) {
513 label = manage (left_aligned_label (_("Driver:")));
514 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
515 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
519 if (backend->use_separate_input_and_output_devices()) {
520 label = manage (left_aligned_label (_("Input Device:")));
521 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
522 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
524 label = manage (left_aligned_label (_("Output Device:")));
525 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
526 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
528 // reset so it isn't used in state comparisons
529 device_combo.set_active_text ("");
531 label = manage (left_aligned_label (_("Device:")));
532 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
533 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
535 // reset these so they don't get used in state comparisons
536 input_device_combo.set_active_text ("");
537 output_device_combo.set_active_text ("");
540 label = manage (left_aligned_label (_("Sample rate:")));
541 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
542 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
546 label = manage (left_aligned_label (_("Buffer size:")));
547 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
548 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
549 buffer_size_duration_label.set_alignment (0.0); /* left-align */
550 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
552 /* button spans 2 rows */
554 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
557 input_channels.set_name ("InputChannels");
558 input_channels.set_flags (Gtk::CAN_FOCUS);
559 input_channels.set_digits (0);
560 input_channels.set_wrap (false);
561 output_channels.set_editable (true);
563 if (!ARDOUR::Profile->get_mixbus()) {
564 label = manage (left_aligned_label (_("Input Channels:")));
565 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
566 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
570 output_channels.set_name ("OutputChannels");
571 output_channels.set_flags (Gtk::CAN_FOCUS);
572 output_channels.set_digits (0);
573 output_channels.set_wrap (false);
574 output_channels.set_editable (true);
576 if (!ARDOUR::Profile->get_mixbus()) {
577 label = manage (left_aligned_label (_("Output Channels:")));
578 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
579 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
583 input_latency.set_name ("InputLatency");
584 input_latency.set_flags (Gtk::CAN_FOCUS);
585 input_latency.set_digits (0);
586 input_latency.set_wrap (false);
587 input_latency.set_editable (true);
589 label = manage (left_aligned_label (_("Hardware input latency:")));
590 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
591 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
592 label = manage (left_aligned_label (_("samples")));
593 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
596 output_latency.set_name ("OutputLatency");
597 output_latency.set_flags (Gtk::CAN_FOCUS);
598 output_latency.set_digits (0);
599 output_latency.set_wrap (false);
600 output_latency.set_editable (true);
602 label = manage (left_aligned_label (_("Hardware output latency:")));
603 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
604 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
605 label = manage (left_aligned_label (_("samples")));
606 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
608 /* button spans 2 rows */
610 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
613 label = manage (left_aligned_label (_("MIDI System:")));
614 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
615 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
616 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
617 /* Currently the only backend with dedicated Midi setup is ALSA.
618 * lot of people complain that this is greyed out
619 * "I can't use MIDI, the setup is greyed out"
621 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
627 EngineControl::build_no_control_notebook ()
629 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
632 using namespace Notebook_Helpers;
634 vector<string> strings;
635 AttachOptions xopt = AttachOptions (FILL|EXPAND);
636 int row = 1; // row zero == backend combo
637 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
639 label = manage (new Label);
640 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
641 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
644 if (backend->can_change_sample_rate_when_running()) {
645 label = manage (left_aligned_label (_("Sample rate:")));
646 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
647 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
651 if (backend->can_change_buffer_size_when_running()) {
652 label = manage (left_aligned_label (_("Buffer size:")));
653 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
654 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
655 buffer_size_duration_label.set_alignment (0.0); /* left-align */
656 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
660 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
664 EngineControl::~EngineControl ()
666 ignore_changes = true;
670 EngineControl::disable_latency_tab ()
672 vector<string> empty;
673 set_popdown_strings (lm_output_channel_combo, empty);
674 set_popdown_strings (lm_input_channel_combo, empty);
675 lm_measure_button.set_sensitive (false);
676 lm_use_button.set_sensitive (false);
680 EngineControl::enable_latency_tab ()
682 vector<string> outputs;
683 vector<string> inputs;
685 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
686 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
687 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
689 if (!ARDOUR::AudioEngine::instance()->running()) {
690 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
691 notebook.set_current_page (0);
695 else if (inputs.empty() || outputs.empty()) {
696 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
697 notebook.set_current_page (0);
702 lm_back_button_signal.disconnect();
704 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
707 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
711 set_popdown_strings (lm_output_channel_combo, outputs);
712 lm_output_channel_combo.set_active_text (outputs.front());
713 lm_output_channel_combo.set_sensitive (true);
715 set_popdown_strings (lm_input_channel_combo, inputs);
716 lm_input_channel_combo.set_active_text (inputs.front());
717 lm_input_channel_combo.set_sensitive (true);
719 lm_measure_button.set_sensitive (true);
723 EngineControl::setup_midi_tab_for_backend ()
725 string backend = backend_combo.get_active_text ();
727 Gtkmm2ext::container_clear (midi_vbox);
729 midi_vbox.set_border_width (12);
730 midi_device_table.set_border_width (12);
732 if (backend == "JACK") {
733 setup_midi_tab_for_jack ();
736 midi_vbox.pack_start (midi_device_table, true, true);
737 midi_vbox.pack_start (midi_back_button, false, false);
738 midi_vbox.show_all ();
742 EngineControl::update_sensitivity ()
744 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
746 ok_button->set_sensitive (false);
747 start_stop_button.set_sensitive (false);
752 size_t devices_available = 0;
754 if (backend->use_separate_input_and_output_devices ()) {
755 devices_available += get_popdown_string_count (input_device_combo);
756 devices_available += get_popdown_string_count (output_device_combo);
758 devices_available += get_popdown_string_count (device_combo);
761 if (devices_available == 0) {
763 input_latency.set_sensitive (false);
764 output_latency.set_sensitive (false);
765 input_channels.set_sensitive (false);
766 output_channels.set_sensitive (false);
768 input_latency.set_sensitive (true);
769 output_latency.set_sensitive (true);
770 input_channels.set_sensitive (true);
771 output_channels.set_sensitive (true);
774 if (get_popdown_string_count (buffer_size_combo) > 0) {
775 if (!ARDOUR::AudioEngine::instance()->running()) {
776 buffer_size_combo.set_sensitive (valid);
777 } else if (backend->can_change_sample_rate_when_running()) {
778 buffer_size_combo.set_sensitive (valid || !_have_control);
782 * Currently there is no way to manually stop the
783 * engine in order to re-configure it.
784 * This needs to remain sensitive for now.
786 * (it's also handy to implicily
787 * re-start the engine)
789 buffer_size_combo.set_sensitive (true);
791 buffer_size_combo.set_sensitive (false);
795 buffer_size_combo.set_sensitive (false);
799 if (get_popdown_string_count (sample_rate_combo) > 0) {
800 if (!ARDOUR::AudioEngine::instance()->running()) {
801 sample_rate_combo.set_sensitive (true);
803 sample_rate_combo.set_sensitive (false);
806 sample_rate_combo.set_sensitive (false);
811 start_stop_button.set_sensitive(true);
812 start_stop_button.show();
813 if (ARDOUR::AudioEngine::instance()->running()) {
814 start_stop_button.set_text("Stop");
815 update_devices_button.set_sensitive(false);
817 if (backend->can_request_update_devices()) {
818 update_devices_button.show();
820 update_devices_button.hide();
822 start_stop_button.set_text("Start");
823 update_devices_button.set_sensitive(true);
826 update_devices_button.set_sensitive(false);
827 update_devices_button.hide();
828 start_stop_button.set_sensitive(false);
829 start_stop_button.hide();
832 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
833 input_device_combo.set_sensitive (false);
834 output_device_combo.set_sensitive (false);
835 device_combo.set_sensitive (false);
836 driver_combo.set_sensitive (false);
838 input_device_combo.set_sensitive (true);
839 output_device_combo.set_sensitive (true);
840 device_combo.set_sensitive (true);
841 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
842 driver_combo.set_sensitive (true);
844 driver_combo.set_sensitive (false);
848 if (valid || !_have_control) {
849 ok_button->set_sensitive (true);
851 ok_button->set_sensitive (false);
856 EngineControl::setup_midi_tab_for_jack ()
861 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
863 device->input_latency = a->get_value();
865 device->output_latency = a->get_value();
870 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
871 b->set_active (!b->get_active());
872 device->enabled = b->get_active();
873 refresh_midi_display(device->name);
877 EngineControl::refresh_midi_display (std::string focus)
879 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
883 AttachOptions xopt = AttachOptions (FILL|EXPAND);
886 Gtkmm2ext::container_clear (midi_device_table);
888 midi_device_table.set_spacings (6);
890 l = manage (new Label);
891 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
892 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
893 l->set_alignment (0.5, 0.5);
897 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
898 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
899 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
900 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
902 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
903 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
904 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
905 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
908 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
913 bool enabled = (*p)->enabled;
915 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
916 m->set_name ("midi device");
917 m->set_can_focus (Gtk::CAN_FOCUS);
918 m->add_events (Gdk::BUTTON_RELEASE_MASK);
919 m->set_active (enabled);
920 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
921 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
922 if ((*p)->name == focus) {
926 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
927 s = manage (new Gtk::SpinButton (*a));
928 a->set_value ((*p)->input_latency);
929 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
930 s->set_sensitive (_can_set_midi_latencies && enabled);
931 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
933 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
934 s = manage (new Gtk::SpinButton (*a));
935 a->set_value ((*p)->output_latency);
936 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
937 s->set_sensitive (_can_set_midi_latencies && enabled);
938 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
940 b = manage (new Button (_("Calibrate")));
941 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
942 b->set_sensitive (_can_set_midi_latencies && enabled);
943 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
950 EngineControl::backend_changed ()
952 SignalBlocker blocker (*this, "backend_changed");
953 string backend_name = backend_combo.get_active_text();
954 boost::shared_ptr<ARDOUR::AudioBackend> backend;
956 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
957 /* eh? setting the backend failed... how ? */
958 /* A: stale config contains a backend that does not exist in current build */
962 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
964 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
967 setup_midi_tab_for_backend ();
968 _midi_devices.clear();
970 if (backend->requires_driver_selection()) {
971 if (set_driver_popdown_strings ()) {
975 /* this will change the device text which will cause a call to
976 * device changed which will set up parameters
981 update_midi_options ();
983 connect_disconnect_button.hide();
985 midi_option_changed();
987 started_at_least_once = false;
989 /* changing the backend implies stopping the engine
990 * ARDOUR::AudioEngine() may or may not emit this signal
991 * depending on previous engine state
993 engine_stopped (); // set "active/inactive"
995 if (!ignore_changes) {
996 maybe_display_saved_state ();
1001 EngineControl::update_midi_options ()
1003 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1004 vector<string> midi_options = backend->enumerate_midi_options();
1006 if (midi_options.size() == 1) {
1007 /* only contains the "none" option */
1008 midi_option_combo.set_sensitive (false);
1010 if (_have_control) {
1011 set_popdown_strings (midi_option_combo, midi_options);
1012 midi_option_combo.set_active_text (midi_options.front());
1013 midi_option_combo.set_sensitive (true);
1015 midi_option_combo.set_sensitive (false);
1021 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1023 if (ARDOUR::Profile->get_mixbus()) {
1027 uint32_t cnt = (uint32_t) sb->get_value();
1029 sb->set_text (_("all available channels"));
1032 snprintf (buf, sizeof (buf), "%d", cnt);
1038 // @return true if there are drivers available
1040 EngineControl::set_driver_popdown_strings ()
1042 DEBUG_ECONTROL ("set_driver_popdown_strings");
1043 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1044 vector<string> drivers = backend->enumerate_drivers();
1046 if (drivers.empty ()) {
1047 // This is an error...?
1051 string current_driver = backend->driver_name ();
1053 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1055 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1058 current_driver = drivers.front ();
1061 set_popdown_strings (driver_combo, drivers);
1063 string_compose ("driver_combo.set_active_text: %1", current_driver));
1064 driver_combo.set_active_text (current_driver);
1069 EngineControl::get_default_device(const string& current_device_name,
1070 const vector<string>& available_devices)
1072 // If the current device is available, use it as default
1073 if (std::find (available_devices.begin (),
1074 available_devices.end (),
1075 current_device_name) != available_devices.end ()) {
1077 return current_device_name;
1080 using namespace ARDOUR;
1082 string default_device_name =
1083 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1085 vector<string>::const_iterator i;
1087 // If there is a "Default" device available, use it
1088 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1089 if (*i == default_device_name) {
1094 string none_device_name =
1095 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1097 // Use the first device that isn't "None"
1098 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1099 if (*i != none_device_name) {
1104 // Use "None" if there are no other available
1105 return available_devices.front();
1108 // @return true if there are devices available
1110 EngineControl::set_device_popdown_strings ()
1112 DEBUG_ECONTROL ("set_device_popdown_strings");
1113 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1114 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1116 /* NOTE: Ardour currently does not display the "available" field of the
1119 * Doing so would require a different GUI widget than the combo
1120 * box/popdown that we currently use, since it has no way to list
1121 * items that are not selectable. Something more like a popup menu,
1122 * which could have unselectable items, would be appropriate.
1125 vector<string> available_devices;
1127 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1128 available_devices.push_back (i->name);
1131 if (available_devices.empty ()) {
1135 set_popdown_strings (device_combo, available_devices);
1137 std::string default_device =
1138 get_default_device(backend->device_name(), available_devices);
1141 string_compose ("set device_combo active text: %1", default_device));
1143 device_combo.set_active_text(default_device);
1147 // @return true if there are input devices available
1149 EngineControl::set_input_device_popdown_strings ()
1151 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1152 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1153 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1155 vector<string> available_devices;
1157 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1158 available_devices.push_back (i->name);
1161 if (available_devices.empty()) {
1165 set_popdown_strings (input_device_combo, available_devices);
1167 std::string default_device =
1168 get_default_device(backend->input_device_name(), available_devices);
1171 string_compose ("set input_device_combo active text: %1", default_device));
1172 input_device_combo.set_active_text(default_device);
1176 // @return true if there are output devices available
1178 EngineControl::set_output_device_popdown_strings ()
1180 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1181 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1182 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1184 vector<string> available_devices;
1186 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1187 available_devices.push_back (i->name);
1190 if (available_devices.empty()) {
1194 set_popdown_strings (output_device_combo, available_devices);
1196 std::string default_device =
1197 get_default_device(backend->output_device_name(), available_devices);
1200 string_compose ("set output_device_combo active text: %1", default_device));
1201 output_device_combo.set_active_text(default_device);
1206 EngineControl::list_devices ()
1208 DEBUG_ECONTROL ("list_devices");
1209 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1212 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1214 bool devices_available = false;
1216 if (backend->use_separate_input_and_output_devices ()) {
1217 bool input_devices_available = set_input_device_popdown_strings ();
1218 bool output_devices_available = set_output_device_popdown_strings ();
1219 devices_available = input_devices_available || output_devices_available;
1221 devices_available = set_device_popdown_strings ();
1224 if (devices_available) {
1227 device_combo.clear();
1228 input_device_combo.clear();
1229 output_device_combo.clear();
1231 update_sensitivity ();
1235 EngineControl::driver_changed ()
1237 SignalBlocker blocker (*this, "driver_changed");
1238 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1241 backend->set_driver (driver_combo.get_active_text());
1244 if (!ignore_changes) {
1245 maybe_display_saved_state ();
1250 EngineControl::get_sample_rates_for_all_devices ()
1252 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1253 ARDOUR::AudioEngine::instance ()->current_backend ();
1254 vector<float> all_rates;
1256 if (backend->use_separate_input_and_output_devices ()) {
1257 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1259 all_rates = backend->available_sample_rates (get_device_name ());
1265 EngineControl::get_default_sample_rates ()
1267 vector<float> rates;
1268 rates.push_back (8000.0f);
1269 rates.push_back (16000.0f);
1270 rates.push_back (32000.0f);
1271 rates.push_back (44100.0f);
1272 rates.push_back (48000.0f);
1273 rates.push_back (88200.0f);
1274 rates.push_back (96000.0f);
1275 rates.push_back (192000.0f);
1276 rates.push_back (384000.0f);
1281 EngineControl::set_samplerate_popdown_strings ()
1283 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1284 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1289 if (_have_control) {
1290 sr = get_sample_rates_for_all_devices ();
1292 sr = get_default_sample_rates ();
1295 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1296 s.push_back (rate_as_string (*x));
1297 if (*x == _desired_sample_rate) {
1302 set_popdown_strings (sample_rate_combo, s);
1305 if (desired.empty ()) {
1306 float new_active_sr = backend->default_sample_rate ();
1308 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1309 new_active_sr = sr.front ();
1312 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1314 sample_rate_combo.set_active_text (desired);
1318 update_sensitivity ();
1322 EngineControl::get_buffer_sizes_for_all_devices ()
1324 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1325 ARDOUR::AudioEngine::instance ()->current_backend ();
1326 vector<uint32_t> all_sizes;
1328 if (backend->use_separate_input_and_output_devices ()) {
1329 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1331 all_sizes = backend->available_buffer_sizes (get_device_name ());
1337 EngineControl::get_default_buffer_sizes ()
1339 vector<uint32_t> sizes;
1340 sizes.push_back (8);
1341 sizes.push_back (16);
1342 sizes.push_back (32);
1343 sizes.push_back (64);
1344 sizes.push_back (128);
1345 sizes.push_back (256);
1346 sizes.push_back (512);
1347 sizes.push_back (1024);
1348 sizes.push_back (2048);
1349 sizes.push_back (4096);
1350 sizes.push_back (8192);
1355 EngineControl::set_buffersize_popdown_strings ()
1357 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1358 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1359 vector<uint32_t> bs;
1362 if (_have_control) {
1363 bs = get_buffer_sizes_for_all_devices ();
1364 } else if (backend->can_change_buffer_size_when_running()) {
1365 bs = get_default_buffer_sizes ();
1368 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1369 s.push_back (bufsize_as_string (*x));
1372 uint32_t previous_size = 0;
1373 if (!buffer_size_combo.get_active_text().empty()) {
1374 previous_size = get_buffer_size ();
1377 set_popdown_strings (buffer_size_combo, s);
1381 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1382 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1385 buffer_size_combo.set_active_text(s.front());
1387 uint32_t period = backend->buffer_size();
1388 if (0 == period && backend->use_separate_input_and_output_devices()) {
1389 period = backend->default_buffer_size(get_input_device_name());
1391 if (0 == period && backend->use_separate_input_and_output_devices()) {
1392 period = backend->default_buffer_size(get_output_device_name());
1394 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1395 period = backend->default_buffer_size(get_device_name());
1398 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1400 show_buffer_duration ();
1402 update_sensitivity ();
1406 EngineControl::device_changed ()
1408 SignalBlocker blocker (*this, "device_changed");
1409 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1412 string device_name_in;
1413 string device_name_out; // only used if backend support separate I/O devices
1415 if (backend->use_separate_input_and_output_devices()) {
1416 device_name_in = get_input_device_name ();
1417 device_name_out = get_output_device_name ();
1419 device_name_in = get_device_name ();
1422 /* we set the backend-device to query various device related intormation.
1423 * This has the side effect that backend->device_name() will match
1424 * the device_name and 'change_device' will never be true.
1425 * so work around this by setting...
1427 if (backend->use_separate_input_and_output_devices()) {
1428 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1429 queue_device_changed = true;
1432 if (device_name_in != backend->device_name()) {
1433 queue_device_changed = true;
1437 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1438 if (backend->use_separate_input_and_output_devices()) {
1439 backend->set_input_device_name (device_name_in);
1440 backend->set_output_device_name (device_name_out);
1442 backend->set_device_name(device_name_in);
1446 /* don't allow programmatic change to combos to cause a
1447 recursive call to this method.
1449 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1451 set_samplerate_popdown_strings ();
1452 set_buffersize_popdown_strings ();
1454 /* TODO set min + max channel counts here */
1456 manage_control_app_sensitivity ();
1459 /* pick up any saved state for this device */
1461 if (!ignore_changes) {
1462 maybe_display_saved_state ();
1467 EngineControl::input_device_changed ()
1469 DEBUG_ECONTROL ("input_device_changed");
1474 EngineControl::output_device_changed ()
1476 DEBUG_ECONTROL ("output_device_changed");
1481 EngineControl::bufsize_as_string (uint32_t sz)
1483 /* Translators: "samples" is always plural here, so no
1484 need for plural+singular forms.
1487 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1492 EngineControl::sample_rate_changed ()
1494 DEBUG_ECONTROL ("sample_rate_changed");
1495 /* reset the strings for buffer size to show the correct msec value
1496 (reflecting the new sample rate).
1499 show_buffer_duration ();
1504 EngineControl::buffer_size_changed ()
1506 DEBUG_ECONTROL ("buffer_size_changed");
1507 show_buffer_duration ();
1511 EngineControl::show_buffer_duration ()
1513 DEBUG_ECONTROL ("show_buffer_duration");
1514 /* buffer sizes - convert from just samples to samples + msecs for
1515 * the displayed string
1518 string bs_text = buffer_size_combo.get_active_text ();
1519 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1520 uint32_t rate = get_rate();
1522 /* Developers: note the hard-coding of a double buffered model
1523 in the (2 * samples) computation of latency. we always start
1524 the audiobackend in this configuration.
1526 /* note to jack1 developers: ardour also always starts the engine
1527 * in async mode (no jack2 --sync option) which adds an extra cycle
1528 * of latency with jack2 (and *3 would be correct)
1529 * The value can also be wrong if jackd is started externally..
1531 * At the time of writing the ALSA backend always uses double-buffering *2,
1532 * The Dummy backend *1, and who knows what ASIO really does :)
1534 * So just display the period size, that's also what
1535 * ARDOUR_UI::update_sample_rate() does for the status bar.
1536 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1537 * but still, that's the buffer period, not [round-trip] latency)
1540 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1541 buffer_size_duration_label.set_text (buf);
1545 EngineControl::midi_option_changed ()
1547 DEBUG_ECONTROL ("midi_option_changed");
1548 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1551 backend->set_midi_option (get_midi_option());
1553 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1555 //_midi_devices.clear(); // TODO merge with state-saved settings..
1556 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1557 std::vector<MidiDeviceSettings> new_devices;
1559 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1560 MidiDeviceSettings mds = find_midi_device (i->name);
1561 if (i->available && !mds) {
1562 uint32_t input_latency = 0;
1563 uint32_t output_latency = 0;
1564 if (_can_set_midi_latencies) {
1565 input_latency = backend->systemic_midi_input_latency (i->name);
1566 output_latency = backend->systemic_midi_output_latency (i->name);
1568 bool enabled = backend->midi_device_enabled (i->name);
1569 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1570 new_devices.push_back (ptr);
1571 } else if (i->available) {
1572 new_devices.push_back (mds);
1575 _midi_devices = new_devices;
1577 if (_midi_devices.empty()) {
1578 midi_devices_button.set_sensitive (false);
1580 midi_devices_button.set_sensitive (true);
1585 EngineControl::parameter_changed ()
1589 EngineControl::State
1590 EngineControl::get_matching_state (
1591 const string& backend,
1592 const string& driver,
1593 const string& device)
1595 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1596 if ((*i)->backend == backend &&
1597 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1605 EngineControl::State
1606 EngineControl::get_matching_state (
1607 const string& backend,
1608 const string& driver,
1609 const string& input_device,
1610 const string& output_device)
1612 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1613 if ((*i)->backend == backend &&
1614 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1622 EngineControl::State
1623 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1625 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1628 if (backend->use_separate_input_and_output_devices ()) {
1629 return get_matching_state (backend_combo.get_active_text(),
1630 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1631 input_device_combo.get_active_text(),
1632 output_device_combo.get_active_text());
1634 return get_matching_state (backend_combo.get_active_text(),
1635 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1636 device_combo.get_active_text());
1640 return get_matching_state (backend_combo.get_active_text(),
1642 device_combo.get_active_text());
1645 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1646 const EngineControl::State& state2)
1648 if (state1->backend == state2->backend &&
1649 state1->driver == state2->driver &&
1650 state1->device == state2->device &&
1651 state1->input_device == state2->input_device &&
1652 state1->output_device == state2->output_device) {
1658 EngineControl::State
1659 EngineControl::save_state ()
1663 if (!_have_control) {
1664 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1668 state.reset(new StateStruct);
1669 state->backend = get_backend ();
1671 state.reset(new StateStruct);
1672 store_state (state);
1675 for (StateList::iterator i = states.begin(); i != states.end();) {
1676 if (equivalent_states (*i, state)) {
1677 i = states.erase(i);
1683 states.push_back (state);
1689 EngineControl::store_state (State state)
1691 state->backend = get_backend ();
1692 state->driver = get_driver ();
1693 state->device = get_device_name ();
1694 state->input_device = get_input_device_name ();
1695 state->output_device = get_output_device_name ();
1696 state->sample_rate = get_rate ();
1697 state->buffer_size = get_buffer_size ();
1698 state->input_latency = get_input_latency ();
1699 state->output_latency = get_output_latency ();
1700 state->input_channels = get_input_channels ();
1701 state->output_channels = get_output_channels ();
1702 state->midi_option = get_midi_option ();
1703 state->midi_devices = _midi_devices;
1707 EngineControl::maybe_display_saved_state ()
1709 if (!_have_control) {
1713 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1716 DEBUG_ECONTROL ("Restoring saved state");
1717 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1719 if (!_desired_sample_rate) {
1720 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1722 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1723 /* call this explicitly because we're ignoring changes to
1724 the controls at this point.
1726 show_buffer_duration ();
1727 input_latency.set_value (state->input_latency);
1728 output_latency.set_value (state->output_latency);
1730 if (!state->midi_option.empty()) {
1731 midi_option_combo.set_active_text (state->midi_option);
1732 _midi_devices = state->midi_devices;
1735 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1740 EngineControl::get_state ()
1742 LocaleGuard lg (X_("C"));
1744 XMLNode* root = new XMLNode ("AudioMIDISetup");
1747 if (!states.empty()) {
1748 XMLNode* state_nodes = new XMLNode ("EngineStates");
1750 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1752 XMLNode* node = new XMLNode ("State");
1754 node->add_property ("backend", (*i)->backend);
1755 node->add_property ("driver", (*i)->driver);
1756 node->add_property ("device", (*i)->device);
1757 node->add_property ("input-device", (*i)->input_device);
1758 node->add_property ("output-device", (*i)->output_device);
1759 node->add_property ("sample-rate", (*i)->sample_rate);
1760 node->add_property ("buffer-size", (*i)->buffer_size);
1761 node->add_property ("input-latency", (*i)->input_latency);
1762 node->add_property ("output-latency", (*i)->output_latency);
1763 node->add_property ("input-channels", (*i)->input_channels);
1764 node->add_property ("output-channels", (*i)->output_channels);
1765 node->add_property ("active", (*i)->active ? "yes" : "no");
1766 node->add_property ("midi-option", (*i)->midi_option);
1768 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1769 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1770 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1771 midi_device_stuff->add_property (X_("name"), (*p)->name);
1772 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1773 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1774 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1775 midi_devices->add_child_nocopy (*midi_device_stuff);
1777 node->add_child_nocopy (*midi_devices);
1779 state_nodes->add_child_nocopy (*node);
1782 root->add_child_nocopy (*state_nodes);
1789 EngineControl::set_default_state ()
1791 vector<string> backend_names;
1792 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1794 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1795 backend_names.push_back ((*b)->name);
1797 backend_combo.set_active_text (backend_names.front());
1799 // We could set default backends per platform etc here
1805 EngineControl::set_state (const XMLNode& root)
1807 XMLNodeList clist, cclist;
1808 XMLNodeConstIterator citer, cciter;
1810 XMLNode* grandchild;
1811 XMLProperty* prop = NULL;
1813 fprintf (stderr, "EngineControl::set_state\n");
1815 if (root.name() != "AudioMIDISetup") {
1819 clist = root.children();
1823 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1827 if (child->name() != "EngineStates") {
1831 cclist = child->children();
1833 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1834 State state (new StateStruct);
1836 grandchild = *cciter;
1838 if (grandchild->name() != "State") {
1842 if ((prop = grandchild->property ("backend")) == 0) {
1845 state->backend = prop->value ();
1847 if ((prop = grandchild->property ("driver")) == 0) {
1850 state->driver = prop->value ();
1852 if ((prop = grandchild->property ("device")) == 0) {
1855 state->device = prop->value ();
1857 if ((prop = grandchild->property ("input-device")) == 0) {
1860 state->input_device = prop->value ();
1862 if ((prop = grandchild->property ("output-device")) == 0) {
1865 state->output_device = prop->value ();
1867 if ((prop = grandchild->property ("sample-rate")) == 0) {
1870 state->sample_rate = atof (prop->value ());
1872 if ((prop = grandchild->property ("buffer-size")) == 0) {
1875 state->buffer_size = atoi (prop->value ());
1877 if ((prop = grandchild->property ("input-latency")) == 0) {
1880 state->input_latency = atoi (prop->value ());
1882 if ((prop = grandchild->property ("output-latency")) == 0) {
1885 state->output_latency = atoi (prop->value ());
1887 if ((prop = grandchild->property ("input-channels")) == 0) {
1890 state->input_channels = atoi (prop->value ());
1892 if ((prop = grandchild->property ("output-channels")) == 0) {
1895 state->output_channels = atoi (prop->value ());
1897 if ((prop = grandchild->property ("active")) == 0) {
1900 state->active = string_is_affirmative (prop->value ());
1902 if ((prop = grandchild->property ("midi-option")) == 0) {
1905 state->midi_option = prop->value ();
1907 state->midi_devices.clear();
1909 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1910 const XMLNodeList mnc = midinode->children();
1911 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1912 if ((*n)->property (X_("name")) == 0
1913 || (*n)->property (X_("enabled")) == 0
1914 || (*n)->property (X_("input-latency")) == 0
1915 || (*n)->property (X_("output-latency")) == 0
1920 MidiDeviceSettings ptr (new MidiDeviceSetting(
1921 (*n)->property (X_("name"))->value (),
1922 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1923 atoi ((*n)->property (X_("input-latency"))->value ()),
1924 atoi ((*n)->property (X_("output-latency"))->value ())
1926 state->midi_devices.push_back (ptr);
1931 /* remove accumulated duplicates (due to bug in ealier version)
1932 * this can be removed again before release
1934 for (StateList::iterator i = states.begin(); i != states.end();) {
1935 if ((*i)->backend == state->backend &&
1936 (*i)->driver == state->driver &&
1937 (*i)->device == state->device) {
1938 i = states.erase(i);
1945 states.push_back (state);
1949 /* now see if there was an active state and switch the setup to it */
1951 // purge states of backend that are not available in this built
1952 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1953 vector<std::string> backend_names;
1955 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1956 backend_names.push_back((*i)->name);
1958 for (StateList::iterator i = states.begin(); i != states.end();) {
1959 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1960 i = states.erase(i);
1966 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1969 return set_current_state (*i);
1976 EngineControl::set_current_state (const State& state)
1978 DEBUG_ECONTROL ("set_current_state");
1980 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1982 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1983 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
1984 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1985 // this shouldn't happen as the invalid backend names should have been
1986 // removed from the list of states.
1990 // now reflect the change in the backend in the GUI so backend_changed will
1991 // do the right thing
1992 backend_combo.set_active_text (state->backend);
1994 if (!state->driver.empty ()) {
1995 if (!backend->requires_driver_selection ()) {
1996 DEBUG_ECONTROL ("Backend should require driver selection");
1997 // A backend has changed from having driver selection to not having
1998 // it or someone has been manually editing a config file and messed
2003 if (backend->set_driver (state->driver) != 0) {
2004 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2005 // Driver names for a backend have changed and the name in the
2006 // config file is now invalid or support for driver is no longer
2007 // included in the backend
2010 // no need to set the driver_combo as backend_changed will use
2011 // backend->driver_name to set the active driver
2014 if (!state->device.empty ()) {
2015 if (backend->set_device_name (state->device) != 0) {
2017 string_compose ("Unable to set device name %1", state->device));
2018 // device is no longer available on the system
2021 // no need to set active device as it will be picked up in
2022 // via backend_changed ()/set_device_popdown_strings
2025 // backend supports separate input/output devices
2026 if (backend->set_input_device_name (state->input_device) != 0) {
2027 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2028 state->input_device));
2029 // input device is no longer available on the system
2033 if (backend->set_output_device_name (state->output_device) != 0) {
2034 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2035 state->input_device));
2036 // output device is no longer available on the system
2039 // no need to set active devices as it will be picked up in via
2040 // backend_changed ()/set_*_device_popdown_strings
2045 // Now restore the state of the rest of the controls
2047 // We don't use a SignalBlocker as set_current_state is currently only
2048 // called from set_state before any signals are connected. If at some point
2049 // a more general named state mechanism is implemented and
2050 // set_current_state is called while signals are connected then a
2051 // SignalBlocker will need to be instantiated before setting these.
2053 device_combo.set_active_text (state->device);
2054 input_device_combo.set_active_text (state->input_device);
2055 output_device_combo.set_active_text (state->output_device);
2056 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2057 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2058 input_latency.set_value (state->input_latency);
2059 output_latency.set_value (state->output_latency);
2060 midi_option_combo.set_active_text (state->midi_option);
2065 EngineControl::push_state_to_backend (bool start)
2067 DEBUG_ECONTROL ("push_state_to_backend");
2068 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2074 /* figure out what is going to change */
2076 bool restart_required = false;
2077 bool was_running = ARDOUR::AudioEngine::instance()->running();
2078 bool change_driver = false;
2079 bool change_device = false;
2080 bool change_rate = false;
2081 bool change_bufsize = false;
2082 bool change_latency = false;
2083 bool change_channels = false;
2084 bool change_midi = false;
2086 uint32_t ochan = get_output_channels ();
2087 uint32_t ichan = get_input_channels ();
2089 if (_have_control) {
2091 if (started_at_least_once) {
2093 /* we can control the backend */
2095 if (backend->requires_driver_selection()) {
2096 if (get_driver() != backend->driver_name()) {
2097 change_driver = true;
2101 if (backend->use_separate_input_and_output_devices()) {
2102 if (get_input_device_name() != backend->input_device_name()) {
2103 change_device = true;
2105 if (get_output_device_name() != backend->output_device_name()) {
2106 change_device = true;
2109 if (get_device_name() != backend->device_name()) {
2110 change_device = true;
2114 if (queue_device_changed) {
2115 change_device = true;
2118 if (get_rate() != backend->sample_rate()) {
2122 if (get_buffer_size() != backend->buffer_size()) {
2123 change_bufsize = true;
2126 if (get_midi_option() != backend->midi_option()) {
2130 /* zero-requested channels means "all available" */
2133 ichan = backend->input_channels();
2137 ochan = backend->output_channels();
2140 if (ichan != backend->input_channels()) {
2141 change_channels = true;
2144 if (ochan != backend->output_channels()) {
2145 change_channels = true;
2148 if (get_input_latency() != backend->systemic_input_latency() ||
2149 get_output_latency() != backend->systemic_output_latency()) {
2150 change_latency = true;
2153 /* backend never started, so we have to force a group
2156 change_device = true;
2157 if (backend->requires_driver_selection()) {
2158 change_driver = true;
2161 change_bufsize = true;
2162 change_channels = true;
2163 change_latency = true;
2169 /* we have no control over the backend, meaning that we can
2170 * only possibly change sample rate and buffer size.
2174 if (get_rate() != backend->sample_rate()) {
2175 change_bufsize = true;
2178 if (get_buffer_size() != backend->buffer_size()) {
2179 change_bufsize = true;
2183 queue_device_changed = false;
2185 if (!_have_control) {
2187 /* We do not have control over the backend, so the best we can
2188 * do is try to change the sample rate and/or bufsize and get
2192 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2196 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2201 backend->set_sample_rate (get_rate());
2204 if (change_bufsize) {
2205 backend->set_buffer_size (get_buffer_size());
2209 if (ARDOUR::AudioEngine::instance()->start ()) {
2210 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2220 /* determine if we need to stop the backend before changing parameters */
2222 if (change_driver || change_device || change_channels || change_latency ||
2223 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2225 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2226 restart_required = true;
2228 restart_required = false;
2233 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2234 /* no changes in any parameters that absolutely require a
2235 * restart, so check those that might be changeable without a
2239 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2240 /* can't do this while running ... */
2241 restart_required = true;
2244 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2245 /* can't do this while running ... */
2246 restart_required = true;
2252 if (restart_required) {
2253 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2260 if (change_driver && backend->set_driver (get_driver())) {
2261 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2264 if (backend->use_separate_input_and_output_devices()) {
2265 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2266 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2269 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2270 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2274 if (change_device && backend->set_device_name (get_device_name())) {
2275 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2279 if (change_rate && backend->set_sample_rate (get_rate())) {
2280 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2283 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2284 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2288 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2289 if (backend->set_input_channels (get_input_channels())) {
2290 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2293 if (backend->set_output_channels (get_output_channels())) {
2294 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2298 if (change_latency) {
2299 if (backend->set_systemic_input_latency (get_input_latency())) {
2300 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2303 if (backend->set_systemic_output_latency (get_output_latency())) {
2304 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2310 backend->set_midi_option (get_midi_option());
2314 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2315 if (_measure_midi) {
2316 if (*p == _measure_midi) {
2317 backend->set_midi_device_enabled ((*p)->name, true);
2319 backend->set_midi_device_enabled ((*p)->name, false);
2323 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2324 if (backend->can_set_systemic_midi_latencies()) {
2325 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2326 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2331 if (start || (was_running && restart_required)) {
2332 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2343 EngineControl::post_push ()
2345 /* get a pointer to the current state object, creating one if
2349 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2352 state = save_state ();
2360 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2361 (*i)->active = false;
2364 /* mark this one active (to be used next time the dialog is
2368 state->active = true;
2370 if (_have_control) { // XXX
2371 manage_control_app_sensitivity ();
2374 /* schedule a redisplay of MIDI ports */
2375 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2380 EngineControl::get_rate () const
2382 float r = atof (sample_rate_combo.get_active_text ());
2383 /* the string may have been translated with an abbreviation for
2384 * thousands, so use a crude heuristic to fix this.
2394 EngineControl::get_buffer_size () const
2396 string txt = buffer_size_combo.get_active_text ();
2399 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2400 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2401 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2409 EngineControl::get_midi_option () const
2411 return midi_option_combo.get_active_text();
2415 EngineControl::get_input_channels() const
2417 if (ARDOUR::Profile->get_mixbus()) {
2418 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2419 if (!backend) return 0;
2420 return backend->input_channels();
2422 return (uint32_t) input_channels_adjustment.get_value();
2426 EngineControl::get_output_channels() const
2428 if (ARDOUR::Profile->get_mixbus()) {
2429 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2430 if (!backend) return 0;
2431 return backend->input_channels();
2433 return (uint32_t) output_channels_adjustment.get_value();
2437 EngineControl::get_input_latency() const
2439 return (uint32_t) input_latency_adjustment.get_value();
2443 EngineControl::get_output_latency() const
2445 return (uint32_t) output_latency_adjustment.get_value();
2449 EngineControl::get_backend () const
2451 return backend_combo.get_active_text ();
2455 EngineControl::get_driver () const
2457 if (driver_combo.get_parent()) {
2458 return driver_combo.get_active_text ();
2465 EngineControl::get_device_name () const
2467 return device_combo.get_active_text ();
2471 EngineControl::get_input_device_name () const
2473 return input_device_combo.get_active_text ();
2477 EngineControl::get_output_device_name () const
2479 return output_device_combo.get_active_text ();
2483 EngineControl::control_app_button_clicked ()
2485 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2491 backend->launch_control_app ();
2495 EngineControl::start_stop_button_clicked ()
2497 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2503 if (ARDOUR::AudioEngine::instance()->running()) {
2504 ARDOUR::AudioEngine::instance()->stop ();
2506 push_state_to_backend (true);
2511 EngineControl::update_devices_button_clicked ()
2513 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2519 if (backend->update_devices()) {
2520 device_list_changed ();
2525 EngineControl::manage_control_app_sensitivity ()
2527 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2533 string appname = backend->control_app_name();
2535 if (appname.empty()) {
2536 control_app_button.set_sensitive (false);
2538 control_app_button.set_sensitive (true);
2543 EngineControl::set_desired_sample_rate (uint32_t sr)
2545 _desired_sample_rate = sr;
2550 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2552 if (page_num == 0) {
2553 cancel_button->set_sensitive (true);
2554 _measure_midi.reset();
2555 update_sensitivity ();
2557 cancel_button->set_sensitive (false);
2558 ok_button->set_sensitive (false);
2561 if (page_num == midi_tab) {
2563 refresh_midi_display ();
2566 if (page_num == latency_tab) {
2569 if (ARDOUR::AudioEngine::instance()->running()) {
2570 // TODO - mark as 'stopped for latency
2571 ARDOUR_UI::instance()->disconnect_from_engine ();
2575 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2577 /* save any existing latency values */
2579 uint32_t il = (uint32_t) input_latency.get_value ();
2580 uint32_t ol = (uint32_t) input_latency.get_value ();
2582 /* reset to zero so that our new test instance
2583 will be clean of any existing latency measures.
2585 NB. this should really be done by the backend
2586 when stated for latency measurement.
2589 input_latency.set_value (0);
2590 output_latency.set_value (0);
2592 push_state_to_backend (false);
2596 input_latency.set_value (il);
2597 output_latency.set_value (ol);
2600 // This should be done in push_state_to_backend()
2601 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2602 disable_latency_tab ();
2605 enable_latency_tab ();
2609 end_latency_detection ();
2610 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2615 /* latency measurement */
2618 EngineControl::check_audio_latency_measurement ()
2620 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2622 if (mtdm->resolve () < 0) {
2623 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2627 if (mtdm->err () > 0.3) {
2633 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2635 if (sample_rate == 0) {
2636 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2637 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2641 int frames_total = mtdm->del();
2642 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2644 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2645 _("Detected roundtrip latency: "),
2646 frames_total, frames_total * 1000.0f/sample_rate,
2647 _("Systemic latency: "),
2648 extra, extra * 1000.0f/sample_rate);
2652 if (mtdm->err () > 0.2) {
2654 strcat (buf, _("(signal detection error)"));
2660 strcat (buf, _("(inverted - bad wiring)"));
2664 lm_results.set_markup (string_compose (results_markup, buf));
2667 have_lm_results = true;
2668 end_latency_detection ();
2669 lm_use_button.set_sensitive (true);
2677 EngineControl::check_midi_latency_measurement ()
2679 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2681 if (!mididm->have_signal () || mididm->latency () == 0) {
2682 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2687 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2689 if (sample_rate == 0) {
2690 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2691 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2695 ARDOUR::framecnt_t frames_total = mididm->latency();
2696 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2697 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2698 _("Detected roundtrip latency: "),
2699 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2700 _("Systemic latency: "),
2701 extra, extra * 1000.0f / sample_rate);
2705 if (!mididm->ok ()) {
2707 strcat (buf, _("(averaging)"));
2711 if (mididm->deviation () > 50.0) {
2713 strcat (buf, _("(too large jitter)"));
2715 } else if (mididm->deviation () > 10.0) {
2717 strcat (buf, _("(large jitter)"));
2721 have_lm_results = true;
2722 end_latency_detection ();
2723 lm_use_button.set_sensitive (true);
2724 lm_results.set_markup (string_compose (results_markup, buf));
2726 } else if (mididm->processed () > 400) {
2727 have_lm_results = false;
2728 end_latency_detection ();
2729 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2733 lm_results.set_markup (string_compose (results_markup, buf));
2739 EngineControl::start_latency_detection ()
2741 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2742 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2744 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2745 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2746 if (_measure_midi) {
2747 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2749 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2751 lm_measure_label.set_text (_("Cancel"));
2752 have_lm_results = false;
2753 lm_use_button.set_sensitive (false);
2754 lm_input_channel_combo.set_sensitive (false);
2755 lm_output_channel_combo.set_sensitive (false);
2761 EngineControl::end_latency_detection ()
2763 latency_timeout.disconnect ();
2764 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2765 lm_measure_label.set_text (_("Measure"));
2766 if (!have_lm_results) {
2767 lm_use_button.set_sensitive (false);
2769 lm_input_channel_combo.set_sensitive (true);
2770 lm_output_channel_combo.set_sensitive (true);
2775 EngineControl::latency_button_clicked ()
2778 start_latency_detection ();
2780 end_latency_detection ();
2785 EngineControl::use_latency_button_clicked ()
2787 if (_measure_midi) {
2788 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2792 ARDOUR::framecnt_t frames_total = mididm->latency();
2793 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2794 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2795 _measure_midi->input_latency = one_way;
2796 _measure_midi->output_latency = one_way;
2797 notebook.set_current_page (midi_tab);
2799 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2805 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2806 one_way = std::max (0., one_way);
2808 input_latency_adjustment.set_value (one_way);
2809 output_latency_adjustment.set_value (one_way);
2811 /* back to settings page */
2812 notebook.set_current_page (0);
2818 EngineControl::on_delete_event (GdkEventAny* ev)
2820 if (notebook.get_current_page() == 2) {
2821 /* currently on latency tab - be sure to clean up */
2822 end_latency_detection ();
2824 return ArdourDialog::on_delete_event (ev);
2828 EngineControl::engine_running ()
2830 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2833 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2834 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2836 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2837 connect_disconnect_button.show();
2839 started_at_least_once = true;
2840 if (_have_control) {
2841 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2843 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2845 update_sensitivity();
2849 EngineControl::engine_stopped ()
2851 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2854 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2855 connect_disconnect_button.show();
2857 if (_have_control) {
2858 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2860 engine_status.set_markup(X_(""));
2863 update_sensitivity();
2867 EngineControl::device_list_changed ()
2869 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2871 midi_option_changed();
2875 EngineControl::connect_disconnect_click()
2877 if (ARDOUR::AudioEngine::instance()->running()) {
2878 ARDOUR_UI::instance()->disconnect_from_engine ();
2880 ARDOUR_UI::instance()->reconnect_to_engine ();
2885 EngineControl::calibrate_audio_latency ()
2887 _measure_midi.reset ();
2888 have_lm_results = false;
2889 lm_use_button.set_sensitive (false);
2890 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2891 notebook.set_current_page (latency_tab);
2895 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2898 have_lm_results = false;
2899 lm_use_button.set_sensitive (false);
2900 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2901 notebook.set_current_page (latency_tab);
2905 EngineControl::configure_midi_devices ()
2907 notebook.set_current_page (midi_tab);