2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , lm_measure_label (_("Measure"))
91 , lm_use_button (_("Use results"))
92 , lm_back_button (_("Back to settings ... (ignore results)"))
93 , lm_button_audio (_("Calibrate Audio"))
95 , have_lm_results (false)
97 , midi_back_button (_("Back to settings"))
99 , _desired_sample_rate (0)
100 , started_at_least_once (false)
101 , queue_device_changed (false)
102 , _have_control (true)
105 using namespace Notebook_Helpers;
106 vector<string> backend_names;
108 AttachOptions xopt = AttachOptions (FILL|EXPAND);
111 set_name (X_("AudioMIDISetup"));
113 /* the backend combo is the one thing that is ALWAYS visible */
115 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
117 if (backends.empty()) {
118 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
120 throw failed_constructor ();
123 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
124 backend_names.push_back ((*b)->name);
127 set_popdown_strings (backend_combo, backend_names);
129 /* setup basic packing characteristics for the table used on the main
130 * tab of the notebook
133 basic_packer.set_spacings (6);
134 basic_packer.set_border_width (12);
135 basic_packer.set_homogeneous (false);
139 basic_hbox.pack_start (basic_packer, false, false);
141 /* latency measurement tab */
143 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
146 lm_table.set_row_spacings (12);
147 lm_table.set_col_spacings (6);
148 lm_table.set_homogeneous (false);
150 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
153 lm_preamble.set_width_chars (60);
154 lm_preamble.set_line_wrap (true);
155 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
157 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
160 Gtk::Label* preamble;
161 preamble = manage (new Label);
162 preamble->set_width_chars (60);
163 preamble->set_line_wrap (true);
164 preamble->set_markup (_("Select two channels below and connect them using a cable."));
166 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
169 label = manage (new Label (_("Output channel")));
170 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
172 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
173 misc_align->add (lm_output_channel_combo);
174 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
177 label = manage (new Label (_("Input channel")));
178 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
180 misc_align = manage (new Alignment (0.0, 0.5));
181 misc_align->add (lm_input_channel_combo);
182 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
185 lm_measure_label.set_padding (10, 10);
186 lm_measure_button.add (lm_measure_label);
187 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
188 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
189 lm_back_button_signal = lm_back_button.signal_clicked().connect(
190 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
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::start_engine ()
414 if (push_state_to_backend(true) != 0) {
415 MessageDialog msg(*this,
416 ARDOUR::AudioEngine::instance()->get_last_backend_error());
424 EngineControl::stop_engine ()
426 if (ARDOUR::AudioEngine::instance()->stop()) {
427 MessageDialog msg(*this,
428 ARDOUR::AudioEngine::instance()->get_last_backend_error());
436 EngineControl::on_response (int response_id)
438 ArdourDialog::on_response (response_id);
440 switch (response_id) {
442 if (!start_engine()) {
447 #ifdef PLATFORM_WINDOWS
449 // But if there's no session open, this can produce
450 // a long gap when nothing appears to be happening.
451 // Let's show the splash image while we're waiting.
452 if (!ARDOUR_COMMAND_LINE::no_splash) {
453 if (ARDOUR_UI::instance()) {
454 if (!ARDOUR_UI::instance()->session_loaded) {
455 ARDOUR_UI::instance()->show_splash();
461 case RESPONSE_DELETE_EVENT: {
463 ev.type = GDK_BUTTON_PRESS;
465 on_delete_event((GdkEventAny*)&ev);
468 case RESPONSE_CANCEL:
469 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
470 ARDOUR_UI::instance()->check_audioengine(*this);
479 EngineControl::build_notebook ()
482 AttachOptions xopt = AttachOptions (FILL|EXPAND);
484 /* clear the table */
486 Gtkmm2ext::container_clear (basic_vbox);
487 Gtkmm2ext::container_clear (basic_packer);
489 if (control_app_button.get_parent()) {
490 control_app_button.get_parent()->remove (control_app_button);
493 label = manage (left_aligned_label (_("Audio System:")));
494 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
495 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
497 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
498 engine_status.show();
500 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
501 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
503 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
504 lm_button_audio.set_name ("generic button");
505 lm_button_audio.set_can_focus(true);
508 build_full_control_notebook ();
510 build_no_control_notebook ();
513 basic_vbox.pack_start (basic_hbox, false, false);
516 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
517 basic_vbox.show_all ();
522 EngineControl::build_full_control_notebook ()
524 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
527 using namespace Notebook_Helpers;
529 vector<string> strings;
530 AttachOptions xopt = AttachOptions (FILL|EXPAND);
531 int row = 1; // row zero == backend combo
533 /* start packing it up */
535 if (backend->requires_driver_selection()) {
536 label = manage (left_aligned_label (_("Driver:")));
537 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
538 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
542 if (backend->use_separate_input_and_output_devices()) {
543 label = manage (left_aligned_label (_("Input Device:")));
544 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
545 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
547 label = manage (left_aligned_label (_("Output Device:")));
548 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
549 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
551 // reset so it isn't used in state comparisons
552 device_combo.set_active_text ("");
554 label = manage (left_aligned_label (_("Device:")));
555 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
556 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
558 // reset these so they don't get used in state comparisons
559 input_device_combo.set_active_text ("");
560 output_device_combo.set_active_text ("");
563 label = manage (left_aligned_label (_("Sample rate:")));
564 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
565 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
569 label = manage (left_aligned_label (_("Buffer size:")));
570 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
571 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
572 buffer_size_duration_label.set_alignment (0.0); /* left-align */
573 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
575 /* button spans 2 rows */
577 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
580 input_channels.set_name ("InputChannels");
581 input_channels.set_flags (Gtk::CAN_FOCUS);
582 input_channels.set_digits (0);
583 input_channels.set_wrap (false);
584 output_channels.set_editable (true);
586 if (!ARDOUR::Profile->get_mixbus()) {
587 label = manage (left_aligned_label (_("Input Channels:")));
588 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
589 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
593 output_channels.set_name ("OutputChannels");
594 output_channels.set_flags (Gtk::CAN_FOCUS);
595 output_channels.set_digits (0);
596 output_channels.set_wrap (false);
597 output_channels.set_editable (true);
599 if (!ARDOUR::Profile->get_mixbus()) {
600 label = manage (left_aligned_label (_("Output Channels:")));
601 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
602 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
606 input_latency.set_name ("InputLatency");
607 input_latency.set_flags (Gtk::CAN_FOCUS);
608 input_latency.set_digits (0);
609 input_latency.set_wrap (false);
610 input_latency.set_editable (true);
612 label = manage (left_aligned_label (_("Hardware input latency:")));
613 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
614 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
615 label = manage (left_aligned_label (_("samples")));
616 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
619 output_latency.set_name ("OutputLatency");
620 output_latency.set_flags (Gtk::CAN_FOCUS);
621 output_latency.set_digits (0);
622 output_latency.set_wrap (false);
623 output_latency.set_editable (true);
625 label = manage (left_aligned_label (_("Hardware output latency:")));
626 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
627 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
628 label = manage (left_aligned_label (_("samples")));
629 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
631 /* button spans 2 rows */
633 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
636 label = manage (left_aligned_label (_("MIDI System:")));
637 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
638 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
639 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
640 /* Currently the only backend with dedicated Midi setup is ALSA.
641 * lot of people complain that this is greyed out
642 * "I can't use MIDI, the setup is greyed out"
644 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
650 EngineControl::build_no_control_notebook ()
652 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
655 using namespace Notebook_Helpers;
657 vector<string> strings;
658 AttachOptions xopt = AttachOptions (FILL|EXPAND);
659 int row = 1; // row zero == backend combo
660 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
662 label = manage (new Label);
663 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
664 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
667 if (backend->can_change_sample_rate_when_running()) {
668 label = manage (left_aligned_label (_("Sample rate:")));
669 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
670 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
674 if (backend->can_change_buffer_size_when_running()) {
675 label = manage (left_aligned_label (_("Buffer size:")));
676 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
677 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
678 buffer_size_duration_label.set_alignment (0.0); /* left-align */
679 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
683 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
687 EngineControl::~EngineControl ()
689 ignore_changes = true;
693 EngineControl::disable_latency_tab ()
695 vector<string> empty;
696 set_popdown_strings (lm_output_channel_combo, empty);
697 set_popdown_strings (lm_input_channel_combo, empty);
698 lm_measure_button.set_sensitive (false);
699 lm_use_button.set_sensitive (false);
703 EngineControl::enable_latency_tab ()
705 vector<string> outputs;
706 vector<string> inputs;
708 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
709 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
710 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
712 if (!ARDOUR::AudioEngine::instance()->running()) {
713 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
714 notebook.set_current_page (0);
718 else if (inputs.empty() || outputs.empty()) {
719 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
720 notebook.set_current_page (0);
725 lm_back_button_signal.disconnect();
727 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
730 lm_back_button_signal = lm_back_button.signal_clicked().connect(
731 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
735 set_popdown_strings (lm_output_channel_combo, outputs);
736 lm_output_channel_combo.set_active_text (outputs.front());
737 lm_output_channel_combo.set_sensitive (true);
739 set_popdown_strings (lm_input_channel_combo, inputs);
740 lm_input_channel_combo.set_active_text (inputs.front());
741 lm_input_channel_combo.set_sensitive (true);
743 lm_measure_button.set_sensitive (true);
747 EngineControl::setup_midi_tab_for_backend ()
749 string backend = backend_combo.get_active_text ();
751 Gtkmm2ext::container_clear (midi_vbox);
753 midi_vbox.set_border_width (12);
754 midi_device_table.set_border_width (12);
756 if (backend == "JACK") {
757 setup_midi_tab_for_jack ();
760 midi_vbox.pack_start (midi_device_table, true, true);
761 midi_vbox.pack_start (midi_back_button, false, false);
762 midi_vbox.show_all ();
766 EngineControl::update_sensitivity ()
768 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
770 ok_button->set_sensitive (false);
771 start_stop_button.set_sensitive (false);
776 size_t devices_available = 0;
778 if (backend->use_separate_input_and_output_devices ()) {
779 devices_available += get_popdown_string_count (input_device_combo);
780 devices_available += get_popdown_string_count (output_device_combo);
782 devices_available += get_popdown_string_count (device_combo);
785 if (devices_available == 0) {
787 input_latency.set_sensitive (false);
788 output_latency.set_sensitive (false);
789 input_channels.set_sensitive (false);
790 output_channels.set_sensitive (false);
792 input_latency.set_sensitive (true);
793 output_latency.set_sensitive (true);
794 input_channels.set_sensitive (true);
795 output_channels.set_sensitive (true);
798 if (get_popdown_string_count (buffer_size_combo) > 0) {
799 if (!ARDOUR::AudioEngine::instance()->running()) {
800 buffer_size_combo.set_sensitive (valid);
801 } else if (backend->can_change_sample_rate_when_running()) {
802 buffer_size_combo.set_sensitive (valid || !_have_control);
806 * Currently there is no way to manually stop the
807 * engine in order to re-configure it.
808 * This needs to remain sensitive for now.
810 * (it's also handy to implicily
811 * re-start the engine)
813 buffer_size_combo.set_sensitive (true);
815 buffer_size_combo.set_sensitive (false);
819 buffer_size_combo.set_sensitive (false);
823 if (get_popdown_string_count (sample_rate_combo) > 0) {
824 if (!ARDOUR::AudioEngine::instance()->running()) {
825 sample_rate_combo.set_sensitive (true);
827 sample_rate_combo.set_sensitive (false);
830 sample_rate_combo.set_sensitive (false);
835 start_stop_button.set_sensitive(true);
836 start_stop_button.show();
837 if (ARDOUR::AudioEngine::instance()->running()) {
838 start_stop_button.set_text("Stop");
839 update_devices_button.set_sensitive(false);
841 if (backend->can_request_update_devices()) {
842 update_devices_button.show();
844 update_devices_button.hide();
846 start_stop_button.set_text("Start");
847 update_devices_button.set_sensitive(true);
850 update_devices_button.set_sensitive(false);
851 update_devices_button.hide();
852 start_stop_button.set_sensitive(false);
853 start_stop_button.hide();
856 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
857 input_device_combo.set_sensitive (false);
858 output_device_combo.set_sensitive (false);
859 device_combo.set_sensitive (false);
860 driver_combo.set_sensitive (false);
862 input_device_combo.set_sensitive (true);
863 output_device_combo.set_sensitive (true);
864 device_combo.set_sensitive (true);
865 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
866 driver_combo.set_sensitive (true);
868 driver_combo.set_sensitive (false);
872 if (valid || !_have_control) {
873 ok_button->set_sensitive (true);
875 ok_button->set_sensitive (false);
880 EngineControl::setup_midi_tab_for_jack ()
885 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
887 device->input_latency = a->get_value();
889 device->output_latency = a->get_value();
894 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
895 b->set_active (!b->get_active());
896 device->enabled = b->get_active();
897 refresh_midi_display(device->name);
901 EngineControl::refresh_midi_display (std::string focus)
903 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
907 AttachOptions xopt = AttachOptions (FILL|EXPAND);
910 Gtkmm2ext::container_clear (midi_device_table);
912 midi_device_table.set_spacings (6);
914 l = manage (new Label);
915 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
916 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
917 l->set_alignment (0.5, 0.5);
921 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
922 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
923 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
924 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
926 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
927 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
928 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
929 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
932 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
937 bool enabled = (*p)->enabled;
939 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
940 m->set_name ("midi device");
941 m->set_can_focus (Gtk::CAN_FOCUS);
942 m->add_events (Gdk::BUTTON_RELEASE_MASK);
943 m->set_active (enabled);
944 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
945 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
946 if ((*p)->name == focus) {
950 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
951 s = manage (new Gtk::SpinButton (*a));
952 a->set_value ((*p)->input_latency);
953 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
954 s->set_sensitive (_can_set_midi_latencies && enabled);
955 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
957 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
958 s = manage (new Gtk::SpinButton (*a));
959 a->set_value ((*p)->output_latency);
960 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
961 s->set_sensitive (_can_set_midi_latencies && enabled);
962 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
964 b = manage (new Button (_("Calibrate")));
965 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
966 b->set_sensitive (_can_set_midi_latencies && enabled);
967 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
974 EngineControl::backend_changed ()
976 SignalBlocker blocker (*this, "backend_changed");
977 string backend_name = backend_combo.get_active_text();
978 boost::shared_ptr<ARDOUR::AudioBackend> backend;
980 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
981 /* eh? setting the backend failed... how ? */
982 /* A: stale config contains a backend that does not exist in current build */
986 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
988 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
991 setup_midi_tab_for_backend ();
992 _midi_devices.clear();
994 if (backend->requires_driver_selection()) {
995 if (set_driver_popdown_strings ()) {
999 /* this will change the device text which will cause a call to
1000 * device changed which will set up parameters
1005 update_midi_options ();
1007 connect_disconnect_button.hide();
1009 midi_option_changed();
1011 started_at_least_once = false;
1013 /* changing the backend implies stopping the engine
1014 * ARDOUR::AudioEngine() may or may not emit this signal
1015 * depending on previous engine state
1017 engine_stopped (); // set "active/inactive"
1019 if (!ignore_changes) {
1020 maybe_display_saved_state ();
1025 EngineControl::update_midi_options ()
1027 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1028 vector<string> midi_options = backend->enumerate_midi_options();
1030 if (midi_options.size() == 1) {
1031 /* only contains the "none" option */
1032 midi_option_combo.set_sensitive (false);
1034 if (_have_control) {
1035 set_popdown_strings (midi_option_combo, midi_options);
1036 midi_option_combo.set_active_text (midi_options.front());
1037 midi_option_combo.set_sensitive (true);
1039 midi_option_combo.set_sensitive (false);
1045 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1047 if (ARDOUR::Profile->get_mixbus()) {
1051 uint32_t cnt = (uint32_t) sb->get_value();
1053 sb->set_text (_("all available channels"));
1056 snprintf (buf, sizeof (buf), "%d", cnt);
1062 // @return true if there are drivers available
1064 EngineControl::set_driver_popdown_strings ()
1066 DEBUG_ECONTROL ("set_driver_popdown_strings");
1067 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1068 vector<string> drivers = backend->enumerate_drivers();
1070 if (drivers.empty ()) {
1071 // This is an error...?
1075 string current_driver = backend->driver_name ();
1077 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1079 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1082 current_driver = drivers.front ();
1085 set_popdown_strings (driver_combo, drivers);
1087 string_compose ("driver_combo.set_active_text: %1", current_driver));
1088 driver_combo.set_active_text (current_driver);
1093 EngineControl::get_default_device(const string& current_device_name,
1094 const vector<string>& available_devices)
1096 // If the current device is available, use it as default
1097 if (std::find (available_devices.begin (),
1098 available_devices.end (),
1099 current_device_name) != available_devices.end ()) {
1101 return current_device_name;
1104 using namespace ARDOUR;
1106 string default_device_name =
1107 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1109 vector<string>::const_iterator i;
1111 // If there is a "Default" device available, use it
1112 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1113 if (*i == default_device_name) {
1118 string none_device_name =
1119 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1121 // Use the first device that isn't "None"
1122 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1123 if (*i != none_device_name) {
1128 // Use "None" if there are no other available
1129 return available_devices.front();
1132 // @return true if there are devices available
1134 EngineControl::set_device_popdown_strings ()
1136 DEBUG_ECONTROL ("set_device_popdown_strings");
1137 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1138 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1140 /* NOTE: Ardour currently does not display the "available" field of the
1143 * Doing so would require a different GUI widget than the combo
1144 * box/popdown that we currently use, since it has no way to list
1145 * items that are not selectable. Something more like a popup menu,
1146 * which could have unselectable items, would be appropriate.
1149 vector<string> available_devices;
1151 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1152 available_devices.push_back (i->name);
1155 if (available_devices.empty ()) {
1159 set_popdown_strings (device_combo, available_devices);
1161 std::string default_device =
1162 get_default_device(backend->device_name(), available_devices);
1165 string_compose ("set device_combo active text: %1", default_device));
1167 device_combo.set_active_text(default_device);
1171 // @return true if there are input devices available
1173 EngineControl::set_input_device_popdown_strings ()
1175 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1176 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1177 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1179 vector<string> available_devices;
1181 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1182 available_devices.push_back (i->name);
1185 if (available_devices.empty()) {
1189 set_popdown_strings (input_device_combo, available_devices);
1191 std::string default_device =
1192 get_default_device(backend->input_device_name(), available_devices);
1195 string_compose ("set input_device_combo active text: %1", default_device));
1196 input_device_combo.set_active_text(default_device);
1200 // @return true if there are output devices available
1202 EngineControl::set_output_device_popdown_strings ()
1204 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1205 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1206 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1208 vector<string> available_devices;
1210 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1211 available_devices.push_back (i->name);
1214 if (available_devices.empty()) {
1218 set_popdown_strings (output_device_combo, available_devices);
1220 std::string default_device =
1221 get_default_device(backend->output_device_name(), available_devices);
1224 string_compose ("set output_device_combo active text: %1", default_device));
1225 output_device_combo.set_active_text(default_device);
1230 EngineControl::list_devices ()
1232 DEBUG_ECONTROL ("list_devices");
1233 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1236 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1238 bool devices_available = false;
1240 if (backend->use_separate_input_and_output_devices ()) {
1241 bool input_devices_available = set_input_device_popdown_strings ();
1242 bool output_devices_available = set_output_device_popdown_strings ();
1243 devices_available = input_devices_available || output_devices_available;
1245 devices_available = set_device_popdown_strings ();
1248 if (devices_available) {
1251 device_combo.clear();
1252 input_device_combo.clear();
1253 output_device_combo.clear();
1255 update_sensitivity ();
1259 EngineControl::driver_changed ()
1261 SignalBlocker blocker (*this, "driver_changed");
1262 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1265 backend->set_driver (driver_combo.get_active_text());
1268 if (!ignore_changes) {
1269 maybe_display_saved_state ();
1274 EngineControl::get_sample_rates_for_all_devices ()
1276 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1277 ARDOUR::AudioEngine::instance ()->current_backend ();
1278 vector<float> all_rates;
1280 if (backend->use_separate_input_and_output_devices ()) {
1281 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1283 all_rates = backend->available_sample_rates (get_device_name ());
1289 EngineControl::get_default_sample_rates ()
1291 vector<float> rates;
1292 rates.push_back (8000.0f);
1293 rates.push_back (16000.0f);
1294 rates.push_back (32000.0f);
1295 rates.push_back (44100.0f);
1296 rates.push_back (48000.0f);
1297 rates.push_back (88200.0f);
1298 rates.push_back (96000.0f);
1299 rates.push_back (192000.0f);
1300 rates.push_back (384000.0f);
1305 EngineControl::set_samplerate_popdown_strings ()
1307 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1308 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1313 if (_have_control) {
1314 sr = get_sample_rates_for_all_devices ();
1316 sr = get_default_sample_rates ();
1319 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1320 s.push_back (rate_as_string (*x));
1321 if (*x == _desired_sample_rate) {
1326 set_popdown_strings (sample_rate_combo, s);
1329 if (desired.empty ()) {
1330 float new_active_sr = backend->default_sample_rate ();
1332 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1333 new_active_sr = sr.front ();
1336 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1338 sample_rate_combo.set_active_text (desired);
1342 update_sensitivity ();
1346 EngineControl::get_buffer_sizes_for_all_devices ()
1348 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1349 ARDOUR::AudioEngine::instance ()->current_backend ();
1350 vector<uint32_t> all_sizes;
1352 if (backend->use_separate_input_and_output_devices ()) {
1353 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1355 all_sizes = backend->available_buffer_sizes (get_device_name ());
1361 EngineControl::get_default_buffer_sizes ()
1363 vector<uint32_t> sizes;
1364 sizes.push_back (8);
1365 sizes.push_back (16);
1366 sizes.push_back (32);
1367 sizes.push_back (64);
1368 sizes.push_back (128);
1369 sizes.push_back (256);
1370 sizes.push_back (512);
1371 sizes.push_back (1024);
1372 sizes.push_back (2048);
1373 sizes.push_back (4096);
1374 sizes.push_back (8192);
1379 EngineControl::set_buffersize_popdown_strings ()
1381 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1382 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1383 vector<uint32_t> bs;
1386 if (_have_control) {
1387 bs = get_buffer_sizes_for_all_devices ();
1388 } else if (backend->can_change_buffer_size_when_running()) {
1389 bs = get_default_buffer_sizes ();
1392 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1393 s.push_back (bufsize_as_string (*x));
1396 uint32_t previous_size = 0;
1397 if (!buffer_size_combo.get_active_text().empty()) {
1398 previous_size = get_buffer_size ();
1401 set_popdown_strings (buffer_size_combo, s);
1405 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1406 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1409 buffer_size_combo.set_active_text(s.front());
1411 uint32_t period = backend->buffer_size();
1412 if (0 == period && backend->use_separate_input_and_output_devices()) {
1413 period = backend->default_buffer_size(get_input_device_name());
1415 if (0 == period && backend->use_separate_input_and_output_devices()) {
1416 period = backend->default_buffer_size(get_output_device_name());
1418 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1419 period = backend->default_buffer_size(get_device_name());
1422 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1424 show_buffer_duration ();
1426 update_sensitivity ();
1430 EngineControl::device_changed ()
1432 SignalBlocker blocker (*this, "device_changed");
1433 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1436 string device_name_in;
1437 string device_name_out; // only used if backend support separate I/O devices
1439 if (backend->use_separate_input_and_output_devices()) {
1440 device_name_in = get_input_device_name ();
1441 device_name_out = get_output_device_name ();
1443 device_name_in = get_device_name ();
1446 /* we set the backend-device to query various device related intormation.
1447 * This has the side effect that backend->device_name() will match
1448 * the device_name and 'change_device' will never be true.
1449 * so work around this by setting...
1451 if (backend->use_separate_input_and_output_devices()) {
1452 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1453 queue_device_changed = true;
1456 if (device_name_in != backend->device_name()) {
1457 queue_device_changed = true;
1461 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1462 if (backend->use_separate_input_and_output_devices()) {
1463 backend->set_input_device_name (device_name_in);
1464 backend->set_output_device_name (device_name_out);
1466 backend->set_device_name(device_name_in);
1470 /* don't allow programmatic change to combos to cause a
1471 recursive call to this method.
1473 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1475 set_samplerate_popdown_strings ();
1476 set_buffersize_popdown_strings ();
1478 /* TODO set min + max channel counts here */
1480 manage_control_app_sensitivity ();
1483 /* pick up any saved state for this device */
1485 if (!ignore_changes) {
1486 maybe_display_saved_state ();
1491 EngineControl::input_device_changed ()
1493 DEBUG_ECONTROL ("input_device_changed");
1498 EngineControl::output_device_changed ()
1500 DEBUG_ECONTROL ("output_device_changed");
1505 EngineControl::bufsize_as_string (uint32_t sz)
1507 /* Translators: "samples" is always plural here, so no
1508 need for plural+singular forms.
1511 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1516 EngineControl::sample_rate_changed ()
1518 DEBUG_ECONTROL ("sample_rate_changed");
1519 /* reset the strings for buffer size to show the correct msec value
1520 (reflecting the new sample rate).
1523 show_buffer_duration ();
1528 EngineControl::buffer_size_changed ()
1530 DEBUG_ECONTROL ("buffer_size_changed");
1531 show_buffer_duration ();
1535 EngineControl::show_buffer_duration ()
1537 DEBUG_ECONTROL ("show_buffer_duration");
1538 /* buffer sizes - convert from just samples to samples + msecs for
1539 * the displayed string
1542 string bs_text = buffer_size_combo.get_active_text ();
1543 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1544 uint32_t rate = get_rate();
1546 /* Developers: note the hard-coding of a double buffered model
1547 in the (2 * samples) computation of latency. we always start
1548 the audiobackend in this configuration.
1550 /* note to jack1 developers: ardour also always starts the engine
1551 * in async mode (no jack2 --sync option) which adds an extra cycle
1552 * of latency with jack2 (and *3 would be correct)
1553 * The value can also be wrong if jackd is started externally..
1555 * At the time of writing the ALSA backend always uses double-buffering *2,
1556 * The Dummy backend *1, and who knows what ASIO really does :)
1558 * So just display the period size, that's also what
1559 * ARDOUR_UI::update_sample_rate() does for the status bar.
1560 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1561 * but still, that's the buffer period, not [round-trip] latency)
1564 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1565 buffer_size_duration_label.set_text (buf);
1569 EngineControl::midi_option_changed ()
1571 DEBUG_ECONTROL ("midi_option_changed");
1572 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1575 backend->set_midi_option (get_midi_option());
1577 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1579 //_midi_devices.clear(); // TODO merge with state-saved settings..
1580 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1581 std::vector<MidiDeviceSettings> new_devices;
1583 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1584 MidiDeviceSettings mds = find_midi_device (i->name);
1585 if (i->available && !mds) {
1586 uint32_t input_latency = 0;
1587 uint32_t output_latency = 0;
1588 if (_can_set_midi_latencies) {
1589 input_latency = backend->systemic_midi_input_latency (i->name);
1590 output_latency = backend->systemic_midi_output_latency (i->name);
1592 bool enabled = backend->midi_device_enabled (i->name);
1593 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1594 new_devices.push_back (ptr);
1595 } else if (i->available) {
1596 new_devices.push_back (mds);
1599 _midi_devices = new_devices;
1601 if (_midi_devices.empty()) {
1602 midi_devices_button.set_sensitive (false);
1604 midi_devices_button.set_sensitive (true);
1609 EngineControl::parameter_changed ()
1613 EngineControl::State
1614 EngineControl::get_matching_state (
1615 const string& backend,
1616 const string& driver,
1617 const string& device)
1619 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1620 if ((*i)->backend == backend &&
1621 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1629 EngineControl::State
1630 EngineControl::get_matching_state (
1631 const string& backend,
1632 const string& driver,
1633 const string& input_device,
1634 const string& output_device)
1636 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1637 if ((*i)->backend == backend &&
1638 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1646 EngineControl::State
1647 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1649 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1652 if (backend->use_separate_input_and_output_devices ()) {
1653 return get_matching_state (backend_combo.get_active_text(),
1654 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1655 input_device_combo.get_active_text(),
1656 output_device_combo.get_active_text());
1658 return get_matching_state (backend_combo.get_active_text(),
1659 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1660 device_combo.get_active_text());
1664 return get_matching_state (backend_combo.get_active_text(),
1666 device_combo.get_active_text());
1669 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1670 const EngineControl::State& state2)
1672 if (state1->backend == state2->backend &&
1673 state1->driver == state2->driver &&
1674 state1->device == state2->device &&
1675 state1->input_device == state2->input_device &&
1676 state1->output_device == state2->output_device) {
1682 EngineControl::State
1683 EngineControl::save_state ()
1687 if (!_have_control) {
1688 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1692 state.reset(new StateStruct);
1693 state->backend = get_backend ();
1695 state.reset(new StateStruct);
1696 store_state (state);
1699 for (StateList::iterator i = states.begin(); i != states.end();) {
1700 if (equivalent_states (*i, state)) {
1701 i = states.erase(i);
1707 states.push_back (state);
1713 EngineControl::store_state (State state)
1715 state->backend = get_backend ();
1716 state->driver = get_driver ();
1717 state->device = get_device_name ();
1718 state->input_device = get_input_device_name ();
1719 state->output_device = get_output_device_name ();
1720 state->sample_rate = get_rate ();
1721 state->buffer_size = get_buffer_size ();
1722 state->input_latency = get_input_latency ();
1723 state->output_latency = get_output_latency ();
1724 state->input_channels = get_input_channels ();
1725 state->output_channels = get_output_channels ();
1726 state->midi_option = get_midi_option ();
1727 state->midi_devices = _midi_devices;
1731 EngineControl::maybe_display_saved_state ()
1733 if (!_have_control) {
1737 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1740 DEBUG_ECONTROL ("Restoring saved state");
1741 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1743 if (!_desired_sample_rate) {
1744 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1746 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1747 /* call this explicitly because we're ignoring changes to
1748 the controls at this point.
1750 show_buffer_duration ();
1751 input_latency.set_value (state->input_latency);
1752 output_latency.set_value (state->output_latency);
1754 if (!state->midi_option.empty()) {
1755 midi_option_combo.set_active_text (state->midi_option);
1756 _midi_devices = state->midi_devices;
1759 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1764 EngineControl::get_state ()
1766 LocaleGuard lg (X_("C"));
1768 XMLNode* root = new XMLNode ("AudioMIDISetup");
1771 if (!states.empty()) {
1772 XMLNode* state_nodes = new XMLNode ("EngineStates");
1774 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1776 XMLNode* node = new XMLNode ("State");
1778 node->add_property ("backend", (*i)->backend);
1779 node->add_property ("driver", (*i)->driver);
1780 node->add_property ("device", (*i)->device);
1781 node->add_property ("input-device", (*i)->input_device);
1782 node->add_property ("output-device", (*i)->output_device);
1783 node->add_property ("sample-rate", (*i)->sample_rate);
1784 node->add_property ("buffer-size", (*i)->buffer_size);
1785 node->add_property ("input-latency", (*i)->input_latency);
1786 node->add_property ("output-latency", (*i)->output_latency);
1787 node->add_property ("input-channels", (*i)->input_channels);
1788 node->add_property ("output-channels", (*i)->output_channels);
1789 node->add_property ("active", (*i)->active ? "yes" : "no");
1790 node->add_property ("midi-option", (*i)->midi_option);
1792 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1793 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1794 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1795 midi_device_stuff->add_property (X_("name"), (*p)->name);
1796 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1797 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1798 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1799 midi_devices->add_child_nocopy (*midi_device_stuff);
1801 node->add_child_nocopy (*midi_devices);
1803 state_nodes->add_child_nocopy (*node);
1806 root->add_child_nocopy (*state_nodes);
1813 EngineControl::set_default_state ()
1815 vector<string> backend_names;
1816 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1818 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1819 backend_names.push_back ((*b)->name);
1821 backend_combo.set_active_text (backend_names.front());
1823 // We could set default backends per platform etc here
1829 EngineControl::set_state (const XMLNode& root)
1831 XMLNodeList clist, cclist;
1832 XMLNodeConstIterator citer, cciter;
1834 XMLNode* grandchild;
1835 XMLProperty* prop = NULL;
1837 fprintf (stderr, "EngineControl::set_state\n");
1839 if (root.name() != "AudioMIDISetup") {
1843 clist = root.children();
1847 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1851 if (child->name() != "EngineStates") {
1855 cclist = child->children();
1857 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1858 State state (new StateStruct);
1860 grandchild = *cciter;
1862 if (grandchild->name() != "State") {
1866 if ((prop = grandchild->property ("backend")) == 0) {
1869 state->backend = prop->value ();
1871 if ((prop = grandchild->property ("driver")) == 0) {
1874 state->driver = prop->value ();
1876 if ((prop = grandchild->property ("device")) == 0) {
1879 state->device = prop->value ();
1881 if ((prop = grandchild->property ("input-device")) == 0) {
1884 state->input_device = prop->value ();
1886 if ((prop = grandchild->property ("output-device")) == 0) {
1889 state->output_device = prop->value ();
1891 if ((prop = grandchild->property ("sample-rate")) == 0) {
1894 state->sample_rate = atof (prop->value ());
1896 if ((prop = grandchild->property ("buffer-size")) == 0) {
1899 state->buffer_size = atoi (prop->value ());
1901 if ((prop = grandchild->property ("input-latency")) == 0) {
1904 state->input_latency = atoi (prop->value ());
1906 if ((prop = grandchild->property ("output-latency")) == 0) {
1909 state->output_latency = atoi (prop->value ());
1911 if ((prop = grandchild->property ("input-channels")) == 0) {
1914 state->input_channels = atoi (prop->value ());
1916 if ((prop = grandchild->property ("output-channels")) == 0) {
1919 state->output_channels = atoi (prop->value ());
1921 if ((prop = grandchild->property ("active")) == 0) {
1924 state->active = string_is_affirmative (prop->value ());
1926 if ((prop = grandchild->property ("midi-option")) == 0) {
1929 state->midi_option = prop->value ();
1931 state->midi_devices.clear();
1933 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1934 const XMLNodeList mnc = midinode->children();
1935 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1936 if ((*n)->property (X_("name")) == 0
1937 || (*n)->property (X_("enabled")) == 0
1938 || (*n)->property (X_("input-latency")) == 0
1939 || (*n)->property (X_("output-latency")) == 0
1944 MidiDeviceSettings ptr (new MidiDeviceSetting(
1945 (*n)->property (X_("name"))->value (),
1946 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1947 atoi ((*n)->property (X_("input-latency"))->value ()),
1948 atoi ((*n)->property (X_("output-latency"))->value ())
1950 state->midi_devices.push_back (ptr);
1955 /* remove accumulated duplicates (due to bug in ealier version)
1956 * this can be removed again before release
1958 for (StateList::iterator i = states.begin(); i != states.end();) {
1959 if ((*i)->backend == state->backend &&
1960 (*i)->driver == state->driver &&
1961 (*i)->device == state->device) {
1962 i = states.erase(i);
1969 states.push_back (state);
1973 /* now see if there was an active state and switch the setup to it */
1975 // purge states of backend that are not available in this built
1976 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1977 vector<std::string> backend_names;
1979 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1980 backend_names.push_back((*i)->name);
1982 for (StateList::iterator i = states.begin(); i != states.end();) {
1983 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1984 i = states.erase(i);
1990 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1993 return set_current_state (*i);
2000 EngineControl::set_current_state (const State& state)
2002 DEBUG_ECONTROL ("set_current_state");
2004 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2006 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2007 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2008 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2009 // this shouldn't happen as the invalid backend names should have been
2010 // removed from the list of states.
2014 // now reflect the change in the backend in the GUI so backend_changed will
2015 // do the right thing
2016 backend_combo.set_active_text (state->backend);
2018 if (!state->driver.empty ()) {
2019 if (!backend->requires_driver_selection ()) {
2020 DEBUG_ECONTROL ("Backend should require driver selection");
2021 // A backend has changed from having driver selection to not having
2022 // it or someone has been manually editing a config file and messed
2027 if (backend->set_driver (state->driver) != 0) {
2028 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2029 // Driver names for a backend have changed and the name in the
2030 // config file is now invalid or support for driver is no longer
2031 // included in the backend
2034 // no need to set the driver_combo as backend_changed will use
2035 // backend->driver_name to set the active driver
2038 if (!state->device.empty ()) {
2039 if (backend->set_device_name (state->device) != 0) {
2041 string_compose ("Unable to set device name %1", state->device));
2042 // device is no longer available on the system
2045 // no need to set active device as it will be picked up in
2046 // via backend_changed ()/set_device_popdown_strings
2049 // backend supports separate input/output devices
2050 if (backend->set_input_device_name (state->input_device) != 0) {
2051 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2052 state->input_device));
2053 // input device is no longer available on the system
2057 if (backend->set_output_device_name (state->output_device) != 0) {
2058 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2059 state->input_device));
2060 // output device is no longer available on the system
2063 // no need to set active devices as it will be picked up in via
2064 // backend_changed ()/set_*_device_popdown_strings
2069 // Now restore the state of the rest of the controls
2071 // We don't use a SignalBlocker as set_current_state is currently only
2072 // called from set_state before any signals are connected. If at some point
2073 // a more general named state mechanism is implemented and
2074 // set_current_state is called while signals are connected then a
2075 // SignalBlocker will need to be instantiated before setting these.
2077 device_combo.set_active_text (state->device);
2078 input_device_combo.set_active_text (state->input_device);
2079 output_device_combo.set_active_text (state->output_device);
2080 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2081 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2082 input_latency.set_value (state->input_latency);
2083 output_latency.set_value (state->output_latency);
2084 midi_option_combo.set_active_text (state->midi_option);
2089 EngineControl::push_state_to_backend (bool start)
2091 DEBUG_ECONTROL ("push_state_to_backend");
2092 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2098 /* figure out what is going to change */
2100 bool restart_required = false;
2101 bool was_running = ARDOUR::AudioEngine::instance()->running();
2102 bool change_driver = false;
2103 bool change_device = false;
2104 bool change_rate = false;
2105 bool change_bufsize = false;
2106 bool change_latency = false;
2107 bool change_channels = false;
2108 bool change_midi = false;
2110 uint32_t ochan = get_output_channels ();
2111 uint32_t ichan = get_input_channels ();
2113 if (_have_control) {
2115 if (started_at_least_once) {
2117 /* we can control the backend */
2119 if (backend->requires_driver_selection()) {
2120 if (get_driver() != backend->driver_name()) {
2121 change_driver = true;
2125 if (backend->use_separate_input_and_output_devices()) {
2126 if (get_input_device_name() != backend->input_device_name()) {
2127 change_device = true;
2129 if (get_output_device_name() != backend->output_device_name()) {
2130 change_device = true;
2133 if (get_device_name() != backend->device_name()) {
2134 change_device = true;
2138 if (queue_device_changed) {
2139 change_device = true;
2142 if (get_rate() != backend->sample_rate()) {
2146 if (get_buffer_size() != backend->buffer_size()) {
2147 change_bufsize = true;
2150 if (get_midi_option() != backend->midi_option()) {
2154 /* zero-requested channels means "all available" */
2157 ichan = backend->input_channels();
2161 ochan = backend->output_channels();
2164 if (ichan != backend->input_channels()) {
2165 change_channels = true;
2168 if (ochan != backend->output_channels()) {
2169 change_channels = true;
2172 if (get_input_latency() != backend->systemic_input_latency() ||
2173 get_output_latency() != backend->systemic_output_latency()) {
2174 change_latency = true;
2177 /* backend never started, so we have to force a group
2180 change_device = true;
2181 if (backend->requires_driver_selection()) {
2182 change_driver = true;
2185 change_bufsize = true;
2186 change_channels = true;
2187 change_latency = true;
2193 /* we have no control over the backend, meaning that we can
2194 * only possibly change sample rate and buffer size.
2198 if (get_rate() != backend->sample_rate()) {
2199 change_bufsize = true;
2202 if (get_buffer_size() != backend->buffer_size()) {
2203 change_bufsize = true;
2207 queue_device_changed = false;
2209 if (!_have_control) {
2211 /* We do not have control over the backend, so the best we can
2212 * do is try to change the sample rate and/or bufsize and get
2216 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2220 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2225 backend->set_sample_rate (get_rate());
2228 if (change_bufsize) {
2229 backend->set_buffer_size (get_buffer_size());
2233 if (ARDOUR::AudioEngine::instance()->start ()) {
2234 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2244 /* determine if we need to stop the backend before changing parameters */
2246 if (change_driver || change_device || change_channels || change_latency ||
2247 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2249 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2250 restart_required = true;
2252 restart_required = false;
2257 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2258 /* no changes in any parameters that absolutely require a
2259 * restart, so check those that might be changeable without a
2263 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2264 /* can't do this while running ... */
2265 restart_required = true;
2268 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2269 /* can't do this while running ... */
2270 restart_required = true;
2276 if (restart_required) {
2277 if (ARDOUR::AudioEngine::instance()->stop()) {
2283 if (change_driver && backend->set_driver (get_driver())) {
2284 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2287 if (backend->use_separate_input_and_output_devices()) {
2288 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2289 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2292 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2293 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2297 if (change_device && backend->set_device_name (get_device_name())) {
2298 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2302 if (change_rate && backend->set_sample_rate (get_rate())) {
2303 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2306 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2307 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2311 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2312 if (backend->set_input_channels (get_input_channels())) {
2313 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2316 if (backend->set_output_channels (get_output_channels())) {
2317 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2321 if (change_latency) {
2322 if (backend->set_systemic_input_latency (get_input_latency())) {
2323 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2326 if (backend->set_systemic_output_latency (get_output_latency())) {
2327 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2333 backend->set_midi_option (get_midi_option());
2337 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2338 if (_measure_midi) {
2339 if (*p == _measure_midi) {
2340 backend->set_midi_device_enabled ((*p)->name, true);
2342 backend->set_midi_device_enabled ((*p)->name, false);
2346 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2347 if (backend->can_set_systemic_midi_latencies()) {
2348 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2349 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2354 if (start || (was_running && restart_required)) {
2355 if (ARDOUR::AudioEngine::instance()->start()) {
2366 EngineControl::post_push ()
2368 /* get a pointer to the current state object, creating one if
2372 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2375 state = save_state ();
2383 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2384 (*i)->active = false;
2387 /* mark this one active (to be used next time the dialog is
2391 state->active = true;
2393 if (_have_control) { // XXX
2394 manage_control_app_sensitivity ();
2397 /* schedule a redisplay of MIDI ports */
2398 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2403 EngineControl::get_rate () const
2405 float r = atof (sample_rate_combo.get_active_text ());
2406 /* the string may have been translated with an abbreviation for
2407 * thousands, so use a crude heuristic to fix this.
2417 EngineControl::get_buffer_size () const
2419 string txt = buffer_size_combo.get_active_text ();
2422 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2423 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2424 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2432 EngineControl::get_midi_option () const
2434 return midi_option_combo.get_active_text();
2438 EngineControl::get_input_channels() const
2440 if (ARDOUR::Profile->get_mixbus()) {
2441 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2442 if (!backend) return 0;
2443 return backend->input_channels();
2445 return (uint32_t) input_channels_adjustment.get_value();
2449 EngineControl::get_output_channels() const
2451 if (ARDOUR::Profile->get_mixbus()) {
2452 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2453 if (!backend) return 0;
2454 return backend->input_channels();
2456 return (uint32_t) output_channels_adjustment.get_value();
2460 EngineControl::get_input_latency() const
2462 return (uint32_t) input_latency_adjustment.get_value();
2466 EngineControl::get_output_latency() const
2468 return (uint32_t) output_latency_adjustment.get_value();
2472 EngineControl::get_backend () const
2474 return backend_combo.get_active_text ();
2478 EngineControl::get_driver () const
2480 if (driver_combo.get_parent()) {
2481 return driver_combo.get_active_text ();
2488 EngineControl::get_device_name () const
2490 return device_combo.get_active_text ();
2494 EngineControl::get_input_device_name () const
2496 return input_device_combo.get_active_text ();
2500 EngineControl::get_output_device_name () const
2502 return output_device_combo.get_active_text ();
2506 EngineControl::control_app_button_clicked ()
2508 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2514 backend->launch_control_app ();
2518 EngineControl::start_stop_button_clicked ()
2520 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2526 if (ARDOUR::AudioEngine::instance()->running()) {
2527 ARDOUR::AudioEngine::instance()->stop ();
2534 EngineControl::update_devices_button_clicked ()
2536 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2542 if (backend->update_devices()) {
2543 device_list_changed ();
2548 EngineControl::manage_control_app_sensitivity ()
2550 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2556 string appname = backend->control_app_name();
2558 if (appname.empty()) {
2559 control_app_button.set_sensitive (false);
2561 control_app_button.set_sensitive (true);
2566 EngineControl::set_desired_sample_rate (uint32_t sr)
2568 _desired_sample_rate = sr;
2573 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2575 if (page_num == 0) {
2576 cancel_button->set_sensitive (true);
2577 _measure_midi.reset();
2578 update_sensitivity ();
2580 cancel_button->set_sensitive (false);
2581 ok_button->set_sensitive (false);
2584 if (page_num == midi_tab) {
2586 refresh_midi_display ();
2589 if (page_num == latency_tab) {
2592 if (ARDOUR::AudioEngine::instance()->running()) {
2593 // TODO - mark as 'stopped for latency
2598 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2600 /* save any existing latency values */
2602 uint32_t il = (uint32_t) input_latency.get_value ();
2603 uint32_t ol = (uint32_t) input_latency.get_value ();
2605 /* reset to zero so that our new test instance
2606 will be clean of any existing latency measures.
2608 NB. this should really be done by the backend
2609 when stated for latency measurement.
2612 input_latency.set_value (0);
2613 output_latency.set_value (0);
2615 push_state_to_backend (false);
2619 input_latency.set_value (il);
2620 output_latency.set_value (ol);
2623 // This should be done in push_state_to_backend()
2624 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2625 disable_latency_tab ();
2628 enable_latency_tab ();
2632 end_latency_detection ();
2633 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2638 /* latency measurement */
2641 EngineControl::check_audio_latency_measurement ()
2643 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2645 if (mtdm->resolve () < 0) {
2646 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2650 if (mtdm->err () > 0.3) {
2656 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2658 if (sample_rate == 0) {
2659 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2660 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2664 int frames_total = mtdm->del();
2665 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2667 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2668 _("Detected roundtrip latency: "),
2669 frames_total, frames_total * 1000.0f/sample_rate,
2670 _("Systemic latency: "),
2671 extra, extra * 1000.0f/sample_rate);
2675 if (mtdm->err () > 0.2) {
2677 strcat (buf, _("(signal detection error)"));
2683 strcat (buf, _("(inverted - bad wiring)"));
2687 lm_results.set_markup (string_compose (results_markup, buf));
2690 have_lm_results = true;
2691 end_latency_detection ();
2692 lm_use_button.set_sensitive (true);
2700 EngineControl::check_midi_latency_measurement ()
2702 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2704 if (!mididm->have_signal () || mididm->latency () == 0) {
2705 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2710 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2712 if (sample_rate == 0) {
2713 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2714 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2718 ARDOUR::framecnt_t frames_total = mididm->latency();
2719 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2720 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2721 _("Detected roundtrip latency: "),
2722 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2723 _("Systemic latency: "),
2724 extra, extra * 1000.0f / sample_rate);
2728 if (!mididm->ok ()) {
2730 strcat (buf, _("(averaging)"));
2734 if (mididm->deviation () > 50.0) {
2736 strcat (buf, _("(too large jitter)"));
2738 } else if (mididm->deviation () > 10.0) {
2740 strcat (buf, _("(large jitter)"));
2744 have_lm_results = true;
2745 end_latency_detection ();
2746 lm_use_button.set_sensitive (true);
2747 lm_results.set_markup (string_compose (results_markup, buf));
2749 } else if (mididm->processed () > 400) {
2750 have_lm_results = false;
2751 end_latency_detection ();
2752 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2756 lm_results.set_markup (string_compose (results_markup, buf));
2762 EngineControl::start_latency_detection ()
2764 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2765 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2767 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2768 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2769 if (_measure_midi) {
2770 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2772 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2774 lm_measure_label.set_text (_("Cancel"));
2775 have_lm_results = false;
2776 lm_use_button.set_sensitive (false);
2777 lm_input_channel_combo.set_sensitive (false);
2778 lm_output_channel_combo.set_sensitive (false);
2784 EngineControl::end_latency_detection ()
2786 latency_timeout.disconnect ();
2787 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2788 lm_measure_label.set_text (_("Measure"));
2789 if (!have_lm_results) {
2790 lm_use_button.set_sensitive (false);
2792 lm_input_channel_combo.set_sensitive (true);
2793 lm_output_channel_combo.set_sensitive (true);
2798 EngineControl::latency_button_clicked ()
2801 start_latency_detection ();
2803 end_latency_detection ();
2808 EngineControl::latency_back_button_clicked ()
2810 ARDOUR::AudioEngine::instance()->stop(true);
2811 notebook.set_current_page(0);
2815 EngineControl::use_latency_button_clicked ()
2817 if (_measure_midi) {
2818 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2822 ARDOUR::framecnt_t frames_total = mididm->latency();
2823 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2824 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2825 _measure_midi->input_latency = one_way;
2826 _measure_midi->output_latency = one_way;
2827 notebook.set_current_page (midi_tab);
2829 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2835 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2836 one_way = std::max (0., one_way);
2838 input_latency_adjustment.set_value (one_way);
2839 output_latency_adjustment.set_value (one_way);
2841 /* back to settings page */
2842 notebook.set_current_page (0);
2847 EngineControl::on_delete_event (GdkEventAny* ev)
2849 if (notebook.get_current_page() == 2) {
2850 /* currently on latency tab - be sure to clean up */
2851 end_latency_detection ();
2853 return ArdourDialog::on_delete_event (ev);
2857 EngineControl::engine_running ()
2859 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2862 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2863 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2865 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2866 connect_disconnect_button.show();
2868 started_at_least_once = true;
2869 if (_have_control) {
2870 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2872 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2874 update_sensitivity();
2878 EngineControl::engine_stopped ()
2880 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2883 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2884 connect_disconnect_button.show();
2886 if (_have_control) {
2887 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2889 engine_status.set_markup(X_(""));
2892 update_sensitivity();
2896 EngineControl::device_list_changed ()
2898 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2900 midi_option_changed();
2904 EngineControl::connect_disconnect_click()
2906 if (ARDOUR::AudioEngine::instance()->running()) {
2914 EngineControl::calibrate_audio_latency ()
2916 _measure_midi.reset ();
2917 have_lm_results = false;
2918 lm_use_button.set_sensitive (false);
2919 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2920 notebook.set_current_page (latency_tab);
2924 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2927 have_lm_results = false;
2928 lm_use_button.set_sensitive (false);
2929 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2930 notebook.set_current_page (latency_tab);
2934 EngineControl::configure_midi_devices ()
2936 notebook.set_current_page (midi_tab);