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 (_have_control && !ignore_changes) {
1025 // set driver & devices
1026 State state = get_matching_state (backend_combo.get_active_text());
1028 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1029 set_current_state (state);
1033 if (!ignore_changes) {
1034 maybe_display_saved_state ();
1039 EngineControl::update_midi_options ()
1041 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1042 vector<string> midi_options = backend->enumerate_midi_options();
1044 if (midi_options.size() == 1) {
1045 /* only contains the "none" option */
1046 midi_option_combo.set_sensitive (false);
1048 if (_have_control) {
1049 set_popdown_strings (midi_option_combo, midi_options);
1050 midi_option_combo.set_active_text (midi_options.front());
1051 midi_option_combo.set_sensitive (true);
1053 midi_option_combo.set_sensitive (false);
1059 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1061 if (ARDOUR::Profile->get_mixbus()) {
1065 uint32_t cnt = (uint32_t) sb->get_value();
1067 sb->set_text (_("all available channels"));
1070 snprintf (buf, sizeof (buf), "%d", cnt);
1076 // @return true if there are drivers available
1078 EngineControl::set_driver_popdown_strings ()
1080 DEBUG_ECONTROL ("set_driver_popdown_strings");
1081 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1082 vector<string> drivers = backend->enumerate_drivers();
1084 if (drivers.empty ()) {
1085 // This is an error...?
1089 string current_driver = backend->driver_name ();
1091 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1093 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1096 current_driver = drivers.front ();
1099 set_popdown_strings (driver_combo, drivers);
1101 string_compose ("driver_combo.set_active_text: %1", current_driver));
1102 driver_combo.set_active_text (current_driver);
1107 EngineControl::get_default_device(const string& current_device_name,
1108 const vector<string>& available_devices)
1110 // If the current device is available, use it as default
1111 if (std::find (available_devices.begin (),
1112 available_devices.end (),
1113 current_device_name) != available_devices.end ()) {
1115 return current_device_name;
1118 using namespace ARDOUR;
1120 string default_device_name =
1121 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1123 vector<string>::const_iterator i;
1125 // If there is a "Default" device available, use it
1126 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1127 if (*i == default_device_name) {
1132 string none_device_name =
1133 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1135 // Use the first device that isn't "None"
1136 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1137 if (*i != none_device_name) {
1142 // Use "None" if there are no other available
1143 return available_devices.front();
1146 // @return true if there are devices available
1148 EngineControl::set_device_popdown_strings ()
1150 DEBUG_ECONTROL ("set_device_popdown_strings");
1151 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1152 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1154 /* NOTE: Ardour currently does not display the "available" field of the
1157 * Doing so would require a different GUI widget than the combo
1158 * box/popdown that we currently use, since it has no way to list
1159 * items that are not selectable. Something more like a popup menu,
1160 * which could have unselectable items, would be appropriate.
1163 vector<string> available_devices;
1165 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1166 available_devices.push_back (i->name);
1169 if (available_devices.empty ()) {
1173 set_popdown_strings (device_combo, available_devices);
1175 std::string default_device =
1176 get_default_device(backend->device_name(), available_devices);
1179 string_compose ("set device_combo active text: %1", default_device));
1181 device_combo.set_active_text(default_device);
1185 // @return true if there are input devices available
1187 EngineControl::set_input_device_popdown_strings ()
1189 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1190 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1191 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1193 vector<string> available_devices;
1195 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1196 available_devices.push_back (i->name);
1199 if (available_devices.empty()) {
1203 set_popdown_strings (input_device_combo, available_devices);
1205 std::string default_device =
1206 get_default_device(backend->input_device_name(), available_devices);
1209 string_compose ("set input_device_combo active text: %1", default_device));
1210 input_device_combo.set_active_text(default_device);
1214 // @return true if there are output devices available
1216 EngineControl::set_output_device_popdown_strings ()
1218 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1219 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1220 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1222 vector<string> available_devices;
1224 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1225 available_devices.push_back (i->name);
1228 if (available_devices.empty()) {
1232 set_popdown_strings (output_device_combo, available_devices);
1234 std::string default_device =
1235 get_default_device(backend->output_device_name(), available_devices);
1238 string_compose ("set output_device_combo active text: %1", default_device));
1239 output_device_combo.set_active_text(default_device);
1244 EngineControl::list_devices ()
1246 DEBUG_ECONTROL ("list_devices");
1247 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1250 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1252 bool devices_available = false;
1254 if (backend->use_separate_input_and_output_devices ()) {
1255 bool input_devices_available = set_input_device_popdown_strings ();
1256 bool output_devices_available = set_output_device_popdown_strings ();
1257 devices_available = input_devices_available || output_devices_available;
1259 devices_available = set_device_popdown_strings ();
1262 if (devices_available) {
1265 device_combo.clear();
1266 input_device_combo.clear();
1267 output_device_combo.clear();
1269 update_sensitivity ();
1273 EngineControl::driver_changed ()
1275 SignalBlocker blocker (*this, "driver_changed");
1276 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1279 backend->set_driver (driver_combo.get_active_text());
1282 // TODO load LRU device(s) for backend + driver combo
1284 if (!ignore_changes) {
1285 maybe_display_saved_state ();
1290 EngineControl::get_sample_rates_for_all_devices ()
1292 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1293 ARDOUR::AudioEngine::instance ()->current_backend ();
1294 vector<float> all_rates;
1296 if (backend->use_separate_input_and_output_devices ()) {
1297 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1299 all_rates = backend->available_sample_rates (get_device_name ());
1305 EngineControl::get_default_sample_rates ()
1307 vector<float> rates;
1308 rates.push_back (8000.0f);
1309 rates.push_back (16000.0f);
1310 rates.push_back (32000.0f);
1311 rates.push_back (44100.0f);
1312 rates.push_back (48000.0f);
1313 rates.push_back (88200.0f);
1314 rates.push_back (96000.0f);
1315 rates.push_back (192000.0f);
1316 rates.push_back (384000.0f);
1321 EngineControl::set_samplerate_popdown_strings ()
1323 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1324 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1329 if (_have_control) {
1330 sr = get_sample_rates_for_all_devices ();
1332 sr = get_default_sample_rates ();
1335 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1336 s.push_back (rate_as_string (*x));
1337 if (*x == _desired_sample_rate) {
1342 set_popdown_strings (sample_rate_combo, s);
1345 if (desired.empty ()) {
1346 float new_active_sr = backend->default_sample_rate ();
1348 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1349 new_active_sr = sr.front ();
1352 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1354 sample_rate_combo.set_active_text (desired);
1358 update_sensitivity ();
1362 EngineControl::get_buffer_sizes_for_all_devices ()
1364 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1365 ARDOUR::AudioEngine::instance ()->current_backend ();
1366 vector<uint32_t> all_sizes;
1368 if (backend->use_separate_input_and_output_devices ()) {
1369 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1371 all_sizes = backend->available_buffer_sizes (get_device_name ());
1377 EngineControl::get_default_buffer_sizes ()
1379 vector<uint32_t> sizes;
1380 sizes.push_back (8);
1381 sizes.push_back (16);
1382 sizes.push_back (32);
1383 sizes.push_back (64);
1384 sizes.push_back (128);
1385 sizes.push_back (256);
1386 sizes.push_back (512);
1387 sizes.push_back (1024);
1388 sizes.push_back (2048);
1389 sizes.push_back (4096);
1390 sizes.push_back (8192);
1395 EngineControl::set_buffersize_popdown_strings ()
1397 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1398 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1399 vector<uint32_t> bs;
1402 if (_have_control) {
1403 bs = get_buffer_sizes_for_all_devices ();
1404 } else if (backend->can_change_buffer_size_when_running()) {
1405 bs = get_default_buffer_sizes ();
1408 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1409 s.push_back (bufsize_as_string (*x));
1412 uint32_t previous_size = 0;
1413 if (!buffer_size_combo.get_active_text().empty()) {
1414 previous_size = get_buffer_size ();
1417 set_popdown_strings (buffer_size_combo, s);
1421 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1422 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1425 buffer_size_combo.set_active_text(s.front());
1427 uint32_t period = backend->buffer_size();
1428 if (0 == period && backend->use_separate_input_and_output_devices()) {
1429 period = backend->default_buffer_size(get_input_device_name());
1431 if (0 == period && backend->use_separate_input_and_output_devices()) {
1432 period = backend->default_buffer_size(get_output_device_name());
1434 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1435 period = backend->default_buffer_size(get_device_name());
1438 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1440 show_buffer_duration ();
1442 update_sensitivity ();
1446 EngineControl::device_changed ()
1448 SignalBlocker blocker (*this, "device_changed");
1449 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1452 string device_name_in;
1453 string device_name_out; // only used if backend support separate I/O devices
1455 if (backend->use_separate_input_and_output_devices()) {
1456 device_name_in = get_input_device_name ();
1457 device_name_out = get_output_device_name ();
1459 device_name_in = get_device_name ();
1462 /* we set the backend-device to query various device related intormation.
1463 * This has the side effect that backend->device_name() will match
1464 * the device_name and 'change_device' will never be true.
1465 * so work around this by setting...
1467 if (backend->use_separate_input_and_output_devices()) {
1468 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1469 queue_device_changed = true;
1472 if (device_name_in != backend->device_name()) {
1473 queue_device_changed = true;
1477 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1478 if (backend->use_separate_input_and_output_devices()) {
1479 backend->set_input_device_name (device_name_in);
1480 backend->set_output_device_name (device_name_out);
1482 backend->set_device_name(device_name_in);
1486 /* don't allow programmatic change to combos to cause a
1487 recursive call to this method.
1489 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1491 set_samplerate_popdown_strings ();
1492 set_buffersize_popdown_strings ();
1494 /* TODO set min + max channel counts here */
1496 manage_control_app_sensitivity ();
1499 /* pick up any saved state for this device */
1501 if (!ignore_changes) {
1502 maybe_display_saved_state ();
1507 EngineControl::input_device_changed ()
1509 DEBUG_ECONTROL ("input_device_changed");
1514 EngineControl::output_device_changed ()
1516 DEBUG_ECONTROL ("output_device_changed");
1521 EngineControl::bufsize_as_string (uint32_t sz)
1523 /* Translators: "samples" is always plural here, so no
1524 need for plural+singular forms.
1527 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1532 EngineControl::sample_rate_changed ()
1534 DEBUG_ECONTROL ("sample_rate_changed");
1535 /* reset the strings for buffer size to show the correct msec value
1536 (reflecting the new sample rate).
1539 show_buffer_duration ();
1544 EngineControl::buffer_size_changed ()
1546 DEBUG_ECONTROL ("buffer_size_changed");
1547 show_buffer_duration ();
1551 EngineControl::show_buffer_duration ()
1553 DEBUG_ECONTROL ("show_buffer_duration");
1554 /* buffer sizes - convert from just samples to samples + msecs for
1555 * the displayed string
1558 string bs_text = buffer_size_combo.get_active_text ();
1559 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1560 uint32_t rate = get_rate();
1562 /* Developers: note the hard-coding of a double buffered model
1563 in the (2 * samples) computation of latency. we always start
1564 the audiobackend in this configuration.
1566 /* note to jack1 developers: ardour also always starts the engine
1567 * in async mode (no jack2 --sync option) which adds an extra cycle
1568 * of latency with jack2 (and *3 would be correct)
1569 * The value can also be wrong if jackd is started externally..
1571 * At the time of writing the ALSA backend always uses double-buffering *2,
1572 * The Dummy backend *1, and who knows what ASIO really does :)
1574 * So just display the period size, that's also what
1575 * ARDOUR_UI::update_sample_rate() does for the status bar.
1576 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1577 * but still, that's the buffer period, not [round-trip] latency)
1580 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1581 buffer_size_duration_label.set_text (buf);
1585 EngineControl::midi_option_changed ()
1587 DEBUG_ECONTROL ("midi_option_changed");
1588 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1591 backend->set_midi_option (get_midi_option());
1593 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1595 //_midi_devices.clear(); // TODO merge with state-saved settings..
1596 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1597 std::vector<MidiDeviceSettings> new_devices;
1599 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1600 MidiDeviceSettings mds = find_midi_device (i->name);
1601 if (i->available && !mds) {
1602 uint32_t input_latency = 0;
1603 uint32_t output_latency = 0;
1604 if (_can_set_midi_latencies) {
1605 input_latency = backend->systemic_midi_input_latency (i->name);
1606 output_latency = backend->systemic_midi_output_latency (i->name);
1608 bool enabled = backend->midi_device_enabled (i->name);
1609 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1610 new_devices.push_back (ptr);
1611 } else if (i->available) {
1612 new_devices.push_back (mds);
1615 _midi_devices = new_devices;
1617 if (_midi_devices.empty()) {
1618 midi_devices_button.set_sensitive (false);
1620 midi_devices_button.set_sensitive (true);
1625 EngineControl::parameter_changed ()
1629 EngineControl::State
1630 EngineControl::get_matching_state (const string& backend)
1632 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1633 // TODO use LRU for every backend and prefer the active one
1634 // uniqueness is only guaranteed for backend + driver + device(s)
1635 if ((*i)->backend == backend) {
1642 EngineControl::State
1643 EngineControl::get_matching_state (
1644 const string& backend,
1645 const string& driver,
1646 const string& device)
1648 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1649 if ((*i)->backend == backend &&
1650 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1658 EngineControl::State
1659 EngineControl::get_matching_state (
1660 const string& backend,
1661 const string& driver,
1662 const string& input_device,
1663 const string& output_device)
1665 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1666 if ((*i)->backend == backend &&
1667 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1675 EngineControl::State
1676 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1678 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1681 if (backend->use_separate_input_and_output_devices ()) {
1682 return get_matching_state (backend_combo.get_active_text(),
1683 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1684 input_device_combo.get_active_text(),
1685 output_device_combo.get_active_text());
1687 return get_matching_state (backend_combo.get_active_text(),
1688 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1689 device_combo.get_active_text());
1693 return get_matching_state (backend_combo.get_active_text(),
1695 device_combo.get_active_text());
1698 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1699 const EngineControl::State& state2)
1701 if (state1->backend == state2->backend &&
1702 state1->driver == state2->driver &&
1703 state1->device == state2->device &&
1704 state1->input_device == state2->input_device &&
1705 state1->output_device == state2->output_device) {
1711 EngineControl::State
1712 EngineControl::save_state ()
1716 if (!_have_control) {
1717 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1721 state.reset(new StateStruct);
1722 state->backend = get_backend ();
1724 state.reset(new StateStruct);
1725 store_state (state);
1728 for (StateList::iterator i = states.begin(); i != states.end();) {
1729 if (equivalent_states (*i, state)) {
1730 i = states.erase(i);
1736 states.push_back (state);
1742 EngineControl::store_state (State state)
1744 state->backend = get_backend ();
1745 state->driver = get_driver ();
1746 state->device = get_device_name ();
1747 state->input_device = get_input_device_name ();
1748 state->output_device = get_output_device_name ();
1749 state->sample_rate = get_rate ();
1750 state->buffer_size = get_buffer_size ();
1751 state->input_latency = get_input_latency ();
1752 state->output_latency = get_output_latency ();
1753 state->input_channels = get_input_channels ();
1754 state->output_channels = get_output_channels ();
1755 state->midi_option = get_midi_option ();
1756 state->midi_devices = _midi_devices;
1760 EngineControl::maybe_display_saved_state ()
1762 if (!_have_control) {
1766 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1769 DEBUG_ECONTROL ("Restoring saved state");
1770 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1772 if (!_desired_sample_rate) {
1773 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1775 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1776 /* call this explicitly because we're ignoring changes to
1777 the controls at this point.
1779 show_buffer_duration ();
1780 input_latency.set_value (state->input_latency);
1781 output_latency.set_value (state->output_latency);
1783 if (!state->midi_option.empty()) {
1784 midi_option_combo.set_active_text (state->midi_option);
1785 _midi_devices = state->midi_devices;
1788 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1793 EngineControl::get_state ()
1795 LocaleGuard lg (X_("C"));
1797 XMLNode* root = new XMLNode ("AudioMIDISetup");
1800 if (!states.empty()) {
1801 XMLNode* state_nodes = new XMLNode ("EngineStates");
1803 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1805 XMLNode* node = new XMLNode ("State");
1807 node->add_property ("backend", (*i)->backend);
1808 node->add_property ("driver", (*i)->driver);
1809 node->add_property ("device", (*i)->device);
1810 node->add_property ("input-device", (*i)->input_device);
1811 node->add_property ("output-device", (*i)->output_device);
1812 node->add_property ("sample-rate", (*i)->sample_rate);
1813 node->add_property ("buffer-size", (*i)->buffer_size);
1814 node->add_property ("input-latency", (*i)->input_latency);
1815 node->add_property ("output-latency", (*i)->output_latency);
1816 node->add_property ("input-channels", (*i)->input_channels);
1817 node->add_property ("output-channels", (*i)->output_channels);
1818 node->add_property ("active", (*i)->active ? "yes" : "no");
1819 node->add_property ("midi-option", (*i)->midi_option);
1821 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1822 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1823 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1824 midi_device_stuff->add_property (X_("name"), (*p)->name);
1825 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1826 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1827 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1828 midi_devices->add_child_nocopy (*midi_device_stuff);
1830 node->add_child_nocopy (*midi_devices);
1832 state_nodes->add_child_nocopy (*node);
1835 root->add_child_nocopy (*state_nodes);
1842 EngineControl::set_default_state ()
1844 vector<string> backend_names;
1845 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1847 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1848 backend_names.push_back ((*b)->name);
1850 backend_combo.set_active_text (backend_names.front());
1852 // We could set default backends per platform etc here
1858 EngineControl::set_state (const XMLNode& root)
1860 XMLNodeList clist, cclist;
1861 XMLNodeConstIterator citer, cciter;
1863 XMLNode* grandchild;
1864 XMLProperty* prop = NULL;
1866 fprintf (stderr, "EngineControl::set_state\n");
1868 if (root.name() != "AudioMIDISetup") {
1872 clist = root.children();
1876 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1880 if (child->name() != "EngineStates") {
1884 cclist = child->children();
1886 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1887 State state (new StateStruct);
1889 grandchild = *cciter;
1891 if (grandchild->name() != "State") {
1895 if ((prop = grandchild->property ("backend")) == 0) {
1898 state->backend = prop->value ();
1900 if ((prop = grandchild->property ("driver")) == 0) {
1903 state->driver = prop->value ();
1905 if ((prop = grandchild->property ("device")) == 0) {
1908 state->device = prop->value ();
1910 if ((prop = grandchild->property ("input-device")) == 0) {
1913 state->input_device = prop->value ();
1915 if ((prop = grandchild->property ("output-device")) == 0) {
1918 state->output_device = prop->value ();
1920 if ((prop = grandchild->property ("sample-rate")) == 0) {
1923 state->sample_rate = atof (prop->value ());
1925 if ((prop = grandchild->property ("buffer-size")) == 0) {
1928 state->buffer_size = atoi (prop->value ());
1930 if ((prop = grandchild->property ("input-latency")) == 0) {
1933 state->input_latency = atoi (prop->value ());
1935 if ((prop = grandchild->property ("output-latency")) == 0) {
1938 state->output_latency = atoi (prop->value ());
1940 if ((prop = grandchild->property ("input-channels")) == 0) {
1943 state->input_channels = atoi (prop->value ());
1945 if ((prop = grandchild->property ("output-channels")) == 0) {
1948 state->output_channels = atoi (prop->value ());
1950 if ((prop = grandchild->property ("active")) == 0) {
1953 state->active = string_is_affirmative (prop->value ());
1955 if ((prop = grandchild->property ("midi-option")) == 0) {
1958 state->midi_option = prop->value ();
1960 state->midi_devices.clear();
1962 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1963 const XMLNodeList mnc = midinode->children();
1964 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1965 if ((*n)->property (X_("name")) == 0
1966 || (*n)->property (X_("enabled")) == 0
1967 || (*n)->property (X_("input-latency")) == 0
1968 || (*n)->property (X_("output-latency")) == 0
1973 MidiDeviceSettings ptr (new MidiDeviceSetting(
1974 (*n)->property (X_("name"))->value (),
1975 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1976 atoi ((*n)->property (X_("input-latency"))->value ()),
1977 atoi ((*n)->property (X_("output-latency"))->value ())
1979 state->midi_devices.push_back (ptr);
1984 /* remove accumulated duplicates (due to bug in ealier version)
1985 * this can be removed again before release
1987 for (StateList::iterator i = states.begin(); i != states.end();) {
1988 if ((*i)->backend == state->backend &&
1989 (*i)->driver == state->driver &&
1990 (*i)->device == state->device) {
1991 i = states.erase(i);
1998 states.push_back (state);
2002 /* now see if there was an active state and switch the setup to it */
2004 // purge states of backend that are not available in this built
2005 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2006 vector<std::string> backend_names;
2008 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2009 backend_names.push_back((*i)->name);
2011 for (StateList::iterator i = states.begin(); i != states.end();) {
2012 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2013 i = states.erase(i);
2019 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2022 return set_current_state (*i);
2029 EngineControl::set_current_state (const State& state)
2031 DEBUG_ECONTROL ("set_current_state");
2033 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2035 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2036 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2037 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2038 // this shouldn't happen as the invalid backend names should have been
2039 // removed from the list of states.
2043 // now reflect the change in the backend in the GUI so backend_changed will
2044 // do the right thing
2045 backend_combo.set_active_text (state->backend);
2047 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2049 // we don't have control don't restore state
2054 if (!state->driver.empty ()) {
2055 if (!backend->requires_driver_selection ()) {
2056 DEBUG_ECONTROL ("Backend should require driver selection");
2057 // A backend has changed from having driver selection to not having
2058 // it or someone has been manually editing a config file and messed
2063 if (backend->set_driver (state->driver) != 0) {
2064 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2065 // Driver names for a backend have changed and the name in the
2066 // config file is now invalid or support for driver is no longer
2067 // included in the backend
2070 // no need to set the driver_combo as backend_changed will use
2071 // backend->driver_name to set the active driver
2074 if (!state->device.empty ()) {
2075 if (backend->set_device_name (state->device) != 0) {
2077 string_compose ("Unable to set device name %1", state->device));
2078 // device is no longer available on the system
2081 // no need to set active device as it will be picked up in
2082 // via backend_changed ()/set_device_popdown_strings
2085 // backend supports separate input/output devices
2086 if (backend->set_input_device_name (state->input_device) != 0) {
2087 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2088 state->input_device));
2089 // input device is no longer available on the system
2093 if (backend->set_output_device_name (state->output_device) != 0) {
2094 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2095 state->input_device));
2096 // output device is no longer available on the system
2099 // no need to set active devices as it will be picked up in via
2100 // backend_changed ()/set_*_device_popdown_strings
2105 // Now restore the state of the rest of the controls
2107 // We don't use a SignalBlocker as set_current_state is currently only
2108 // called from set_state before any signals are connected. If at some point
2109 // a more general named state mechanism is implemented and
2110 // set_current_state is called while signals are connected then a
2111 // SignalBlocker will need to be instantiated before setting these.
2113 device_combo.set_active_text (state->device);
2114 input_device_combo.set_active_text (state->input_device);
2115 output_device_combo.set_active_text (state->output_device);
2116 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2117 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2118 input_latency.set_value (state->input_latency);
2119 output_latency.set_value (state->output_latency);
2120 midi_option_combo.set_active_text (state->midi_option);
2125 EngineControl::push_state_to_backend (bool start)
2127 DEBUG_ECONTROL ("push_state_to_backend");
2128 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2134 /* figure out what is going to change */
2136 bool restart_required = false;
2137 bool was_running = ARDOUR::AudioEngine::instance()->running();
2138 bool change_driver = false;
2139 bool change_device = false;
2140 bool change_rate = false;
2141 bool change_bufsize = false;
2142 bool change_latency = false;
2143 bool change_channels = false;
2144 bool change_midi = false;
2146 uint32_t ochan = get_output_channels ();
2147 uint32_t ichan = get_input_channels ();
2149 if (_have_control) {
2151 if (started_at_least_once) {
2153 /* we can control the backend */
2155 if (backend->requires_driver_selection()) {
2156 if (get_driver() != backend->driver_name()) {
2157 change_driver = true;
2161 if (backend->use_separate_input_and_output_devices()) {
2162 if (get_input_device_name() != backend->input_device_name()) {
2163 change_device = true;
2165 if (get_output_device_name() != backend->output_device_name()) {
2166 change_device = true;
2169 if (get_device_name() != backend->device_name()) {
2170 change_device = true;
2174 if (queue_device_changed) {
2175 change_device = true;
2178 if (get_rate() != backend->sample_rate()) {
2182 if (get_buffer_size() != backend->buffer_size()) {
2183 change_bufsize = true;
2186 if (get_midi_option() != backend->midi_option()) {
2190 /* zero-requested channels means "all available" */
2193 ichan = backend->input_channels();
2197 ochan = backend->output_channels();
2200 if (ichan != backend->input_channels()) {
2201 change_channels = true;
2204 if (ochan != backend->output_channels()) {
2205 change_channels = true;
2208 if (get_input_latency() != backend->systemic_input_latency() ||
2209 get_output_latency() != backend->systemic_output_latency()) {
2210 change_latency = true;
2213 /* backend never started, so we have to force a group
2216 change_device = true;
2217 if (backend->requires_driver_selection()) {
2218 change_driver = true;
2221 change_bufsize = true;
2222 change_channels = true;
2223 change_latency = true;
2229 /* we have no control over the backend, meaning that we can
2230 * only possibly change sample rate and buffer size.
2234 if (get_rate() != backend->sample_rate()) {
2235 change_bufsize = true;
2238 if (get_buffer_size() != backend->buffer_size()) {
2239 change_bufsize = true;
2243 queue_device_changed = false;
2245 if (!_have_control) {
2247 /* We do not have control over the backend, so the best we can
2248 * do is try to change the sample rate and/or bufsize and get
2252 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2256 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2261 backend->set_sample_rate (get_rate());
2264 if (change_bufsize) {
2265 backend->set_buffer_size (get_buffer_size());
2269 if (ARDOUR::AudioEngine::instance()->start ()) {
2270 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2280 /* determine if we need to stop the backend before changing parameters */
2282 if (change_driver || change_device || change_channels || change_latency ||
2283 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2285 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2286 restart_required = true;
2288 restart_required = false;
2293 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2294 /* no changes in any parameters that absolutely require a
2295 * restart, so check those that might be changeable without a
2299 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2300 /* can't do this while running ... */
2301 restart_required = true;
2304 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2305 /* can't do this while running ... */
2306 restart_required = true;
2312 if (restart_required) {
2313 if (ARDOUR::AudioEngine::instance()->stop()) {
2319 if (change_driver && backend->set_driver (get_driver())) {
2320 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2323 if (backend->use_separate_input_and_output_devices()) {
2324 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2325 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2328 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2329 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2333 if (change_device && backend->set_device_name (get_device_name())) {
2334 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2338 if (change_rate && backend->set_sample_rate (get_rate())) {
2339 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2342 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2343 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2347 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2348 if (backend->set_input_channels (get_input_channels())) {
2349 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2352 if (backend->set_output_channels (get_output_channels())) {
2353 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2357 if (change_latency) {
2358 if (backend->set_systemic_input_latency (get_input_latency())) {
2359 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2362 if (backend->set_systemic_output_latency (get_output_latency())) {
2363 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2369 backend->set_midi_option (get_midi_option());
2373 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2374 if (_measure_midi) {
2375 if (*p == _measure_midi) {
2376 backend->set_midi_device_enabled ((*p)->name, true);
2378 backend->set_midi_device_enabled ((*p)->name, false);
2382 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2383 if (backend->can_set_systemic_midi_latencies()) {
2384 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2385 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2390 if (start || (was_running && restart_required)) {
2391 if (ARDOUR::AudioEngine::instance()->start()) {
2402 EngineControl::post_push ()
2404 /* get a pointer to the current state object, creating one if
2408 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2411 state = save_state ();
2419 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2420 (*i)->active = false;
2423 /* mark this one active (to be used next time the dialog is
2427 state->active = true;
2429 if (_have_control) { // XXX
2430 manage_control_app_sensitivity ();
2433 /* schedule a redisplay of MIDI ports */
2434 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2439 EngineControl::get_rate () const
2441 float r = atof (sample_rate_combo.get_active_text ());
2442 /* the string may have been translated with an abbreviation for
2443 * thousands, so use a crude heuristic to fix this.
2453 EngineControl::get_buffer_size () const
2455 string txt = buffer_size_combo.get_active_text ();
2458 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2459 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2460 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2468 EngineControl::get_midi_option () const
2470 return midi_option_combo.get_active_text();
2474 EngineControl::get_input_channels() const
2476 if (ARDOUR::Profile->get_mixbus()) {
2477 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2478 if (!backend) return 0;
2479 return backend->input_channels();
2481 return (uint32_t) input_channels_adjustment.get_value();
2485 EngineControl::get_output_channels() const
2487 if (ARDOUR::Profile->get_mixbus()) {
2488 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2489 if (!backend) return 0;
2490 return backend->input_channels();
2492 return (uint32_t) output_channels_adjustment.get_value();
2496 EngineControl::get_input_latency() const
2498 return (uint32_t) input_latency_adjustment.get_value();
2502 EngineControl::get_output_latency() const
2504 return (uint32_t) output_latency_adjustment.get_value();
2508 EngineControl::get_backend () const
2510 return backend_combo.get_active_text ();
2514 EngineControl::get_driver () const
2516 if (driver_combo.get_parent()) {
2517 return driver_combo.get_active_text ();
2524 EngineControl::get_device_name () const
2526 return device_combo.get_active_text ();
2530 EngineControl::get_input_device_name () const
2532 return input_device_combo.get_active_text ();
2536 EngineControl::get_output_device_name () const
2538 return output_device_combo.get_active_text ();
2542 EngineControl::control_app_button_clicked ()
2544 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2550 backend->launch_control_app ();
2554 EngineControl::start_stop_button_clicked ()
2556 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2562 if (ARDOUR::AudioEngine::instance()->running()) {
2563 ARDOUR::AudioEngine::instance()->stop ();
2570 EngineControl::update_devices_button_clicked ()
2572 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2578 if (backend->update_devices()) {
2579 device_list_changed ();
2584 EngineControl::manage_control_app_sensitivity ()
2586 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2592 string appname = backend->control_app_name();
2594 if (appname.empty()) {
2595 control_app_button.set_sensitive (false);
2597 control_app_button.set_sensitive (true);
2602 EngineControl::set_desired_sample_rate (uint32_t sr)
2604 _desired_sample_rate = sr;
2609 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2611 if (page_num == 0) {
2612 cancel_button->set_sensitive (true);
2613 _measure_midi.reset();
2614 update_sensitivity ();
2616 cancel_button->set_sensitive (false);
2617 ok_button->set_sensitive (false);
2620 if (page_num == midi_tab) {
2622 refresh_midi_display ();
2625 if (page_num == latency_tab) {
2628 if (ARDOUR::AudioEngine::instance()->running()) {
2629 // TODO - mark as 'stopped for latency
2634 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2636 /* save any existing latency values */
2638 uint32_t il = (uint32_t) input_latency.get_value ();
2639 uint32_t ol = (uint32_t) input_latency.get_value ();
2641 /* reset to zero so that our new test instance
2642 will be clean of any existing latency measures.
2644 NB. this should really be done by the backend
2645 when stated for latency measurement.
2648 input_latency.set_value (0);
2649 output_latency.set_value (0);
2651 push_state_to_backend (false);
2655 input_latency.set_value (il);
2656 output_latency.set_value (ol);
2659 // This should be done in push_state_to_backend()
2660 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2661 disable_latency_tab ();
2664 enable_latency_tab ();
2668 end_latency_detection ();
2669 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2674 /* latency measurement */
2677 EngineControl::check_audio_latency_measurement ()
2679 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2681 if (mtdm->resolve () < 0) {
2682 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2686 if (mtdm->err () > 0.3) {
2692 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2694 if (sample_rate == 0) {
2695 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2696 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2700 int frames_total = mtdm->del();
2701 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2703 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2704 _("Detected roundtrip latency: "),
2705 frames_total, frames_total * 1000.0f/sample_rate,
2706 _("Systemic latency: "),
2707 extra, extra * 1000.0f/sample_rate);
2711 if (mtdm->err () > 0.2) {
2713 strcat (buf, _("(signal detection error)"));
2719 strcat (buf, _("(inverted - bad wiring)"));
2723 lm_results.set_markup (string_compose (results_markup, buf));
2726 have_lm_results = true;
2727 end_latency_detection ();
2728 lm_use_button.set_sensitive (true);
2736 EngineControl::check_midi_latency_measurement ()
2738 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2740 if (!mididm->have_signal () || mididm->latency () == 0) {
2741 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2746 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2748 if (sample_rate == 0) {
2749 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2750 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2754 ARDOUR::framecnt_t frames_total = mididm->latency();
2755 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2756 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2757 _("Detected roundtrip latency: "),
2758 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2759 _("Systemic latency: "),
2760 extra, extra * 1000.0f / sample_rate);
2764 if (!mididm->ok ()) {
2766 strcat (buf, _("(averaging)"));
2770 if (mididm->deviation () > 50.0) {
2772 strcat (buf, _("(too large jitter)"));
2774 } else if (mididm->deviation () > 10.0) {
2776 strcat (buf, _("(large jitter)"));
2780 have_lm_results = true;
2781 end_latency_detection ();
2782 lm_use_button.set_sensitive (true);
2783 lm_results.set_markup (string_compose (results_markup, buf));
2785 } else if (mididm->processed () > 400) {
2786 have_lm_results = false;
2787 end_latency_detection ();
2788 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2792 lm_results.set_markup (string_compose (results_markup, buf));
2798 EngineControl::start_latency_detection ()
2800 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2801 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2803 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2804 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2805 if (_measure_midi) {
2806 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2808 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2810 lm_measure_label.set_text (_("Cancel"));
2811 have_lm_results = false;
2812 lm_use_button.set_sensitive (false);
2813 lm_input_channel_combo.set_sensitive (false);
2814 lm_output_channel_combo.set_sensitive (false);
2820 EngineControl::end_latency_detection ()
2822 latency_timeout.disconnect ();
2823 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2824 lm_measure_label.set_text (_("Measure"));
2825 if (!have_lm_results) {
2826 lm_use_button.set_sensitive (false);
2828 lm_input_channel_combo.set_sensitive (true);
2829 lm_output_channel_combo.set_sensitive (true);
2834 EngineControl::latency_button_clicked ()
2837 start_latency_detection ();
2839 end_latency_detection ();
2844 EngineControl::latency_back_button_clicked ()
2846 ARDOUR::AudioEngine::instance()->stop(true);
2847 notebook.set_current_page(0);
2851 EngineControl::use_latency_button_clicked ()
2853 if (_measure_midi) {
2854 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2858 ARDOUR::framecnt_t frames_total = mididm->latency();
2859 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2860 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2861 _measure_midi->input_latency = one_way;
2862 _measure_midi->output_latency = one_way;
2863 notebook.set_current_page (midi_tab);
2865 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2871 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2872 one_way = std::max (0., one_way);
2874 input_latency_adjustment.set_value (one_way);
2875 output_latency_adjustment.set_value (one_way);
2877 /* back to settings page */
2878 notebook.set_current_page (0);
2883 EngineControl::on_delete_event (GdkEventAny* ev)
2885 if (notebook.get_current_page() == 2) {
2886 /* currently on latency tab - be sure to clean up */
2887 end_latency_detection ();
2889 return ArdourDialog::on_delete_event (ev);
2893 EngineControl::engine_running ()
2895 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2898 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2899 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2901 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2902 connect_disconnect_button.show();
2904 started_at_least_once = true;
2905 if (_have_control) {
2906 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2908 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2910 update_sensitivity();
2914 EngineControl::engine_stopped ()
2916 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2919 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2920 connect_disconnect_button.show();
2922 if (_have_control) {
2923 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2925 engine_status.set_markup(X_(""));
2928 update_sensitivity();
2932 EngineControl::device_list_changed ()
2934 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2936 midi_option_changed();
2940 EngineControl::connect_disconnect_click()
2942 if (ARDOUR::AudioEngine::instance()->running()) {
2950 EngineControl::calibrate_audio_latency ()
2952 _measure_midi.reset ();
2953 have_lm_results = false;
2954 lm_use_button.set_sensitive (false);
2955 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2956 notebook.set_current_page (latency_tab);
2960 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2963 have_lm_results = false;
2964 lm_use_button.set_sensitive (false);
2965 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2966 notebook.set_current_page (latency_tab);
2970 EngineControl::configure_midi_devices ()
2972 notebook.set_current_page (midi_tab);