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 (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
191 lm_use_button.set_sensitive (false);
193 /* Increase the default spacing around the labels of these three
199 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
200 l->set_padding (10, 10);
203 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
204 l->set_padding (10, 10);
207 preamble = manage (new Label);
208 preamble->set_width_chars (60);
209 preamble->set_line_wrap (true);
210 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
211 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
214 preamble = manage (new Label);
215 preamble->set_width_chars (60);
216 preamble->set_line_wrap (true);
217 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
218 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220 ++row; // skip a row in the table
221 ++row; // skip a row in the table
223 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 ++row; // skip a row in the table
226 ++row; // skip a row in the table
228 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
234 lm_vbox.set_border_width (12);
235 lm_vbox.pack_start (lm_table, false, false);
237 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
241 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
242 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
243 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
244 notebook.set_border_width (12);
246 notebook.set_show_tabs (false);
247 notebook.show_all ();
249 notebook.set_name ("SettingsNotebook");
251 /* packup the notebook */
253 get_vbox()->set_border_width (12);
254 get_vbox()->pack_start (notebook);
256 /* need a special function to print "all available channels" when the
257 * channel counts hit zero.
260 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
261 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
263 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
264 midi_devices_button.set_sensitive (false);
265 midi_devices_button.set_name ("generic button");
266 midi_devices_button.set_can_focus(true);
268 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
269 control_app_button.set_name ("generic button");
270 control_app_button.set_can_focus(true);
271 manage_control_app_sensitivity ();
273 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
274 start_stop_button.set_sensitive (false);
275 start_stop_button.set_name ("generic button");
276 start_stop_button.set_can_focus(true);
278 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
279 update_devices_button.set_sensitive (false);
280 update_devices_button.set_name ("generic button");
281 update_devices_button.set_can_focus(true);
283 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
284 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
286 /* Pick up any existing audio setup configuration, if appropriate */
288 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
290 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
291 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
292 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
293 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
296 if (!set_state (*audio_setup)) {
297 set_default_state ();
300 set_default_state ();
303 connect_changed_signals ();
305 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
307 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
308 connect_disconnect_button.set_no_show_all();
313 EngineControl::connect_changed_signals ()
315 backend_combo_connection = backend_combo.signal_changed ().connect (
316 sigc::mem_fun (*this, &EngineControl::backend_changed));
317 driver_combo_connection = driver_combo.signal_changed ().connect (
318 sigc::mem_fun (*this, &EngineControl::driver_changed));
319 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
320 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
321 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
322 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
323 device_combo_connection = device_combo.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::device_changed));
325 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
328 input_device_combo_connection = input_device_combo.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::input_device_changed));
330 output_device_combo_connection = output_device_combo.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::output_device_changed));
333 input_latency_connection = input_latency.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::parameter_changed));
335 output_latency_connection = output_latency.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::parameter_changed));
337 input_channels_connection = input_channels.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::parameter_changed));
339 output_channels_connection = output_channels.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::parameter_changed));
344 EngineControl::block_changed_signals ()
346 if (block_signals++ == 0) {
347 DEBUG_ECONTROL ("Blocking changed signals");
348 backend_combo_connection.block ();
349 driver_combo_connection.block ();
350 sample_rate_combo_connection.block ();
351 buffer_size_combo_connection.block ();
352 device_combo_connection.block ();
353 input_device_combo_connection.block ();
354 output_device_combo_connection.block ();
355 midi_option_combo_connection.block ();
356 input_latency_connection.block ();
357 output_latency_connection.block ();
358 input_channels_connection.block ();
359 output_channels_connection.block ();
364 EngineControl::unblock_changed_signals ()
366 if (--block_signals == 0) {
367 DEBUG_ECONTROL ("Unblocking changed signals");
368 backend_combo_connection.unblock ();
369 driver_combo_connection.unblock ();
370 sample_rate_combo_connection.unblock ();
371 buffer_size_combo_connection.unblock ();
372 device_combo_connection.unblock ();
373 input_device_combo_connection.unblock ();
374 output_device_combo_connection.unblock ();
375 midi_option_combo_connection.unblock ();
376 input_latency_connection.unblock ();
377 output_latency_connection.unblock ();
378 input_channels_connection.unblock ();
379 output_channels_connection.unblock ();
383 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
384 const std::string& reason)
385 : ec (engine_control)
388 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
389 ec.block_changed_signals ();
392 EngineControl::SignalBlocker::~SignalBlocker ()
394 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
395 ec.unblock_changed_signals ();
399 EngineControl::on_show ()
401 ArdourDialog::on_show ();
402 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
403 // re-check _have_control (jackd running) see #6041
407 ok_button->grab_focus();
411 EngineControl::start_engine ()
413 if (push_state_to_backend(true) != 0) {
414 MessageDialog msg(*this,
415 ARDOUR::AudioEngine::instance()->get_last_backend_error());
423 EngineControl::stop_engine ()
425 if (ARDOUR::AudioEngine::instance()->stop()) {
426 MessageDialog msg(*this,
427 ARDOUR::AudioEngine::instance()->get_last_backend_error());
435 EngineControl::on_response (int response_id)
437 ArdourDialog::on_response (response_id);
439 switch (response_id) {
441 if (!start_engine()) {
446 #ifdef PLATFORM_WINDOWS
448 // But if there's no session open, this can produce
449 // a long gap when nothing appears to be happening.
450 // Let's show the splash image while we're waiting.
451 if (!ARDOUR_COMMAND_LINE::no_splash) {
452 if (ARDOUR_UI::instance()) {
453 if (!ARDOUR_UI::instance()->session_loaded) {
454 ARDOUR_UI::instance()->show_splash();
460 case RESPONSE_DELETE_EVENT: {
462 ev.type = GDK_BUTTON_PRESS;
464 on_delete_event((GdkEventAny*)&ev);
467 case RESPONSE_CANCEL:
468 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
469 ARDOUR_UI::instance()->check_audioengine(*this);
478 EngineControl::build_notebook ()
481 AttachOptions xopt = AttachOptions (FILL|EXPAND);
483 /* clear the table */
485 Gtkmm2ext::container_clear (basic_vbox);
486 Gtkmm2ext::container_clear (basic_packer);
488 if (control_app_button.get_parent()) {
489 control_app_button.get_parent()->remove (control_app_button);
492 label = manage (left_aligned_label (_("Audio System:")));
493 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
494 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
496 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
497 engine_status.show();
499 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
500 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
502 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
503 lm_button_audio.set_name ("generic button");
504 lm_button_audio.set_can_focus(true);
507 build_full_control_notebook ();
509 build_no_control_notebook ();
512 basic_vbox.pack_start (basic_hbox, false, false);
515 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
516 basic_vbox.show_all ();
521 EngineControl::build_full_control_notebook ()
523 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
526 using namespace Notebook_Helpers;
528 vector<string> strings;
529 AttachOptions xopt = AttachOptions (FILL|EXPAND);
530 int row = 1; // row zero == backend combo
532 /* start packing it up */
534 if (backend->requires_driver_selection()) {
535 label = manage (left_aligned_label (_("Driver:")));
536 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
537 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
541 if (backend->use_separate_input_and_output_devices()) {
542 label = manage (left_aligned_label (_("Input Device:")));
543 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
544 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
546 label = manage (left_aligned_label (_("Output Device:")));
547 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
548 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
550 // reset so it isn't used in state comparisons
551 device_combo.set_active_text ("");
553 label = manage (left_aligned_label (_("Device:")));
554 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
555 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
557 // reset these so they don't get used in state comparisons
558 input_device_combo.set_active_text ("");
559 output_device_combo.set_active_text ("");
562 label = manage (left_aligned_label (_("Sample rate:")));
563 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
564 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
568 label = manage (left_aligned_label (_("Buffer size:")));
569 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
570 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
571 buffer_size_duration_label.set_alignment (0.0); /* left-align */
572 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
574 /* button spans 2 rows */
576 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
579 input_channels.set_name ("InputChannels");
580 input_channels.set_flags (Gtk::CAN_FOCUS);
581 input_channels.set_digits (0);
582 input_channels.set_wrap (false);
583 output_channels.set_editable (true);
585 if (!ARDOUR::Profile->get_mixbus()) {
586 label = manage (left_aligned_label (_("Input Channels:")));
587 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
588 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
592 output_channels.set_name ("OutputChannels");
593 output_channels.set_flags (Gtk::CAN_FOCUS);
594 output_channels.set_digits (0);
595 output_channels.set_wrap (false);
596 output_channels.set_editable (true);
598 if (!ARDOUR::Profile->get_mixbus()) {
599 label = manage (left_aligned_label (_("Output Channels:")));
600 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
601 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
605 input_latency.set_name ("InputLatency");
606 input_latency.set_flags (Gtk::CAN_FOCUS);
607 input_latency.set_digits (0);
608 input_latency.set_wrap (false);
609 input_latency.set_editable (true);
611 label = manage (left_aligned_label (_("Hardware input latency:")));
612 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
613 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
614 label = manage (left_aligned_label (_("samples")));
615 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
618 output_latency.set_name ("OutputLatency");
619 output_latency.set_flags (Gtk::CAN_FOCUS);
620 output_latency.set_digits (0);
621 output_latency.set_wrap (false);
622 output_latency.set_editable (true);
624 label = manage (left_aligned_label (_("Hardware output latency:")));
625 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
626 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
627 label = manage (left_aligned_label (_("samples")));
628 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
630 /* button spans 2 rows */
632 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
635 label = manage (left_aligned_label (_("MIDI System:")));
636 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
637 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
638 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
639 /* Currently the only backend with dedicated Midi setup is ALSA.
640 * lot of people complain that this is greyed out
641 * "I can't use MIDI, the setup is greyed out"
643 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
649 EngineControl::build_no_control_notebook ()
651 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
654 using namespace Notebook_Helpers;
656 vector<string> strings;
657 AttachOptions xopt = AttachOptions (FILL|EXPAND);
658 int row = 1; // row zero == backend combo
659 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
661 label = manage (new Label);
662 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
663 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
666 if (backend->can_change_sample_rate_when_running()) {
667 label = manage (left_aligned_label (_("Sample rate:")));
668 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
669 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
673 if (backend->can_change_buffer_size_when_running()) {
674 label = manage (left_aligned_label (_("Buffer size:")));
675 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
676 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
677 buffer_size_duration_label.set_alignment (0.0); /* left-align */
678 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
682 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
686 EngineControl::~EngineControl ()
688 ignore_changes = true;
692 EngineControl::disable_latency_tab ()
694 vector<string> empty;
695 set_popdown_strings (lm_output_channel_combo, empty);
696 set_popdown_strings (lm_input_channel_combo, empty);
697 lm_measure_button.set_sensitive (false);
698 lm_use_button.set_sensitive (false);
702 EngineControl::enable_latency_tab ()
704 vector<string> outputs;
705 vector<string> inputs;
707 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
708 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
709 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
711 if (!ARDOUR::AudioEngine::instance()->running()) {
712 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
713 notebook.set_current_page (0);
717 else if (inputs.empty() || outputs.empty()) {
718 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
719 notebook.set_current_page (0);
724 lm_back_button_signal.disconnect();
726 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
729 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
733 set_popdown_strings (lm_output_channel_combo, outputs);
734 lm_output_channel_combo.set_active_text (outputs.front());
735 lm_output_channel_combo.set_sensitive (true);
737 set_popdown_strings (lm_input_channel_combo, inputs);
738 lm_input_channel_combo.set_active_text (inputs.front());
739 lm_input_channel_combo.set_sensitive (true);
741 lm_measure_button.set_sensitive (true);
745 EngineControl::setup_midi_tab_for_backend ()
747 string backend = backend_combo.get_active_text ();
749 Gtkmm2ext::container_clear (midi_vbox);
751 midi_vbox.set_border_width (12);
752 midi_device_table.set_border_width (12);
754 if (backend == "JACK") {
755 setup_midi_tab_for_jack ();
758 midi_vbox.pack_start (midi_device_table, true, true);
759 midi_vbox.pack_start (midi_back_button, false, false);
760 midi_vbox.show_all ();
764 EngineControl::update_sensitivity ()
766 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
768 ok_button->set_sensitive (false);
769 start_stop_button.set_sensitive (false);
774 size_t devices_available = 0;
776 if (backend->use_separate_input_and_output_devices ()) {
777 devices_available += get_popdown_string_count (input_device_combo);
778 devices_available += get_popdown_string_count (output_device_combo);
780 devices_available += get_popdown_string_count (device_combo);
783 if (devices_available == 0) {
785 input_latency.set_sensitive (false);
786 output_latency.set_sensitive (false);
787 input_channels.set_sensitive (false);
788 output_channels.set_sensitive (false);
790 input_latency.set_sensitive (true);
791 output_latency.set_sensitive (true);
792 input_channels.set_sensitive (true);
793 output_channels.set_sensitive (true);
796 if (get_popdown_string_count (buffer_size_combo) > 0) {
797 if (!ARDOUR::AudioEngine::instance()->running()) {
798 buffer_size_combo.set_sensitive (valid);
799 } else if (backend->can_change_sample_rate_when_running()) {
800 buffer_size_combo.set_sensitive (valid || !_have_control);
804 * Currently there is no way to manually stop the
805 * engine in order to re-configure it.
806 * This needs to remain sensitive for now.
808 * (it's also handy to implicily
809 * re-start the engine)
811 buffer_size_combo.set_sensitive (true);
813 buffer_size_combo.set_sensitive (false);
817 buffer_size_combo.set_sensitive (false);
821 if (get_popdown_string_count (sample_rate_combo) > 0) {
822 if (!ARDOUR::AudioEngine::instance()->running()) {
823 sample_rate_combo.set_sensitive (true);
825 sample_rate_combo.set_sensitive (false);
828 sample_rate_combo.set_sensitive (false);
833 start_stop_button.set_sensitive(true);
834 start_stop_button.show();
835 if (ARDOUR::AudioEngine::instance()->running()) {
836 start_stop_button.set_text("Stop");
837 update_devices_button.set_sensitive(false);
839 if (backend->can_request_update_devices()) {
840 update_devices_button.show();
842 update_devices_button.hide();
844 start_stop_button.set_text("Start");
845 update_devices_button.set_sensitive(true);
848 update_devices_button.set_sensitive(false);
849 update_devices_button.hide();
850 start_stop_button.set_sensitive(false);
851 start_stop_button.hide();
854 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
855 input_device_combo.set_sensitive (false);
856 output_device_combo.set_sensitive (false);
857 device_combo.set_sensitive (false);
858 driver_combo.set_sensitive (false);
860 input_device_combo.set_sensitive (true);
861 output_device_combo.set_sensitive (true);
862 device_combo.set_sensitive (true);
863 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
864 driver_combo.set_sensitive (true);
866 driver_combo.set_sensitive (false);
870 if (valid || !_have_control) {
871 ok_button->set_sensitive (true);
873 ok_button->set_sensitive (false);
878 EngineControl::setup_midi_tab_for_jack ()
883 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
885 device->input_latency = a->get_value();
887 device->output_latency = a->get_value();
892 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
893 b->set_active (!b->get_active());
894 device->enabled = b->get_active();
895 refresh_midi_display(device->name);
899 EngineControl::refresh_midi_display (std::string focus)
901 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
905 AttachOptions xopt = AttachOptions (FILL|EXPAND);
908 Gtkmm2ext::container_clear (midi_device_table);
910 midi_device_table.set_spacings (6);
912 l = manage (new Label);
913 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
914 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
915 l->set_alignment (0.5, 0.5);
919 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
920 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
921 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
922 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
924 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
925 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
926 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
927 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
930 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
935 bool enabled = (*p)->enabled;
937 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
938 m->set_name ("midi device");
939 m->set_can_focus (Gtk::CAN_FOCUS);
940 m->add_events (Gdk::BUTTON_RELEASE_MASK);
941 m->set_active (enabled);
942 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
943 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
944 if ((*p)->name == focus) {
948 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
949 s = manage (new Gtk::SpinButton (*a));
950 a->set_value ((*p)->input_latency);
951 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
952 s->set_sensitive (_can_set_midi_latencies && enabled);
953 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
955 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
956 s = manage (new Gtk::SpinButton (*a));
957 a->set_value ((*p)->output_latency);
958 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
959 s->set_sensitive (_can_set_midi_latencies && enabled);
960 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
962 b = manage (new Button (_("Calibrate")));
963 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
964 b->set_sensitive (_can_set_midi_latencies && enabled);
965 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
972 EngineControl::backend_changed ()
974 SignalBlocker blocker (*this, "backend_changed");
975 string backend_name = backend_combo.get_active_text();
976 boost::shared_ptr<ARDOUR::AudioBackend> backend;
978 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
979 /* eh? setting the backend failed... how ? */
980 /* A: stale config contains a backend that does not exist in current build */
984 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
986 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
989 setup_midi_tab_for_backend ();
990 _midi_devices.clear();
992 if (backend->requires_driver_selection()) {
993 if (set_driver_popdown_strings ()) {
997 /* this will change the device text which will cause a call to
998 * device changed which will set up parameters
1003 update_midi_options ();
1005 connect_disconnect_button.hide();
1007 midi_option_changed();
1009 started_at_least_once = false;
1011 /* changing the backend implies stopping the engine
1012 * ARDOUR::AudioEngine() may or may not emit this signal
1013 * depending on previous engine state
1015 engine_stopped (); // set "active/inactive"
1017 if (!ignore_changes) {
1018 maybe_display_saved_state ();
1023 EngineControl::update_midi_options ()
1025 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1026 vector<string> midi_options = backend->enumerate_midi_options();
1028 if (midi_options.size() == 1) {
1029 /* only contains the "none" option */
1030 midi_option_combo.set_sensitive (false);
1032 if (_have_control) {
1033 set_popdown_strings (midi_option_combo, midi_options);
1034 midi_option_combo.set_active_text (midi_options.front());
1035 midi_option_combo.set_sensitive (true);
1037 midi_option_combo.set_sensitive (false);
1043 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1045 if (ARDOUR::Profile->get_mixbus()) {
1049 uint32_t cnt = (uint32_t) sb->get_value();
1051 sb->set_text (_("all available channels"));
1054 snprintf (buf, sizeof (buf), "%d", cnt);
1060 // @return true if there are drivers available
1062 EngineControl::set_driver_popdown_strings ()
1064 DEBUG_ECONTROL ("set_driver_popdown_strings");
1065 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1066 vector<string> drivers = backend->enumerate_drivers();
1068 if (drivers.empty ()) {
1069 // This is an error...?
1073 string current_driver = backend->driver_name ();
1075 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1077 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1080 current_driver = drivers.front ();
1083 set_popdown_strings (driver_combo, drivers);
1085 string_compose ("driver_combo.set_active_text: %1", current_driver));
1086 driver_combo.set_active_text (current_driver);
1091 EngineControl::get_default_device(const string& current_device_name,
1092 const vector<string>& available_devices)
1094 // If the current device is available, use it as default
1095 if (std::find (available_devices.begin (),
1096 available_devices.end (),
1097 current_device_name) != available_devices.end ()) {
1099 return current_device_name;
1102 using namespace ARDOUR;
1104 string default_device_name =
1105 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1107 vector<string>::const_iterator i;
1109 // If there is a "Default" device available, use it
1110 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1111 if (*i == default_device_name) {
1116 string none_device_name =
1117 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1119 // Use the first device that isn't "None"
1120 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1121 if (*i != none_device_name) {
1126 // Use "None" if there are no other available
1127 return available_devices.front();
1130 // @return true if there are devices available
1132 EngineControl::set_device_popdown_strings ()
1134 DEBUG_ECONTROL ("set_device_popdown_strings");
1135 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1136 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1138 /* NOTE: Ardour currently does not display the "available" field of the
1141 * Doing so would require a different GUI widget than the combo
1142 * box/popdown that we currently use, since it has no way to list
1143 * items that are not selectable. Something more like a popup menu,
1144 * which could have unselectable items, would be appropriate.
1147 vector<string> available_devices;
1149 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1150 available_devices.push_back (i->name);
1153 if (available_devices.empty ()) {
1157 set_popdown_strings (device_combo, available_devices);
1159 std::string default_device =
1160 get_default_device(backend->device_name(), available_devices);
1163 string_compose ("set device_combo active text: %1", default_device));
1165 device_combo.set_active_text(default_device);
1169 // @return true if there are input devices available
1171 EngineControl::set_input_device_popdown_strings ()
1173 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1174 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1175 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1177 vector<string> available_devices;
1179 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1180 available_devices.push_back (i->name);
1183 if (available_devices.empty()) {
1187 set_popdown_strings (input_device_combo, available_devices);
1189 std::string default_device =
1190 get_default_device(backend->input_device_name(), available_devices);
1193 string_compose ("set input_device_combo active text: %1", default_device));
1194 input_device_combo.set_active_text(default_device);
1198 // @return true if there are output devices available
1200 EngineControl::set_output_device_popdown_strings ()
1202 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1203 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1204 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1206 vector<string> available_devices;
1208 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1209 available_devices.push_back (i->name);
1212 if (available_devices.empty()) {
1216 set_popdown_strings (output_device_combo, available_devices);
1218 std::string default_device =
1219 get_default_device(backend->output_device_name(), available_devices);
1222 string_compose ("set output_device_combo active text: %1", default_device));
1223 output_device_combo.set_active_text(default_device);
1228 EngineControl::list_devices ()
1230 DEBUG_ECONTROL ("list_devices");
1231 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1234 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1236 bool devices_available = false;
1238 if (backend->use_separate_input_and_output_devices ()) {
1239 bool input_devices_available = set_input_device_popdown_strings ();
1240 bool output_devices_available = set_output_device_popdown_strings ();
1241 devices_available = input_devices_available || output_devices_available;
1243 devices_available = set_device_popdown_strings ();
1246 if (devices_available) {
1249 device_combo.clear();
1250 input_device_combo.clear();
1251 output_device_combo.clear();
1253 update_sensitivity ();
1257 EngineControl::driver_changed ()
1259 SignalBlocker blocker (*this, "driver_changed");
1260 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1263 backend->set_driver (driver_combo.get_active_text());
1266 if (!ignore_changes) {
1267 maybe_display_saved_state ();
1272 EngineControl::get_sample_rates_for_all_devices ()
1274 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1275 ARDOUR::AudioEngine::instance ()->current_backend ();
1276 vector<float> all_rates;
1278 if (backend->use_separate_input_and_output_devices ()) {
1279 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1281 all_rates = backend->available_sample_rates (get_device_name ());
1287 EngineControl::get_default_sample_rates ()
1289 vector<float> rates;
1290 rates.push_back (8000.0f);
1291 rates.push_back (16000.0f);
1292 rates.push_back (32000.0f);
1293 rates.push_back (44100.0f);
1294 rates.push_back (48000.0f);
1295 rates.push_back (88200.0f);
1296 rates.push_back (96000.0f);
1297 rates.push_back (192000.0f);
1298 rates.push_back (384000.0f);
1303 EngineControl::set_samplerate_popdown_strings ()
1305 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1306 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1311 if (_have_control) {
1312 sr = get_sample_rates_for_all_devices ();
1314 sr = get_default_sample_rates ();
1317 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1318 s.push_back (rate_as_string (*x));
1319 if (*x == _desired_sample_rate) {
1324 set_popdown_strings (sample_rate_combo, s);
1327 if (desired.empty ()) {
1328 float new_active_sr = backend->default_sample_rate ();
1330 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1331 new_active_sr = sr.front ();
1334 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1336 sample_rate_combo.set_active_text (desired);
1340 update_sensitivity ();
1344 EngineControl::get_buffer_sizes_for_all_devices ()
1346 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1347 ARDOUR::AudioEngine::instance ()->current_backend ();
1348 vector<uint32_t> all_sizes;
1350 if (backend->use_separate_input_and_output_devices ()) {
1351 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1353 all_sizes = backend->available_buffer_sizes (get_device_name ());
1359 EngineControl::get_default_buffer_sizes ()
1361 vector<uint32_t> sizes;
1362 sizes.push_back (8);
1363 sizes.push_back (16);
1364 sizes.push_back (32);
1365 sizes.push_back (64);
1366 sizes.push_back (128);
1367 sizes.push_back (256);
1368 sizes.push_back (512);
1369 sizes.push_back (1024);
1370 sizes.push_back (2048);
1371 sizes.push_back (4096);
1372 sizes.push_back (8192);
1377 EngineControl::set_buffersize_popdown_strings ()
1379 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1380 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1381 vector<uint32_t> bs;
1384 if (_have_control) {
1385 bs = get_buffer_sizes_for_all_devices ();
1386 } else if (backend->can_change_buffer_size_when_running()) {
1387 bs = get_default_buffer_sizes ();
1390 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1391 s.push_back (bufsize_as_string (*x));
1394 uint32_t previous_size = 0;
1395 if (!buffer_size_combo.get_active_text().empty()) {
1396 previous_size = get_buffer_size ();
1399 set_popdown_strings (buffer_size_combo, s);
1403 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1404 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1407 buffer_size_combo.set_active_text(s.front());
1409 uint32_t period = backend->buffer_size();
1410 if (0 == period && backend->use_separate_input_and_output_devices()) {
1411 period = backend->default_buffer_size(get_input_device_name());
1413 if (0 == period && backend->use_separate_input_and_output_devices()) {
1414 period = backend->default_buffer_size(get_output_device_name());
1416 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1417 period = backend->default_buffer_size(get_device_name());
1420 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1422 show_buffer_duration ();
1424 update_sensitivity ();
1428 EngineControl::device_changed ()
1430 SignalBlocker blocker (*this, "device_changed");
1431 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1434 string device_name_in;
1435 string device_name_out; // only used if backend support separate I/O devices
1437 if (backend->use_separate_input_and_output_devices()) {
1438 device_name_in = get_input_device_name ();
1439 device_name_out = get_output_device_name ();
1441 device_name_in = get_device_name ();
1444 /* we set the backend-device to query various device related intormation.
1445 * This has the side effect that backend->device_name() will match
1446 * the device_name and 'change_device' will never be true.
1447 * so work around this by setting...
1449 if (backend->use_separate_input_and_output_devices()) {
1450 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1451 queue_device_changed = true;
1454 if (device_name_in != backend->device_name()) {
1455 queue_device_changed = true;
1459 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1460 if (backend->use_separate_input_and_output_devices()) {
1461 backend->set_input_device_name (device_name_in);
1462 backend->set_output_device_name (device_name_out);
1464 backend->set_device_name(device_name_in);
1468 /* don't allow programmatic change to combos to cause a
1469 recursive call to this method.
1471 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1473 set_samplerate_popdown_strings ();
1474 set_buffersize_popdown_strings ();
1476 /* TODO set min + max channel counts here */
1478 manage_control_app_sensitivity ();
1481 /* pick up any saved state for this device */
1483 if (!ignore_changes) {
1484 maybe_display_saved_state ();
1489 EngineControl::input_device_changed ()
1491 DEBUG_ECONTROL ("input_device_changed");
1496 EngineControl::output_device_changed ()
1498 DEBUG_ECONTROL ("output_device_changed");
1503 EngineControl::bufsize_as_string (uint32_t sz)
1505 /* Translators: "samples" is always plural here, so no
1506 need for plural+singular forms.
1509 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1514 EngineControl::sample_rate_changed ()
1516 DEBUG_ECONTROL ("sample_rate_changed");
1517 /* reset the strings for buffer size to show the correct msec value
1518 (reflecting the new sample rate).
1521 show_buffer_duration ();
1526 EngineControl::buffer_size_changed ()
1528 DEBUG_ECONTROL ("buffer_size_changed");
1529 show_buffer_duration ();
1533 EngineControl::show_buffer_duration ()
1535 DEBUG_ECONTROL ("show_buffer_duration");
1536 /* buffer sizes - convert from just samples to samples + msecs for
1537 * the displayed string
1540 string bs_text = buffer_size_combo.get_active_text ();
1541 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1542 uint32_t rate = get_rate();
1544 /* Developers: note the hard-coding of a double buffered model
1545 in the (2 * samples) computation of latency. we always start
1546 the audiobackend in this configuration.
1548 /* note to jack1 developers: ardour also always starts the engine
1549 * in async mode (no jack2 --sync option) which adds an extra cycle
1550 * of latency with jack2 (and *3 would be correct)
1551 * The value can also be wrong if jackd is started externally..
1553 * At the time of writing the ALSA backend always uses double-buffering *2,
1554 * The Dummy backend *1, and who knows what ASIO really does :)
1556 * So just display the period size, that's also what
1557 * ARDOUR_UI::update_sample_rate() does for the status bar.
1558 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1559 * but still, that's the buffer period, not [round-trip] latency)
1562 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1563 buffer_size_duration_label.set_text (buf);
1567 EngineControl::midi_option_changed ()
1569 DEBUG_ECONTROL ("midi_option_changed");
1570 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1573 backend->set_midi_option (get_midi_option());
1575 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1577 //_midi_devices.clear(); // TODO merge with state-saved settings..
1578 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1579 std::vector<MidiDeviceSettings> new_devices;
1581 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1582 MidiDeviceSettings mds = find_midi_device (i->name);
1583 if (i->available && !mds) {
1584 uint32_t input_latency = 0;
1585 uint32_t output_latency = 0;
1586 if (_can_set_midi_latencies) {
1587 input_latency = backend->systemic_midi_input_latency (i->name);
1588 output_latency = backend->systemic_midi_output_latency (i->name);
1590 bool enabled = backend->midi_device_enabled (i->name);
1591 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1592 new_devices.push_back (ptr);
1593 } else if (i->available) {
1594 new_devices.push_back (mds);
1597 _midi_devices = new_devices;
1599 if (_midi_devices.empty()) {
1600 midi_devices_button.set_sensitive (false);
1602 midi_devices_button.set_sensitive (true);
1607 EngineControl::parameter_changed ()
1611 EngineControl::State
1612 EngineControl::get_matching_state (
1613 const string& backend,
1614 const string& driver,
1615 const string& device)
1617 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1618 if ((*i)->backend == backend &&
1619 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1627 EngineControl::State
1628 EngineControl::get_matching_state (
1629 const string& backend,
1630 const string& driver,
1631 const string& input_device,
1632 const string& output_device)
1634 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1635 if ((*i)->backend == backend &&
1636 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1644 EngineControl::State
1645 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1647 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1650 if (backend->use_separate_input_and_output_devices ()) {
1651 return get_matching_state (backend_combo.get_active_text(),
1652 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1653 input_device_combo.get_active_text(),
1654 output_device_combo.get_active_text());
1656 return get_matching_state (backend_combo.get_active_text(),
1657 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1658 device_combo.get_active_text());
1662 return get_matching_state (backend_combo.get_active_text(),
1664 device_combo.get_active_text());
1667 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1668 const EngineControl::State& state2)
1670 if (state1->backend == state2->backend &&
1671 state1->driver == state2->driver &&
1672 state1->device == state2->device &&
1673 state1->input_device == state2->input_device &&
1674 state1->output_device == state2->output_device) {
1680 EngineControl::State
1681 EngineControl::save_state ()
1685 if (!_have_control) {
1686 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1690 state.reset(new StateStruct);
1691 state->backend = get_backend ();
1693 state.reset(new StateStruct);
1694 store_state (state);
1697 for (StateList::iterator i = states.begin(); i != states.end();) {
1698 if (equivalent_states (*i, state)) {
1699 i = states.erase(i);
1705 states.push_back (state);
1711 EngineControl::store_state (State state)
1713 state->backend = get_backend ();
1714 state->driver = get_driver ();
1715 state->device = get_device_name ();
1716 state->input_device = get_input_device_name ();
1717 state->output_device = get_output_device_name ();
1718 state->sample_rate = get_rate ();
1719 state->buffer_size = get_buffer_size ();
1720 state->input_latency = get_input_latency ();
1721 state->output_latency = get_output_latency ();
1722 state->input_channels = get_input_channels ();
1723 state->output_channels = get_output_channels ();
1724 state->midi_option = get_midi_option ();
1725 state->midi_devices = _midi_devices;
1729 EngineControl::maybe_display_saved_state ()
1731 if (!_have_control) {
1735 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1738 DEBUG_ECONTROL ("Restoring saved state");
1739 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1741 if (!_desired_sample_rate) {
1742 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1744 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1745 /* call this explicitly because we're ignoring changes to
1746 the controls at this point.
1748 show_buffer_duration ();
1749 input_latency.set_value (state->input_latency);
1750 output_latency.set_value (state->output_latency);
1752 if (!state->midi_option.empty()) {
1753 midi_option_combo.set_active_text (state->midi_option);
1754 _midi_devices = state->midi_devices;
1757 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1762 EngineControl::get_state ()
1764 LocaleGuard lg (X_("C"));
1766 XMLNode* root = new XMLNode ("AudioMIDISetup");
1769 if (!states.empty()) {
1770 XMLNode* state_nodes = new XMLNode ("EngineStates");
1772 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1774 XMLNode* node = new XMLNode ("State");
1776 node->add_property ("backend", (*i)->backend);
1777 node->add_property ("driver", (*i)->driver);
1778 node->add_property ("device", (*i)->device);
1779 node->add_property ("input-device", (*i)->input_device);
1780 node->add_property ("output-device", (*i)->output_device);
1781 node->add_property ("sample-rate", (*i)->sample_rate);
1782 node->add_property ("buffer-size", (*i)->buffer_size);
1783 node->add_property ("input-latency", (*i)->input_latency);
1784 node->add_property ("output-latency", (*i)->output_latency);
1785 node->add_property ("input-channels", (*i)->input_channels);
1786 node->add_property ("output-channels", (*i)->output_channels);
1787 node->add_property ("active", (*i)->active ? "yes" : "no");
1788 node->add_property ("midi-option", (*i)->midi_option);
1790 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1791 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1792 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1793 midi_device_stuff->add_property (X_("name"), (*p)->name);
1794 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1795 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1796 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1797 midi_devices->add_child_nocopy (*midi_device_stuff);
1799 node->add_child_nocopy (*midi_devices);
1801 state_nodes->add_child_nocopy (*node);
1804 root->add_child_nocopy (*state_nodes);
1811 EngineControl::set_default_state ()
1813 vector<string> backend_names;
1814 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1816 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1817 backend_names.push_back ((*b)->name);
1819 backend_combo.set_active_text (backend_names.front());
1821 // We could set default backends per platform etc here
1827 EngineControl::set_state (const XMLNode& root)
1829 XMLNodeList clist, cclist;
1830 XMLNodeConstIterator citer, cciter;
1832 XMLNode* grandchild;
1833 XMLProperty* prop = NULL;
1835 fprintf (stderr, "EngineControl::set_state\n");
1837 if (root.name() != "AudioMIDISetup") {
1841 clist = root.children();
1845 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1849 if (child->name() != "EngineStates") {
1853 cclist = child->children();
1855 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1856 State state (new StateStruct);
1858 grandchild = *cciter;
1860 if (grandchild->name() != "State") {
1864 if ((prop = grandchild->property ("backend")) == 0) {
1867 state->backend = prop->value ();
1869 if ((prop = grandchild->property ("driver")) == 0) {
1872 state->driver = prop->value ();
1874 if ((prop = grandchild->property ("device")) == 0) {
1877 state->device = prop->value ();
1879 if ((prop = grandchild->property ("input-device")) == 0) {
1882 state->input_device = prop->value ();
1884 if ((prop = grandchild->property ("output-device")) == 0) {
1887 state->output_device = prop->value ();
1889 if ((prop = grandchild->property ("sample-rate")) == 0) {
1892 state->sample_rate = atof (prop->value ());
1894 if ((prop = grandchild->property ("buffer-size")) == 0) {
1897 state->buffer_size = atoi (prop->value ());
1899 if ((prop = grandchild->property ("input-latency")) == 0) {
1902 state->input_latency = atoi (prop->value ());
1904 if ((prop = grandchild->property ("output-latency")) == 0) {
1907 state->output_latency = atoi (prop->value ());
1909 if ((prop = grandchild->property ("input-channels")) == 0) {
1912 state->input_channels = atoi (prop->value ());
1914 if ((prop = grandchild->property ("output-channels")) == 0) {
1917 state->output_channels = atoi (prop->value ());
1919 if ((prop = grandchild->property ("active")) == 0) {
1922 state->active = string_is_affirmative (prop->value ());
1924 if ((prop = grandchild->property ("midi-option")) == 0) {
1927 state->midi_option = prop->value ();
1929 state->midi_devices.clear();
1931 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1932 const XMLNodeList mnc = midinode->children();
1933 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1934 if ((*n)->property (X_("name")) == 0
1935 || (*n)->property (X_("enabled")) == 0
1936 || (*n)->property (X_("input-latency")) == 0
1937 || (*n)->property (X_("output-latency")) == 0
1942 MidiDeviceSettings ptr (new MidiDeviceSetting(
1943 (*n)->property (X_("name"))->value (),
1944 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1945 atoi ((*n)->property (X_("input-latency"))->value ()),
1946 atoi ((*n)->property (X_("output-latency"))->value ())
1948 state->midi_devices.push_back (ptr);
1953 /* remove accumulated duplicates (due to bug in ealier version)
1954 * this can be removed again before release
1956 for (StateList::iterator i = states.begin(); i != states.end();) {
1957 if ((*i)->backend == state->backend &&
1958 (*i)->driver == state->driver &&
1959 (*i)->device == state->device) {
1960 i = states.erase(i);
1967 states.push_back (state);
1971 /* now see if there was an active state and switch the setup to it */
1973 // purge states of backend that are not available in this built
1974 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1975 vector<std::string> backend_names;
1977 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1978 backend_names.push_back((*i)->name);
1980 for (StateList::iterator i = states.begin(); i != states.end();) {
1981 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1982 i = states.erase(i);
1988 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1991 return set_current_state (*i);
1998 EngineControl::set_current_state (const State& state)
2000 DEBUG_ECONTROL ("set_current_state");
2002 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2004 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2005 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2006 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2007 // this shouldn't happen as the invalid backend names should have been
2008 // removed from the list of states.
2012 // now reflect the change in the backend in the GUI so backend_changed will
2013 // do the right thing
2014 backend_combo.set_active_text (state->backend);
2016 if (!state->driver.empty ()) {
2017 if (!backend->requires_driver_selection ()) {
2018 DEBUG_ECONTROL ("Backend should require driver selection");
2019 // A backend has changed from having driver selection to not having
2020 // it or someone has been manually editing a config file and messed
2025 if (backend->set_driver (state->driver) != 0) {
2026 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2027 // Driver names for a backend have changed and the name in the
2028 // config file is now invalid or support for driver is no longer
2029 // included in the backend
2032 // no need to set the driver_combo as backend_changed will use
2033 // backend->driver_name to set the active driver
2036 if (!state->device.empty ()) {
2037 if (backend->set_device_name (state->device) != 0) {
2039 string_compose ("Unable to set device name %1", state->device));
2040 // device is no longer available on the system
2043 // no need to set active device as it will be picked up in
2044 // via backend_changed ()/set_device_popdown_strings
2047 // backend supports separate input/output devices
2048 if (backend->set_input_device_name (state->input_device) != 0) {
2049 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2050 state->input_device));
2051 // input device is no longer available on the system
2055 if (backend->set_output_device_name (state->output_device) != 0) {
2056 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2057 state->input_device));
2058 // output device is no longer available on the system
2061 // no need to set active devices as it will be picked up in via
2062 // backend_changed ()/set_*_device_popdown_strings
2067 // Now restore the state of the rest of the controls
2069 // We don't use a SignalBlocker as set_current_state is currently only
2070 // called from set_state before any signals are connected. If at some point
2071 // a more general named state mechanism is implemented and
2072 // set_current_state is called while signals are connected then a
2073 // SignalBlocker will need to be instantiated before setting these.
2075 device_combo.set_active_text (state->device);
2076 input_device_combo.set_active_text (state->input_device);
2077 output_device_combo.set_active_text (state->output_device);
2078 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2079 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2080 input_latency.set_value (state->input_latency);
2081 output_latency.set_value (state->output_latency);
2082 midi_option_combo.set_active_text (state->midi_option);
2087 EngineControl::push_state_to_backend (bool start)
2089 DEBUG_ECONTROL ("push_state_to_backend");
2090 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2096 /* figure out what is going to change */
2098 bool restart_required = false;
2099 bool was_running = ARDOUR::AudioEngine::instance()->running();
2100 bool change_driver = false;
2101 bool change_device = false;
2102 bool change_rate = false;
2103 bool change_bufsize = false;
2104 bool change_latency = false;
2105 bool change_channels = false;
2106 bool change_midi = false;
2108 uint32_t ochan = get_output_channels ();
2109 uint32_t ichan = get_input_channels ();
2111 if (_have_control) {
2113 if (started_at_least_once) {
2115 /* we can control the backend */
2117 if (backend->requires_driver_selection()) {
2118 if (get_driver() != backend->driver_name()) {
2119 change_driver = true;
2123 if (backend->use_separate_input_and_output_devices()) {
2124 if (get_input_device_name() != backend->input_device_name()) {
2125 change_device = true;
2127 if (get_output_device_name() != backend->output_device_name()) {
2128 change_device = true;
2131 if (get_device_name() != backend->device_name()) {
2132 change_device = true;
2136 if (queue_device_changed) {
2137 change_device = true;
2140 if (get_rate() != backend->sample_rate()) {
2144 if (get_buffer_size() != backend->buffer_size()) {
2145 change_bufsize = true;
2148 if (get_midi_option() != backend->midi_option()) {
2152 /* zero-requested channels means "all available" */
2155 ichan = backend->input_channels();
2159 ochan = backend->output_channels();
2162 if (ichan != backend->input_channels()) {
2163 change_channels = true;
2166 if (ochan != backend->output_channels()) {
2167 change_channels = true;
2170 if (get_input_latency() != backend->systemic_input_latency() ||
2171 get_output_latency() != backend->systemic_output_latency()) {
2172 change_latency = true;
2175 /* backend never started, so we have to force a group
2178 change_device = true;
2179 if (backend->requires_driver_selection()) {
2180 change_driver = true;
2183 change_bufsize = true;
2184 change_channels = true;
2185 change_latency = true;
2191 /* we have no control over the backend, meaning that we can
2192 * only possibly change sample rate and buffer size.
2196 if (get_rate() != backend->sample_rate()) {
2197 change_bufsize = true;
2200 if (get_buffer_size() != backend->buffer_size()) {
2201 change_bufsize = true;
2205 queue_device_changed = false;
2207 if (!_have_control) {
2209 /* We do not have control over the backend, so the best we can
2210 * do is try to change the sample rate and/or bufsize and get
2214 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2218 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2223 backend->set_sample_rate (get_rate());
2226 if (change_bufsize) {
2227 backend->set_buffer_size (get_buffer_size());
2231 if (ARDOUR::AudioEngine::instance()->start ()) {
2232 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2242 /* determine if we need to stop the backend before changing parameters */
2244 if (change_driver || change_device || change_channels || change_latency ||
2245 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2247 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2248 restart_required = true;
2250 restart_required = false;
2255 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2256 /* no changes in any parameters that absolutely require a
2257 * restart, so check those that might be changeable without a
2261 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2262 /* can't do this while running ... */
2263 restart_required = true;
2266 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2267 /* can't do this while running ... */
2268 restart_required = true;
2274 if (restart_required) {
2275 if (ARDOUR::AudioEngine::instance()->stop()) {
2281 if (change_driver && backend->set_driver (get_driver())) {
2282 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2285 if (backend->use_separate_input_and_output_devices()) {
2286 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2287 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2290 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2291 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2295 if (change_device && backend->set_device_name (get_device_name())) {
2296 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2300 if (change_rate && backend->set_sample_rate (get_rate())) {
2301 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2304 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2305 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2309 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2310 if (backend->set_input_channels (get_input_channels())) {
2311 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2314 if (backend->set_output_channels (get_output_channels())) {
2315 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2319 if (change_latency) {
2320 if (backend->set_systemic_input_latency (get_input_latency())) {
2321 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2324 if (backend->set_systemic_output_latency (get_output_latency())) {
2325 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2331 backend->set_midi_option (get_midi_option());
2335 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2336 if (_measure_midi) {
2337 if (*p == _measure_midi) {
2338 backend->set_midi_device_enabled ((*p)->name, true);
2340 backend->set_midi_device_enabled ((*p)->name, false);
2344 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2345 if (backend->can_set_systemic_midi_latencies()) {
2346 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2347 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2352 if (start || (was_running && restart_required)) {
2353 if (ARDOUR::AudioEngine::instance()->start()) {
2364 EngineControl::post_push ()
2366 /* get a pointer to the current state object, creating one if
2370 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2373 state = save_state ();
2381 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2382 (*i)->active = false;
2385 /* mark this one active (to be used next time the dialog is
2389 state->active = true;
2391 if (_have_control) { // XXX
2392 manage_control_app_sensitivity ();
2395 /* schedule a redisplay of MIDI ports */
2396 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2401 EngineControl::get_rate () const
2403 float r = atof (sample_rate_combo.get_active_text ());
2404 /* the string may have been translated with an abbreviation for
2405 * thousands, so use a crude heuristic to fix this.
2415 EngineControl::get_buffer_size () const
2417 string txt = buffer_size_combo.get_active_text ();
2420 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2421 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2422 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2430 EngineControl::get_midi_option () const
2432 return midi_option_combo.get_active_text();
2436 EngineControl::get_input_channels() const
2438 if (ARDOUR::Profile->get_mixbus()) {
2439 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2440 if (!backend) return 0;
2441 return backend->input_channels();
2443 return (uint32_t) input_channels_adjustment.get_value();
2447 EngineControl::get_output_channels() const
2449 if (ARDOUR::Profile->get_mixbus()) {
2450 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2451 if (!backend) return 0;
2452 return backend->input_channels();
2454 return (uint32_t) output_channels_adjustment.get_value();
2458 EngineControl::get_input_latency() const
2460 return (uint32_t) input_latency_adjustment.get_value();
2464 EngineControl::get_output_latency() const
2466 return (uint32_t) output_latency_adjustment.get_value();
2470 EngineControl::get_backend () const
2472 return backend_combo.get_active_text ();
2476 EngineControl::get_driver () const
2478 if (driver_combo.get_parent()) {
2479 return driver_combo.get_active_text ();
2486 EngineControl::get_device_name () const
2488 return device_combo.get_active_text ();
2492 EngineControl::get_input_device_name () const
2494 return input_device_combo.get_active_text ();
2498 EngineControl::get_output_device_name () const
2500 return output_device_combo.get_active_text ();
2504 EngineControl::control_app_button_clicked ()
2506 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2512 backend->launch_control_app ();
2516 EngineControl::start_stop_button_clicked ()
2518 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2524 if (ARDOUR::AudioEngine::instance()->running()) {
2525 ARDOUR::AudioEngine::instance()->stop ();
2532 EngineControl::update_devices_button_clicked ()
2534 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2540 if (backend->update_devices()) {
2541 device_list_changed ();
2546 EngineControl::manage_control_app_sensitivity ()
2548 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2554 string appname = backend->control_app_name();
2556 if (appname.empty()) {
2557 control_app_button.set_sensitive (false);
2559 control_app_button.set_sensitive (true);
2564 EngineControl::set_desired_sample_rate (uint32_t sr)
2566 _desired_sample_rate = sr;
2571 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2573 if (page_num == 0) {
2574 cancel_button->set_sensitive (true);
2575 _measure_midi.reset();
2576 update_sensitivity ();
2578 cancel_button->set_sensitive (false);
2579 ok_button->set_sensitive (false);
2582 if (page_num == midi_tab) {
2584 refresh_midi_display ();
2587 if (page_num == latency_tab) {
2590 if (ARDOUR::AudioEngine::instance()->running()) {
2591 // TODO - mark as 'stopped for latency
2596 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2598 /* save any existing latency values */
2600 uint32_t il = (uint32_t) input_latency.get_value ();
2601 uint32_t ol = (uint32_t) input_latency.get_value ();
2603 /* reset to zero so that our new test instance
2604 will be clean of any existing latency measures.
2606 NB. this should really be done by the backend
2607 when stated for latency measurement.
2610 input_latency.set_value (0);
2611 output_latency.set_value (0);
2613 push_state_to_backend (false);
2617 input_latency.set_value (il);
2618 output_latency.set_value (ol);
2621 // This should be done in push_state_to_backend()
2622 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2623 disable_latency_tab ();
2626 enable_latency_tab ();
2630 end_latency_detection ();
2631 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2636 /* latency measurement */
2639 EngineControl::check_audio_latency_measurement ()
2641 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2643 if (mtdm->resolve () < 0) {
2644 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2648 if (mtdm->err () > 0.3) {
2654 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2656 if (sample_rate == 0) {
2657 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2658 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2662 int frames_total = mtdm->del();
2663 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2665 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2666 _("Detected roundtrip latency: "),
2667 frames_total, frames_total * 1000.0f/sample_rate,
2668 _("Systemic latency: "),
2669 extra, extra * 1000.0f/sample_rate);
2673 if (mtdm->err () > 0.2) {
2675 strcat (buf, _("(signal detection error)"));
2681 strcat (buf, _("(inverted - bad wiring)"));
2685 lm_results.set_markup (string_compose (results_markup, buf));
2688 have_lm_results = true;
2689 end_latency_detection ();
2690 lm_use_button.set_sensitive (true);
2698 EngineControl::check_midi_latency_measurement ()
2700 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2702 if (!mididm->have_signal () || mididm->latency () == 0) {
2703 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2708 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2710 if (sample_rate == 0) {
2711 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2712 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2716 ARDOUR::framecnt_t frames_total = mididm->latency();
2717 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2718 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2719 _("Detected roundtrip latency: "),
2720 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2721 _("Systemic latency: "),
2722 extra, extra * 1000.0f / sample_rate);
2726 if (!mididm->ok ()) {
2728 strcat (buf, _("(averaging)"));
2732 if (mididm->deviation () > 50.0) {
2734 strcat (buf, _("(too large jitter)"));
2736 } else if (mididm->deviation () > 10.0) {
2738 strcat (buf, _("(large jitter)"));
2742 have_lm_results = true;
2743 end_latency_detection ();
2744 lm_use_button.set_sensitive (true);
2745 lm_results.set_markup (string_compose (results_markup, buf));
2747 } else if (mididm->processed () > 400) {
2748 have_lm_results = false;
2749 end_latency_detection ();
2750 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2754 lm_results.set_markup (string_compose (results_markup, buf));
2760 EngineControl::start_latency_detection ()
2762 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2763 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2765 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2766 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2767 if (_measure_midi) {
2768 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2770 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2772 lm_measure_label.set_text (_("Cancel"));
2773 have_lm_results = false;
2774 lm_use_button.set_sensitive (false);
2775 lm_input_channel_combo.set_sensitive (false);
2776 lm_output_channel_combo.set_sensitive (false);
2782 EngineControl::end_latency_detection ()
2784 latency_timeout.disconnect ();
2785 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2786 lm_measure_label.set_text (_("Measure"));
2787 if (!have_lm_results) {
2788 lm_use_button.set_sensitive (false);
2790 lm_input_channel_combo.set_sensitive (true);
2791 lm_output_channel_combo.set_sensitive (true);
2796 EngineControl::latency_button_clicked ()
2799 start_latency_detection ();
2801 end_latency_detection ();
2806 EngineControl::use_latency_button_clicked ()
2808 if (_measure_midi) {
2809 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2813 ARDOUR::framecnt_t frames_total = mididm->latency();
2814 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2815 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2816 _measure_midi->input_latency = one_way;
2817 _measure_midi->output_latency = one_way;
2818 notebook.set_current_page (midi_tab);
2820 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2826 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2827 one_way = std::max (0., one_way);
2829 input_latency_adjustment.set_value (one_way);
2830 output_latency_adjustment.set_value (one_way);
2832 /* back to settings page */
2833 notebook.set_current_page (0);
2839 EngineControl::on_delete_event (GdkEventAny* ev)
2841 if (notebook.get_current_page() == 2) {
2842 /* currently on latency tab - be sure to clean up */
2843 end_latency_detection ();
2845 return ArdourDialog::on_delete_event (ev);
2849 EngineControl::engine_running ()
2851 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2854 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2855 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2857 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2858 connect_disconnect_button.show();
2860 started_at_least_once = true;
2861 if (_have_control) {
2862 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2864 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2866 update_sensitivity();
2870 EngineControl::engine_stopped ()
2872 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2875 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2876 connect_disconnect_button.show();
2878 if (_have_control) {
2879 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2881 engine_status.set_markup(X_(""));
2884 update_sensitivity();
2888 EngineControl::device_list_changed ()
2890 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2892 midi_option_changed();
2896 EngineControl::connect_disconnect_click()
2898 if (ARDOUR::AudioEngine::instance()->running()) {
2906 EngineControl::calibrate_audio_latency ()
2908 _measure_midi.reset ();
2909 have_lm_results = false;
2910 lm_use_button.set_sensitive (false);
2911 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2912 notebook.set_current_page (latency_tab);
2916 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2919 have_lm_results = false;
2920 lm_use_button.set_sensitive (false);
2921 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2922 notebook.set_current_page (latency_tab);
2926 EngineControl::configure_midi_devices ()
2928 notebook.set_current_page (midi_tab);