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 (!_have_control) {
1020 // set settings from backend that we do have control over
1021 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1024 if (!ignore_changes) {
1025 maybe_display_saved_state ();
1030 EngineControl::update_midi_options ()
1032 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1033 vector<string> midi_options = backend->enumerate_midi_options();
1035 if (midi_options.size() == 1) {
1036 /* only contains the "none" option */
1037 midi_option_combo.set_sensitive (false);
1039 if (_have_control) {
1040 set_popdown_strings (midi_option_combo, midi_options);
1041 midi_option_combo.set_active_text (midi_options.front());
1042 midi_option_combo.set_sensitive (true);
1044 midi_option_combo.set_sensitive (false);
1050 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1052 if (ARDOUR::Profile->get_mixbus()) {
1056 uint32_t cnt = (uint32_t) sb->get_value();
1058 sb->set_text (_("all available channels"));
1061 snprintf (buf, sizeof (buf), "%d", cnt);
1067 // @return true if there are drivers available
1069 EngineControl::set_driver_popdown_strings ()
1071 DEBUG_ECONTROL ("set_driver_popdown_strings");
1072 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1073 vector<string> drivers = backend->enumerate_drivers();
1075 if (drivers.empty ()) {
1076 // This is an error...?
1080 string current_driver = backend->driver_name ();
1082 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1084 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1087 current_driver = drivers.front ();
1090 set_popdown_strings (driver_combo, drivers);
1092 string_compose ("driver_combo.set_active_text: %1", current_driver));
1093 driver_combo.set_active_text (current_driver);
1098 EngineControl::get_default_device(const string& current_device_name,
1099 const vector<string>& available_devices)
1101 // If the current device is available, use it as default
1102 if (std::find (available_devices.begin (),
1103 available_devices.end (),
1104 current_device_name) != available_devices.end ()) {
1106 return current_device_name;
1109 using namespace ARDOUR;
1111 string default_device_name =
1112 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1114 vector<string>::const_iterator i;
1116 // If there is a "Default" device available, use it
1117 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1118 if (*i == default_device_name) {
1123 string none_device_name =
1124 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1126 // Use the first device that isn't "None"
1127 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1128 if (*i != none_device_name) {
1133 // Use "None" if there are no other available
1134 return available_devices.front();
1137 // @return true if there are devices available
1139 EngineControl::set_device_popdown_strings ()
1141 DEBUG_ECONTROL ("set_device_popdown_strings");
1142 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1143 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1145 /* NOTE: Ardour currently does not display the "available" field of the
1148 * Doing so would require a different GUI widget than the combo
1149 * box/popdown that we currently use, since it has no way to list
1150 * items that are not selectable. Something more like a popup menu,
1151 * which could have unselectable items, would be appropriate.
1154 vector<string> available_devices;
1156 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1157 available_devices.push_back (i->name);
1160 if (available_devices.empty ()) {
1164 set_popdown_strings (device_combo, available_devices);
1166 std::string default_device =
1167 get_default_device(backend->device_name(), available_devices);
1170 string_compose ("set device_combo active text: %1", default_device));
1172 device_combo.set_active_text(default_device);
1176 // @return true if there are input devices available
1178 EngineControl::set_input_device_popdown_strings ()
1180 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1181 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1182 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_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 (input_device_combo, available_devices);
1196 std::string default_device =
1197 get_default_device(backend->input_device_name(), available_devices);
1200 string_compose ("set input_device_combo active text: %1", default_device));
1201 input_device_combo.set_active_text(default_device);
1205 // @return true if there are output devices available
1207 EngineControl::set_output_device_popdown_strings ()
1209 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1210 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1211 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1213 vector<string> available_devices;
1215 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1216 available_devices.push_back (i->name);
1219 if (available_devices.empty()) {
1223 set_popdown_strings (output_device_combo, available_devices);
1225 std::string default_device =
1226 get_default_device(backend->output_device_name(), available_devices);
1229 string_compose ("set output_device_combo active text: %1", default_device));
1230 output_device_combo.set_active_text(default_device);
1235 EngineControl::list_devices ()
1237 DEBUG_ECONTROL ("list_devices");
1238 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1241 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1243 bool devices_available = false;
1245 if (backend->use_separate_input_and_output_devices ()) {
1246 bool input_devices_available = set_input_device_popdown_strings ();
1247 bool output_devices_available = set_output_device_popdown_strings ();
1248 devices_available = input_devices_available || output_devices_available;
1250 devices_available = set_device_popdown_strings ();
1253 if (devices_available) {
1256 device_combo.clear();
1257 input_device_combo.clear();
1258 output_device_combo.clear();
1260 update_sensitivity ();
1264 EngineControl::driver_changed ()
1266 SignalBlocker blocker (*this, "driver_changed");
1267 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1270 backend->set_driver (driver_combo.get_active_text());
1273 if (!ignore_changes) {
1274 maybe_display_saved_state ();
1279 EngineControl::get_sample_rates_for_all_devices ()
1281 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1282 ARDOUR::AudioEngine::instance ()->current_backend ();
1283 vector<float> all_rates;
1285 if (backend->use_separate_input_and_output_devices ()) {
1286 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1288 all_rates = backend->available_sample_rates (get_device_name ());
1294 EngineControl::get_default_sample_rates ()
1296 vector<float> rates;
1297 rates.push_back (8000.0f);
1298 rates.push_back (16000.0f);
1299 rates.push_back (32000.0f);
1300 rates.push_back (44100.0f);
1301 rates.push_back (48000.0f);
1302 rates.push_back (88200.0f);
1303 rates.push_back (96000.0f);
1304 rates.push_back (192000.0f);
1305 rates.push_back (384000.0f);
1310 EngineControl::set_samplerate_popdown_strings ()
1312 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1313 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1318 if (_have_control) {
1319 sr = get_sample_rates_for_all_devices ();
1321 sr = get_default_sample_rates ();
1324 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1325 s.push_back (rate_as_string (*x));
1326 if (*x == _desired_sample_rate) {
1331 set_popdown_strings (sample_rate_combo, s);
1334 if (desired.empty ()) {
1335 float new_active_sr = backend->default_sample_rate ();
1337 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1338 new_active_sr = sr.front ();
1341 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1343 sample_rate_combo.set_active_text (desired);
1347 update_sensitivity ();
1351 EngineControl::get_buffer_sizes_for_all_devices ()
1353 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1354 ARDOUR::AudioEngine::instance ()->current_backend ();
1355 vector<uint32_t> all_sizes;
1357 if (backend->use_separate_input_and_output_devices ()) {
1358 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1360 all_sizes = backend->available_buffer_sizes (get_device_name ());
1366 EngineControl::get_default_buffer_sizes ()
1368 vector<uint32_t> sizes;
1369 sizes.push_back (8);
1370 sizes.push_back (16);
1371 sizes.push_back (32);
1372 sizes.push_back (64);
1373 sizes.push_back (128);
1374 sizes.push_back (256);
1375 sizes.push_back (512);
1376 sizes.push_back (1024);
1377 sizes.push_back (2048);
1378 sizes.push_back (4096);
1379 sizes.push_back (8192);
1384 EngineControl::set_buffersize_popdown_strings ()
1386 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1387 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1388 vector<uint32_t> bs;
1391 if (_have_control) {
1392 bs = get_buffer_sizes_for_all_devices ();
1393 } else if (backend->can_change_buffer_size_when_running()) {
1394 bs = get_default_buffer_sizes ();
1397 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1398 s.push_back (bufsize_as_string (*x));
1401 uint32_t previous_size = 0;
1402 if (!buffer_size_combo.get_active_text().empty()) {
1403 previous_size = get_buffer_size ();
1406 set_popdown_strings (buffer_size_combo, s);
1410 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1411 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1414 buffer_size_combo.set_active_text(s.front());
1416 uint32_t period = backend->buffer_size();
1417 if (0 == period && backend->use_separate_input_and_output_devices()) {
1418 period = backend->default_buffer_size(get_input_device_name());
1420 if (0 == period && backend->use_separate_input_and_output_devices()) {
1421 period = backend->default_buffer_size(get_output_device_name());
1423 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1424 period = backend->default_buffer_size(get_device_name());
1427 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1429 show_buffer_duration ();
1431 update_sensitivity ();
1435 EngineControl::device_changed ()
1437 SignalBlocker blocker (*this, "device_changed");
1438 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1441 string device_name_in;
1442 string device_name_out; // only used if backend support separate I/O devices
1444 if (backend->use_separate_input_and_output_devices()) {
1445 device_name_in = get_input_device_name ();
1446 device_name_out = get_output_device_name ();
1448 device_name_in = get_device_name ();
1451 /* we set the backend-device to query various device related intormation.
1452 * This has the side effect that backend->device_name() will match
1453 * the device_name and 'change_device' will never be true.
1454 * so work around this by setting...
1456 if (backend->use_separate_input_and_output_devices()) {
1457 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1458 queue_device_changed = true;
1461 if (device_name_in != backend->device_name()) {
1462 queue_device_changed = true;
1466 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1467 if (backend->use_separate_input_and_output_devices()) {
1468 backend->set_input_device_name (device_name_in);
1469 backend->set_output_device_name (device_name_out);
1471 backend->set_device_name(device_name_in);
1475 /* don't allow programmatic change to combos to cause a
1476 recursive call to this method.
1478 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1480 set_samplerate_popdown_strings ();
1481 set_buffersize_popdown_strings ();
1483 /* TODO set min + max channel counts here */
1485 manage_control_app_sensitivity ();
1488 /* pick up any saved state for this device */
1490 if (!ignore_changes) {
1491 maybe_display_saved_state ();
1496 EngineControl::input_device_changed ()
1498 DEBUG_ECONTROL ("input_device_changed");
1503 EngineControl::output_device_changed ()
1505 DEBUG_ECONTROL ("output_device_changed");
1510 EngineControl::bufsize_as_string (uint32_t sz)
1512 /* Translators: "samples" is always plural here, so no
1513 need for plural+singular forms.
1516 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1521 EngineControl::sample_rate_changed ()
1523 DEBUG_ECONTROL ("sample_rate_changed");
1524 /* reset the strings for buffer size to show the correct msec value
1525 (reflecting the new sample rate).
1528 show_buffer_duration ();
1533 EngineControl::buffer_size_changed ()
1535 DEBUG_ECONTROL ("buffer_size_changed");
1536 show_buffer_duration ();
1540 EngineControl::show_buffer_duration ()
1542 DEBUG_ECONTROL ("show_buffer_duration");
1543 /* buffer sizes - convert from just samples to samples + msecs for
1544 * the displayed string
1547 string bs_text = buffer_size_combo.get_active_text ();
1548 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1549 uint32_t rate = get_rate();
1551 /* Developers: note the hard-coding of a double buffered model
1552 in the (2 * samples) computation of latency. we always start
1553 the audiobackend in this configuration.
1555 /* note to jack1 developers: ardour also always starts the engine
1556 * in async mode (no jack2 --sync option) which adds an extra cycle
1557 * of latency with jack2 (and *3 would be correct)
1558 * The value can also be wrong if jackd is started externally..
1560 * At the time of writing the ALSA backend always uses double-buffering *2,
1561 * The Dummy backend *1, and who knows what ASIO really does :)
1563 * So just display the period size, that's also what
1564 * ARDOUR_UI::update_sample_rate() does for the status bar.
1565 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1566 * but still, that's the buffer period, not [round-trip] latency)
1569 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1570 buffer_size_duration_label.set_text (buf);
1574 EngineControl::midi_option_changed ()
1576 DEBUG_ECONTROL ("midi_option_changed");
1577 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1580 backend->set_midi_option (get_midi_option());
1582 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1584 //_midi_devices.clear(); // TODO merge with state-saved settings..
1585 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1586 std::vector<MidiDeviceSettings> new_devices;
1588 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1589 MidiDeviceSettings mds = find_midi_device (i->name);
1590 if (i->available && !mds) {
1591 uint32_t input_latency = 0;
1592 uint32_t output_latency = 0;
1593 if (_can_set_midi_latencies) {
1594 input_latency = backend->systemic_midi_input_latency (i->name);
1595 output_latency = backend->systemic_midi_output_latency (i->name);
1597 bool enabled = backend->midi_device_enabled (i->name);
1598 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1599 new_devices.push_back (ptr);
1600 } else if (i->available) {
1601 new_devices.push_back (mds);
1604 _midi_devices = new_devices;
1606 if (_midi_devices.empty()) {
1607 midi_devices_button.set_sensitive (false);
1609 midi_devices_button.set_sensitive (true);
1614 EngineControl::parameter_changed ()
1618 EngineControl::State
1619 EngineControl::get_matching_state (
1620 const string& backend,
1621 const string& driver,
1622 const string& device)
1624 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1625 if ((*i)->backend == backend &&
1626 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1634 EngineControl::State
1635 EngineControl::get_matching_state (
1636 const string& backend,
1637 const string& driver,
1638 const string& input_device,
1639 const string& output_device)
1641 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1642 if ((*i)->backend == backend &&
1643 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1651 EngineControl::State
1652 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1654 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1657 if (backend->use_separate_input_and_output_devices ()) {
1658 return get_matching_state (backend_combo.get_active_text(),
1659 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1660 input_device_combo.get_active_text(),
1661 output_device_combo.get_active_text());
1663 return get_matching_state (backend_combo.get_active_text(),
1664 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1665 device_combo.get_active_text());
1669 return get_matching_state (backend_combo.get_active_text(),
1671 device_combo.get_active_text());
1674 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1675 const EngineControl::State& state2)
1677 if (state1->backend == state2->backend &&
1678 state1->driver == state2->driver &&
1679 state1->device == state2->device &&
1680 state1->input_device == state2->input_device &&
1681 state1->output_device == state2->output_device) {
1687 EngineControl::State
1688 EngineControl::save_state ()
1692 if (!_have_control) {
1693 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1697 state.reset(new StateStruct);
1698 state->backend = get_backend ();
1700 state.reset(new StateStruct);
1701 store_state (state);
1704 for (StateList::iterator i = states.begin(); i != states.end();) {
1705 if (equivalent_states (*i, state)) {
1706 i = states.erase(i);
1712 states.push_back (state);
1718 EngineControl::store_state (State state)
1720 state->backend = get_backend ();
1721 state->driver = get_driver ();
1722 state->device = get_device_name ();
1723 state->input_device = get_input_device_name ();
1724 state->output_device = get_output_device_name ();
1725 state->sample_rate = get_rate ();
1726 state->buffer_size = get_buffer_size ();
1727 state->input_latency = get_input_latency ();
1728 state->output_latency = get_output_latency ();
1729 state->input_channels = get_input_channels ();
1730 state->output_channels = get_output_channels ();
1731 state->midi_option = get_midi_option ();
1732 state->midi_devices = _midi_devices;
1736 EngineControl::maybe_display_saved_state ()
1738 if (!_have_control) {
1742 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1745 DEBUG_ECONTROL ("Restoring saved state");
1746 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1748 if (!_desired_sample_rate) {
1749 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1751 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1752 /* call this explicitly because we're ignoring changes to
1753 the controls at this point.
1755 show_buffer_duration ();
1756 input_latency.set_value (state->input_latency);
1757 output_latency.set_value (state->output_latency);
1759 if (!state->midi_option.empty()) {
1760 midi_option_combo.set_active_text (state->midi_option);
1761 _midi_devices = state->midi_devices;
1764 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1769 EngineControl::get_state ()
1771 LocaleGuard lg (X_("C"));
1773 XMLNode* root = new XMLNode ("AudioMIDISetup");
1776 if (!states.empty()) {
1777 XMLNode* state_nodes = new XMLNode ("EngineStates");
1779 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1781 XMLNode* node = new XMLNode ("State");
1783 node->add_property ("backend", (*i)->backend);
1784 node->add_property ("driver", (*i)->driver);
1785 node->add_property ("device", (*i)->device);
1786 node->add_property ("input-device", (*i)->input_device);
1787 node->add_property ("output-device", (*i)->output_device);
1788 node->add_property ("sample-rate", (*i)->sample_rate);
1789 node->add_property ("buffer-size", (*i)->buffer_size);
1790 node->add_property ("input-latency", (*i)->input_latency);
1791 node->add_property ("output-latency", (*i)->output_latency);
1792 node->add_property ("input-channels", (*i)->input_channels);
1793 node->add_property ("output-channels", (*i)->output_channels);
1794 node->add_property ("active", (*i)->active ? "yes" : "no");
1795 node->add_property ("midi-option", (*i)->midi_option);
1797 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1798 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1799 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1800 midi_device_stuff->add_property (X_("name"), (*p)->name);
1801 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1802 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1803 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1804 midi_devices->add_child_nocopy (*midi_device_stuff);
1806 node->add_child_nocopy (*midi_devices);
1808 state_nodes->add_child_nocopy (*node);
1811 root->add_child_nocopy (*state_nodes);
1818 EngineControl::set_default_state ()
1820 vector<string> backend_names;
1821 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1823 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1824 backend_names.push_back ((*b)->name);
1826 backend_combo.set_active_text (backend_names.front());
1828 // We could set default backends per platform etc here
1834 EngineControl::set_state (const XMLNode& root)
1836 XMLNodeList clist, cclist;
1837 XMLNodeConstIterator citer, cciter;
1839 XMLNode* grandchild;
1840 XMLProperty* prop = NULL;
1842 fprintf (stderr, "EngineControl::set_state\n");
1844 if (root.name() != "AudioMIDISetup") {
1848 clist = root.children();
1852 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1856 if (child->name() != "EngineStates") {
1860 cclist = child->children();
1862 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1863 State state (new StateStruct);
1865 grandchild = *cciter;
1867 if (grandchild->name() != "State") {
1871 if ((prop = grandchild->property ("backend")) == 0) {
1874 state->backend = prop->value ();
1876 if ((prop = grandchild->property ("driver")) == 0) {
1879 state->driver = prop->value ();
1881 if ((prop = grandchild->property ("device")) == 0) {
1884 state->device = prop->value ();
1886 if ((prop = grandchild->property ("input-device")) == 0) {
1889 state->input_device = prop->value ();
1891 if ((prop = grandchild->property ("output-device")) == 0) {
1894 state->output_device = prop->value ();
1896 if ((prop = grandchild->property ("sample-rate")) == 0) {
1899 state->sample_rate = atof (prop->value ());
1901 if ((prop = grandchild->property ("buffer-size")) == 0) {
1904 state->buffer_size = atoi (prop->value ());
1906 if ((prop = grandchild->property ("input-latency")) == 0) {
1909 state->input_latency = atoi (prop->value ());
1911 if ((prop = grandchild->property ("output-latency")) == 0) {
1914 state->output_latency = atoi (prop->value ());
1916 if ((prop = grandchild->property ("input-channels")) == 0) {
1919 state->input_channels = atoi (prop->value ());
1921 if ((prop = grandchild->property ("output-channels")) == 0) {
1924 state->output_channels = atoi (prop->value ());
1926 if ((prop = grandchild->property ("active")) == 0) {
1929 state->active = string_is_affirmative (prop->value ());
1931 if ((prop = grandchild->property ("midi-option")) == 0) {
1934 state->midi_option = prop->value ();
1936 state->midi_devices.clear();
1938 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1939 const XMLNodeList mnc = midinode->children();
1940 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1941 if ((*n)->property (X_("name")) == 0
1942 || (*n)->property (X_("enabled")) == 0
1943 || (*n)->property (X_("input-latency")) == 0
1944 || (*n)->property (X_("output-latency")) == 0
1949 MidiDeviceSettings ptr (new MidiDeviceSetting(
1950 (*n)->property (X_("name"))->value (),
1951 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1952 atoi ((*n)->property (X_("input-latency"))->value ()),
1953 atoi ((*n)->property (X_("output-latency"))->value ())
1955 state->midi_devices.push_back (ptr);
1960 /* remove accumulated duplicates (due to bug in ealier version)
1961 * this can be removed again before release
1963 for (StateList::iterator i = states.begin(); i != states.end();) {
1964 if ((*i)->backend == state->backend &&
1965 (*i)->driver == state->driver &&
1966 (*i)->device == state->device) {
1967 i = states.erase(i);
1974 states.push_back (state);
1978 /* now see if there was an active state and switch the setup to it */
1980 // purge states of backend that are not available in this built
1981 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1982 vector<std::string> backend_names;
1984 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1985 backend_names.push_back((*i)->name);
1987 for (StateList::iterator i = states.begin(); i != states.end();) {
1988 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1989 i = states.erase(i);
1995 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1998 return set_current_state (*i);
2005 EngineControl::set_current_state (const State& state)
2007 DEBUG_ECONTROL ("set_current_state");
2009 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2011 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2012 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2013 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2014 // this shouldn't happen as the invalid backend names should have been
2015 // removed from the list of states.
2019 // now reflect the change in the backend in the GUI so backend_changed will
2020 // do the right thing
2021 backend_combo.set_active_text (state->backend);
2023 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2025 // we don't have control don't restore state
2030 if (!state->driver.empty ()) {
2031 if (!backend->requires_driver_selection ()) {
2032 DEBUG_ECONTROL ("Backend should require driver selection");
2033 // A backend has changed from having driver selection to not having
2034 // it or someone has been manually editing a config file and messed
2039 if (backend->set_driver (state->driver) != 0) {
2040 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2041 // Driver names for a backend have changed and the name in the
2042 // config file is now invalid or support for driver is no longer
2043 // included in the backend
2046 // no need to set the driver_combo as backend_changed will use
2047 // backend->driver_name to set the active driver
2050 if (!state->device.empty ()) {
2051 if (backend->set_device_name (state->device) != 0) {
2053 string_compose ("Unable to set device name %1", state->device));
2054 // device is no longer available on the system
2057 // no need to set active device as it will be picked up in
2058 // via backend_changed ()/set_device_popdown_strings
2061 // backend supports separate input/output devices
2062 if (backend->set_input_device_name (state->input_device) != 0) {
2063 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2064 state->input_device));
2065 // input device is no longer available on the system
2069 if (backend->set_output_device_name (state->output_device) != 0) {
2070 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2071 state->input_device));
2072 // output device is no longer available on the system
2075 // no need to set active devices as it will be picked up in via
2076 // backend_changed ()/set_*_device_popdown_strings
2081 // Now restore the state of the rest of the controls
2083 // We don't use a SignalBlocker as set_current_state is currently only
2084 // called from set_state before any signals are connected. If at some point
2085 // a more general named state mechanism is implemented and
2086 // set_current_state is called while signals are connected then a
2087 // SignalBlocker will need to be instantiated before setting these.
2089 device_combo.set_active_text (state->device);
2090 input_device_combo.set_active_text (state->input_device);
2091 output_device_combo.set_active_text (state->output_device);
2092 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2093 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2094 input_latency.set_value (state->input_latency);
2095 output_latency.set_value (state->output_latency);
2096 midi_option_combo.set_active_text (state->midi_option);
2101 EngineControl::push_state_to_backend (bool start)
2103 DEBUG_ECONTROL ("push_state_to_backend");
2104 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2110 /* figure out what is going to change */
2112 bool restart_required = false;
2113 bool was_running = ARDOUR::AudioEngine::instance()->running();
2114 bool change_driver = false;
2115 bool change_device = false;
2116 bool change_rate = false;
2117 bool change_bufsize = false;
2118 bool change_latency = false;
2119 bool change_channels = false;
2120 bool change_midi = false;
2122 uint32_t ochan = get_output_channels ();
2123 uint32_t ichan = get_input_channels ();
2125 if (_have_control) {
2127 if (started_at_least_once) {
2129 /* we can control the backend */
2131 if (backend->requires_driver_selection()) {
2132 if (get_driver() != backend->driver_name()) {
2133 change_driver = true;
2137 if (backend->use_separate_input_and_output_devices()) {
2138 if (get_input_device_name() != backend->input_device_name()) {
2139 change_device = true;
2141 if (get_output_device_name() != backend->output_device_name()) {
2142 change_device = true;
2145 if (get_device_name() != backend->device_name()) {
2146 change_device = true;
2150 if (queue_device_changed) {
2151 change_device = true;
2154 if (get_rate() != backend->sample_rate()) {
2158 if (get_buffer_size() != backend->buffer_size()) {
2159 change_bufsize = true;
2162 if (get_midi_option() != backend->midi_option()) {
2166 /* zero-requested channels means "all available" */
2169 ichan = backend->input_channels();
2173 ochan = backend->output_channels();
2176 if (ichan != backend->input_channels()) {
2177 change_channels = true;
2180 if (ochan != backend->output_channels()) {
2181 change_channels = true;
2184 if (get_input_latency() != backend->systemic_input_latency() ||
2185 get_output_latency() != backend->systemic_output_latency()) {
2186 change_latency = true;
2189 /* backend never started, so we have to force a group
2192 change_device = true;
2193 if (backend->requires_driver_selection()) {
2194 change_driver = true;
2197 change_bufsize = true;
2198 change_channels = true;
2199 change_latency = true;
2205 /* we have no control over the backend, meaning that we can
2206 * only possibly change sample rate and buffer size.
2210 if (get_rate() != backend->sample_rate()) {
2211 change_bufsize = true;
2214 if (get_buffer_size() != backend->buffer_size()) {
2215 change_bufsize = true;
2219 queue_device_changed = false;
2221 if (!_have_control) {
2223 /* We do not have control over the backend, so the best we can
2224 * do is try to change the sample rate and/or bufsize and get
2228 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2232 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2237 backend->set_sample_rate (get_rate());
2240 if (change_bufsize) {
2241 backend->set_buffer_size (get_buffer_size());
2245 if (ARDOUR::AudioEngine::instance()->start ()) {
2246 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2256 /* determine if we need to stop the backend before changing parameters */
2258 if (change_driver || change_device || change_channels || change_latency ||
2259 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2261 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2262 restart_required = true;
2264 restart_required = false;
2269 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2270 /* no changes in any parameters that absolutely require a
2271 * restart, so check those that might be changeable without a
2275 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2276 /* can't do this while running ... */
2277 restart_required = true;
2280 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2281 /* can't do this while running ... */
2282 restart_required = true;
2288 if (restart_required) {
2289 if (ARDOUR::AudioEngine::instance()->stop()) {
2295 if (change_driver && backend->set_driver (get_driver())) {
2296 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2299 if (backend->use_separate_input_and_output_devices()) {
2300 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2301 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2304 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2305 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2309 if (change_device && backend->set_device_name (get_device_name())) {
2310 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2314 if (change_rate && backend->set_sample_rate (get_rate())) {
2315 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2318 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2319 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2323 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2324 if (backend->set_input_channels (get_input_channels())) {
2325 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2328 if (backend->set_output_channels (get_output_channels())) {
2329 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2333 if (change_latency) {
2334 if (backend->set_systemic_input_latency (get_input_latency())) {
2335 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2338 if (backend->set_systemic_output_latency (get_output_latency())) {
2339 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2345 backend->set_midi_option (get_midi_option());
2349 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2350 if (_measure_midi) {
2351 if (*p == _measure_midi) {
2352 backend->set_midi_device_enabled ((*p)->name, true);
2354 backend->set_midi_device_enabled ((*p)->name, false);
2358 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2359 if (backend->can_set_systemic_midi_latencies()) {
2360 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2361 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2366 if (start || (was_running && restart_required)) {
2367 if (ARDOUR::AudioEngine::instance()->start()) {
2378 EngineControl::post_push ()
2380 /* get a pointer to the current state object, creating one if
2384 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2387 state = save_state ();
2395 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2396 (*i)->active = false;
2399 /* mark this one active (to be used next time the dialog is
2403 state->active = true;
2405 if (_have_control) { // XXX
2406 manage_control_app_sensitivity ();
2409 /* schedule a redisplay of MIDI ports */
2410 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2415 EngineControl::get_rate () const
2417 float r = atof (sample_rate_combo.get_active_text ());
2418 /* the string may have been translated with an abbreviation for
2419 * thousands, so use a crude heuristic to fix this.
2429 EngineControl::get_buffer_size () const
2431 string txt = buffer_size_combo.get_active_text ();
2434 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2435 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2436 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2444 EngineControl::get_midi_option () const
2446 return midi_option_combo.get_active_text();
2450 EngineControl::get_input_channels() const
2452 if (ARDOUR::Profile->get_mixbus()) {
2453 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2454 if (!backend) return 0;
2455 return backend->input_channels();
2457 return (uint32_t) input_channels_adjustment.get_value();
2461 EngineControl::get_output_channels() const
2463 if (ARDOUR::Profile->get_mixbus()) {
2464 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2465 if (!backend) return 0;
2466 return backend->input_channels();
2468 return (uint32_t) output_channels_adjustment.get_value();
2472 EngineControl::get_input_latency() const
2474 return (uint32_t) input_latency_adjustment.get_value();
2478 EngineControl::get_output_latency() const
2480 return (uint32_t) output_latency_adjustment.get_value();
2484 EngineControl::get_backend () const
2486 return backend_combo.get_active_text ();
2490 EngineControl::get_driver () const
2492 if (driver_combo.get_parent()) {
2493 return driver_combo.get_active_text ();
2500 EngineControl::get_device_name () const
2502 return device_combo.get_active_text ();
2506 EngineControl::get_input_device_name () const
2508 return input_device_combo.get_active_text ();
2512 EngineControl::get_output_device_name () const
2514 return output_device_combo.get_active_text ();
2518 EngineControl::control_app_button_clicked ()
2520 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2526 backend->launch_control_app ();
2530 EngineControl::start_stop_button_clicked ()
2532 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2538 if (ARDOUR::AudioEngine::instance()->running()) {
2539 ARDOUR::AudioEngine::instance()->stop ();
2546 EngineControl::update_devices_button_clicked ()
2548 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2554 if (backend->update_devices()) {
2555 device_list_changed ();
2560 EngineControl::manage_control_app_sensitivity ()
2562 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2568 string appname = backend->control_app_name();
2570 if (appname.empty()) {
2571 control_app_button.set_sensitive (false);
2573 control_app_button.set_sensitive (true);
2578 EngineControl::set_desired_sample_rate (uint32_t sr)
2580 _desired_sample_rate = sr;
2585 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2587 if (page_num == 0) {
2588 cancel_button->set_sensitive (true);
2589 _measure_midi.reset();
2590 update_sensitivity ();
2592 cancel_button->set_sensitive (false);
2593 ok_button->set_sensitive (false);
2596 if (page_num == midi_tab) {
2598 refresh_midi_display ();
2601 if (page_num == latency_tab) {
2604 if (ARDOUR::AudioEngine::instance()->running()) {
2605 // TODO - mark as 'stopped for latency
2610 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2612 /* save any existing latency values */
2614 uint32_t il = (uint32_t) input_latency.get_value ();
2615 uint32_t ol = (uint32_t) input_latency.get_value ();
2617 /* reset to zero so that our new test instance
2618 will be clean of any existing latency measures.
2620 NB. this should really be done by the backend
2621 when stated for latency measurement.
2624 input_latency.set_value (0);
2625 output_latency.set_value (0);
2627 push_state_to_backend (false);
2631 input_latency.set_value (il);
2632 output_latency.set_value (ol);
2635 // This should be done in push_state_to_backend()
2636 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2637 disable_latency_tab ();
2640 enable_latency_tab ();
2644 end_latency_detection ();
2645 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2650 /* latency measurement */
2653 EngineControl::check_audio_latency_measurement ()
2655 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2657 if (mtdm->resolve () < 0) {
2658 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2662 if (mtdm->err () > 0.3) {
2668 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2670 if (sample_rate == 0) {
2671 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2672 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2676 int frames_total = mtdm->del();
2677 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2679 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2680 _("Detected roundtrip latency: "),
2681 frames_total, frames_total * 1000.0f/sample_rate,
2682 _("Systemic latency: "),
2683 extra, extra * 1000.0f/sample_rate);
2687 if (mtdm->err () > 0.2) {
2689 strcat (buf, _("(signal detection error)"));
2695 strcat (buf, _("(inverted - bad wiring)"));
2699 lm_results.set_markup (string_compose (results_markup, buf));
2702 have_lm_results = true;
2703 end_latency_detection ();
2704 lm_use_button.set_sensitive (true);
2712 EngineControl::check_midi_latency_measurement ()
2714 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2716 if (!mididm->have_signal () || mididm->latency () == 0) {
2717 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2722 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2724 if (sample_rate == 0) {
2725 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2726 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2730 ARDOUR::framecnt_t frames_total = mididm->latency();
2731 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2732 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2733 _("Detected roundtrip latency: "),
2734 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2735 _("Systemic latency: "),
2736 extra, extra * 1000.0f / sample_rate);
2740 if (!mididm->ok ()) {
2742 strcat (buf, _("(averaging)"));
2746 if (mididm->deviation () > 50.0) {
2748 strcat (buf, _("(too large jitter)"));
2750 } else if (mididm->deviation () > 10.0) {
2752 strcat (buf, _("(large jitter)"));
2756 have_lm_results = true;
2757 end_latency_detection ();
2758 lm_use_button.set_sensitive (true);
2759 lm_results.set_markup (string_compose (results_markup, buf));
2761 } else if (mididm->processed () > 400) {
2762 have_lm_results = false;
2763 end_latency_detection ();
2764 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2768 lm_results.set_markup (string_compose (results_markup, buf));
2774 EngineControl::start_latency_detection ()
2776 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2777 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2779 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2780 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2781 if (_measure_midi) {
2782 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2784 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2786 lm_measure_label.set_text (_("Cancel"));
2787 have_lm_results = false;
2788 lm_use_button.set_sensitive (false);
2789 lm_input_channel_combo.set_sensitive (false);
2790 lm_output_channel_combo.set_sensitive (false);
2796 EngineControl::end_latency_detection ()
2798 latency_timeout.disconnect ();
2799 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2800 lm_measure_label.set_text (_("Measure"));
2801 if (!have_lm_results) {
2802 lm_use_button.set_sensitive (false);
2804 lm_input_channel_combo.set_sensitive (true);
2805 lm_output_channel_combo.set_sensitive (true);
2810 EngineControl::latency_button_clicked ()
2813 start_latency_detection ();
2815 end_latency_detection ();
2820 EngineControl::latency_back_button_clicked ()
2822 ARDOUR::AudioEngine::instance()->stop(true);
2823 notebook.set_current_page(0);
2827 EngineControl::use_latency_button_clicked ()
2829 if (_measure_midi) {
2830 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2834 ARDOUR::framecnt_t frames_total = mididm->latency();
2835 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2836 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2837 _measure_midi->input_latency = one_way;
2838 _measure_midi->output_latency = one_way;
2839 notebook.set_current_page (midi_tab);
2841 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2847 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2848 one_way = std::max (0., one_way);
2850 input_latency_adjustment.set_value (one_way);
2851 output_latency_adjustment.set_value (one_way);
2853 /* back to settings page */
2854 notebook.set_current_page (0);
2859 EngineControl::on_delete_event (GdkEventAny* ev)
2861 if (notebook.get_current_page() == 2) {
2862 /* currently on latency tab - be sure to clean up */
2863 end_latency_detection ();
2865 return ArdourDialog::on_delete_event (ev);
2869 EngineControl::engine_running ()
2871 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2874 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2875 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2877 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2878 connect_disconnect_button.show();
2880 started_at_least_once = true;
2881 if (_have_control) {
2882 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2884 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2886 update_sensitivity();
2890 EngineControl::engine_stopped ()
2892 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2895 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2896 connect_disconnect_button.show();
2898 if (_have_control) {
2899 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2901 engine_status.set_markup(X_(""));
2904 update_sensitivity();
2908 EngineControl::device_list_changed ()
2910 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2912 midi_option_changed();
2916 EngineControl::connect_disconnect_click()
2918 if (ARDOUR::AudioEngine::instance()->running()) {
2926 EngineControl::calibrate_audio_latency ()
2928 _measure_midi.reset ();
2929 have_lm_results = false;
2930 lm_use_button.set_sensitive (false);
2931 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2932 notebook.set_current_page (latency_tab);
2936 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2939 have_lm_results = false;
2940 lm_use_button.set_sensitive (false);
2941 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2942 notebook.set_current_page (latency_tab);
2946 EngineControl::configure_midi_devices ()
2948 notebook.set_current_page (midi_tab);