2 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2008-2012 David Robillard <d@drobilla.net>
5 * Copyright (C) 2013-2014 Colin Fletcher <colin.m.fletcher@googlemail.com>
6 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
7 * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
8 * Copyright (C) 2015 Ben Loftis <ben@harrisonconsoles.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <boost/scoped_ptr.hpp>
32 #include "pbd/error.h"
33 #include "pbd/locale_guard.h"
34 #include "pbd/xml++.h"
35 #include "pbd/unwind.h"
36 #include "pbd/failed_constructor.h"
38 #include <gtkmm/alignment.h>
39 #include <gtkmm/stock.h>
40 #include <gtkmm/notebook.h>
41 #include <gtkmm2ext/utils.h>
43 #include "widgets/tooltips.h"
45 #include "ardour/audio_backend.h"
46 #include "ardour/audioengine.h"
47 #include "ardour/mtdm.h"
48 #include "ardour/mididm.h"
49 #include "ardour/rc_configuration.h"
50 #include "ardour/types.h"
51 #include "ardour/profile.h"
53 #include "pbd/convert.h"
54 #include "pbd/error.h"
58 #include "ardour_message.h"
59 #include "ardour_ui.h"
60 #include "engine_dialog.h"
61 #include "gui_thread.h"
62 #include "ui_config.h"
63 #include "public_editor.h"
70 using namespace Gtkmm2ext;
73 using namespace ArdourWidgets;
74 using namespace ARDOUR_UI_UTILS;
76 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
78 static const unsigned int midi_tab = 2;
79 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
81 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
83 EngineControl::EngineControl ()
84 : ArdourDialog (_("Audio/MIDI Setup"))
87 , input_latency_adjustment (0, 0, 99999, 1)
88 , input_latency (input_latency_adjustment)
89 , output_latency_adjustment (0, 0, 99999, 1)
90 , output_latency (output_latency_adjustment)
91 , input_channels_adjustment (0, 0, 256, 1)
92 , input_channels (input_channels_adjustment)
93 , output_channels_adjustment (0, 0, 256, 1)
94 , output_channels (output_channels_adjustment)
95 , ports_adjustment (128, 8, 1024, 1, 16)
96 , ports_spinner (ports_adjustment)
97 , control_app_button (_("Device Control Panel"))
98 , midi_devices_button (_("Midi Device Setup"))
99 , start_stop_button (_("Stop"))
100 , update_devices_button (_("Refresh Devices"))
101 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
102 , try_autostart_button (_("Autostart"), ArdourButton::led_default_elements)
103 , lm_measure_label (_("Measure"))
104 , lm_use_button (_("Use results"))
105 , lm_back_button (_("Back to settings ... (ignore results)"))
106 , lm_button_audio (_("Calibrate Audio"))
108 , have_lm_results (false)
110 , midi_back_button (_("Back to settings"))
112 , ignore_device_changes (0)
113 , _desired_sample_rate (0)
114 , started_at_least_once (false)
115 , queue_device_changed (false)
116 , _have_control (true)
119 using namespace Notebook_Helpers;
120 vector<string> backend_names;
122 AttachOptions xopt = AttachOptions (FILL|EXPAND);
125 set_name (X_("AudioMIDISetup"));
127 /* the backend combo is the one thing that is ALWAYS visible */
129 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
131 if (backends.empty()) {
132 ArdourMessageDialog 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));
134 throw failed_constructor ();
137 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
138 backend_names.push_back ((*b)->name);
141 set_popdown_strings (backend_combo, backend_names);
143 /* setup basic packing characteristics for the table used on the main
144 * tab of the notebook
147 basic_packer.set_spacings (6);
148 basic_packer.set_border_width (12);
149 basic_packer.set_homogeneous (false);
153 basic_hbox.pack_start (basic_packer, false, false);
155 /* latency measurement tab */
157 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
160 lm_table.set_row_spacings (12);
161 lm_table.set_col_spacings (6);
162 lm_table.set_homogeneous (false);
164 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
167 lm_preamble.set_width_chars (60);
168 lm_preamble.set_line_wrap (true);
169 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
171 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
174 Gtk::Label* preamble;
175 preamble = manage (new Label);
176 preamble->set_width_chars (60);
177 preamble->set_line_wrap (true);
178 preamble->set_markup (_("Select two channels below and connect them using a cable."));
180 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
183 label = manage (new Label (_("Output channel:")));
184 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
186 lm_output_channel_list = Gtk::ListStore::create (lm_output_channel_cols);
187 lm_output_channel_combo.set_model (lm_output_channel_list);
188 lm_output_channel_combo.pack_start (lm_output_channel_cols.pretty_name);
190 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
191 misc_align->add (lm_output_channel_combo);
192 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
195 label = manage (new Label (_("Input channel:")));
196 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
198 lm_input_channel_list = Gtk::ListStore::create (lm_input_channel_cols);
199 lm_input_channel_combo.set_model (lm_input_channel_list);
200 lm_input_channel_combo.pack_start (lm_input_channel_cols.pretty_name);
202 misc_align = manage (new Alignment (0.0, 0.5));
203 misc_align->add (lm_input_channel_combo);
204 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
207 lm_measure_label.set_padding (10, 10);
208 lm_measure_button.add (lm_measure_label);
209 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
210 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
211 lm_back_button_signal = lm_back_button.signal_clicked().connect(
212 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
214 lm_use_button.set_sensitive (false);
216 /* Increase the default spacing around the labels of these three
222 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
223 l->set_padding (10, 10);
226 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
227 l->set_padding (10, 10);
230 preamble = manage (new Label);
231 preamble->set_width_chars (60);
232 preamble->set_line_wrap (true);
233 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
234 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
237 preamble = manage (new Label);
238 preamble->set_width_chars (60);
239 preamble->set_line_wrap (true);
240 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
241 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
243 ++row; // skip a row in the table
244 ++row; // skip a row in the table
246 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
248 ++row; // skip a row in the table
249 ++row; // skip a row in the table
251 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
252 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
253 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
255 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
257 lm_vbox.set_border_width (12);
258 lm_vbox.pack_start (lm_table, false, false);
260 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
264 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
265 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
266 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
267 notebook.set_border_width (12);
269 notebook.set_show_tabs (false);
270 notebook.show_all ();
272 notebook.set_name ("SettingsNotebook");
274 /* packup the notebook */
276 get_vbox()->set_border_width (12);
277 get_vbox()->pack_start (notebook);
279 /* need a special function to print "all available channels" when the
280 * channel counts hit zero.
283 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
284 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
286 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
287 midi_devices_button.set_name ("generic button");
288 midi_devices_button.set_can_focus(true);
290 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
291 control_app_button.set_name ("generic button");
292 control_app_button.set_can_focus(true);
293 manage_control_app_sensitivity ();
295 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
296 start_stop_button.set_sensitive (false);
297 start_stop_button.set_name ("generic button");
298 start_stop_button.set_can_focus(true);
299 start_stop_button.set_can_default(true);
300 start_stop_button.set_act_on_release (false);
302 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
303 update_devices_button.set_sensitive (false);
304 update_devices_button.set_name ("generic button");
305 update_devices_button.set_can_focus(true);
307 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
308 use_buffered_io_button.set_sensitive (false);
309 use_buffered_io_button.set_name ("generic button");
310 use_buffered_io_button.set_can_focus(true);
312 try_autostart_button.signal_clicked.connect (mem_fun (*this, &EngineControl::try_autostart_button_clicked));
313 try_autostart_button.set_name ("generic button");
314 try_autostart_button.set_can_focus(true);
315 config_parameter_changed ("try-autostart-engine");
316 set_tooltip (try_autostart_button,
317 string_compose (_("Always try these settings when starting %1, if the same device is available"), PROGRAM_NAME));
319 ARDOUR::Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&EngineControl::config_parameter_changed, this, _1), gui_context());
321 /* Pick up any existing audio setup configuration, if appropriate */
323 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
325 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
326 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
327 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
328 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
331 if (!set_state (*audio_setup)) {
332 set_default_state ();
335 set_default_state ();
338 update_sensitivity ();
339 connect_changed_signals ();
341 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
343 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
345 connect_disconnect_button.set_no_show_all();
346 start_stop_button.set_no_show_all();
350 EngineControl::connect_changed_signals ()
352 backend_combo_connection = backend_combo.signal_changed ().connect (
353 sigc::mem_fun (*this, &EngineControl::backend_changed));
354 driver_combo_connection = driver_combo.signal_changed ().connect (
355 sigc::mem_fun (*this, &EngineControl::driver_changed));
356 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
357 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
358 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
359 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
360 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
361 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
362 device_combo_connection = device_combo.signal_changed ().connect (
363 sigc::mem_fun (*this, &EngineControl::device_changed));
364 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
365 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
367 input_device_combo_connection = input_device_combo.signal_changed ().connect (
368 sigc::mem_fun (*this, &EngineControl::input_device_changed));
369 output_device_combo_connection = output_device_combo.signal_changed ().connect (
370 sigc::mem_fun (*this, &EngineControl::output_device_changed));
372 input_latency_connection = input_latency.signal_changed ().connect (
373 sigc::mem_fun (*this, &EngineControl::parameter_changed));
374 output_latency_connection = output_latency.signal_changed ().connect (
375 sigc::mem_fun (*this, &EngineControl::parameter_changed));
376 input_channels_connection = input_channels.signal_changed ().connect (
377 sigc::mem_fun (*this, &EngineControl::parameter_changed));
378 output_channels_connection = output_channels.signal_changed ().connect (
379 sigc::mem_fun (*this, &EngineControl::parameter_changed));
383 EngineControl::block_changed_signals ()
385 if (block_signals++ == 0) {
386 DEBUG_ECONTROL ("Blocking changed signals");
387 backend_combo_connection.block ();
388 driver_combo_connection.block ();
389 sample_rate_combo_connection.block ();
390 buffer_size_combo_connection.block ();
391 nperiods_combo_connection.block ();
392 device_combo_connection.block ();
393 input_device_combo_connection.block ();
394 output_device_combo_connection.block ();
395 midi_option_combo_connection.block ();
396 input_latency_connection.block ();
397 output_latency_connection.block ();
398 input_channels_connection.block ();
399 output_channels_connection.block ();
404 EngineControl::unblock_changed_signals ()
406 if (--block_signals == 0) {
407 DEBUG_ECONTROL ("Unblocking changed signals");
408 backend_combo_connection.unblock ();
409 driver_combo_connection.unblock ();
410 sample_rate_combo_connection.unblock ();
411 buffer_size_combo_connection.unblock ();
412 nperiods_combo_connection.unblock ();
413 device_combo_connection.unblock ();
414 input_device_combo_connection.unblock ();
415 output_device_combo_connection.unblock ();
416 midi_option_combo_connection.unblock ();
417 input_latency_connection.unblock ();
418 output_latency_connection.unblock ();
419 input_channels_connection.unblock ();
420 output_channels_connection.unblock ();
424 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
425 const std::string& reason)
426 : ec (engine_control)
429 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
430 ec.block_changed_signals ();
433 EngineControl::SignalBlocker::~SignalBlocker ()
435 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
436 ec.unblock_changed_signals ();
440 EngineControl::on_show ()
442 ArdourDialog::on_show ();
443 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
444 // re-check _have_control (jackd running) see #6041
448 start_stop_button.grab_focus();
452 EngineControl::on_map ()
454 if (!ARDOUR_UI::instance()->the_session () && !PublicEditor::_instance) {
455 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
456 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
457 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
459 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
461 ArdourDialog::on_map ();
465 EngineControl::config_parameter_changed (std::string const & p)
467 if (p == "try-autostart-engine") {
468 try_autostart_button.set_active (ARDOUR::Config->get_try_autostart_engine ());
473 EngineControl::start_engine ()
475 if (push_state_to_backend (true) != 0) {
476 ArdourMessageDialog msg (*this, ARDOUR::AudioEngine::instance()->get_last_backend_error());
484 EngineControl::stop_engine (bool for_latency)
486 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
487 ArdourMessageDialog msg(*this, ARDOUR::AudioEngine::instance()->get_last_backend_error());
495 EngineControl::build_notebook ()
498 AttachOptions xopt = AttachOptions (FILL|EXPAND);
500 /* clear the table */
502 Gtkmm2ext::container_clear (basic_vbox);
503 Gtkmm2ext::container_clear (basic_packer);
505 if (control_app_button.get_parent()) {
506 control_app_button.get_parent()->remove (control_app_button);
509 label = manage (left_aligned_label (_("Audio System:")));
510 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
511 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
513 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
514 engine_status.show();
516 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
518 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
519 lm_button_audio.set_name ("generic button");
520 lm_button_audio.set_can_focus(true);
523 build_full_control_notebook ();
525 build_no_control_notebook ();
528 basic_vbox.pack_start (basic_hbox, false, false);
531 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
532 basic_vbox.show_all ();
537 EngineControl::build_full_control_notebook ()
539 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
542 using namespace Notebook_Helpers;
544 vector<string> strings;
545 AttachOptions xopt = AttachOptions (FILL|EXPAND);
546 int row = 1; // row zero == backend combo
547 int btn = 1; // row zero == start_stop_button
548 bool autostart_packed = false;
550 /* start packing it up */
552 if (backend->requires_driver_selection()) {
553 label = manage (left_aligned_label (_("Driver:")));
554 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
555 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
559 if (backend->use_separate_input_and_output_devices()) {
560 label = manage (left_aligned_label (_("Input Device:")));
561 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
562 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
564 label = manage (left_aligned_label (_("Output Device:")));
565 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
568 // reset so it isn't used in state comparisons
569 device_combo.set_active_text ("");
571 label = manage (left_aligned_label (_("Device:")));
572 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
575 // reset these so they don't get used in state comparisons
576 input_device_combo.set_active_text ("");
577 output_device_combo.set_active_text ("");
580 /* same line as Driver */
581 if (backend->can_use_buffered_io()) {
582 basic_packer.attach (use_buffered_io_button, 3, 4, btn, btn + 1, xopt, xopt);
586 /* same line as Device(s) */
587 if (backend->can_request_update_devices()) {
588 basic_packer.attach (update_devices_button, 3, 4, btn, btn + 1, xopt, xopt);
592 /* prefer "try autostart" below "Start" if possible */
594 basic_packer.attach (try_autostart_button, 3, 4, btn, btn + 1, xopt, xopt);
596 autostart_packed = true;
599 label = manage (left_aligned_label (_("Sample rate:")));
600 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
601 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
604 label = manage (left_aligned_label (_("Buffer size:")));
605 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
606 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
607 buffer_size_duration_label.set_alignment (0.0); /* left-align */
608 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
610 int ctrl_btn_span = 1;
611 if (backend->can_set_period_size ()) {
613 label = manage (left_aligned_label (_("Periods:")));
614 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
615 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
619 /* button spans 2 or 3 rows: Sample rate, Buffer size, Periods */
620 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
623 input_channels.set_name ("InputChannels");
624 input_channels.set_flags (Gtk::CAN_FOCUS);
625 input_channels.set_digits (0);
626 input_channels.set_wrap (false);
627 output_channels.set_editable (true);
629 if (!ARDOUR::Profile->get_mixbus()) {
630 label = manage (left_aligned_label (_("Input channels:")));
631 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
632 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
636 output_channels.set_name ("OutputChannels");
637 output_channels.set_flags (Gtk::CAN_FOCUS);
638 output_channels.set_digits (0);
639 output_channels.set_wrap (false);
640 output_channels.set_editable (true);
642 if (!ARDOUR::Profile->get_mixbus()) {
643 label = manage (left_aligned_label (_("Output channels:")));
644 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
645 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
649 /* Prefere next available vertical slot, 1 row */
650 if (btn < row && !autostart_packed) {
651 basic_packer.attach (try_autostart_button, 3, 4, btn, btn + 1, xopt, xopt);
653 autostart_packed = true;
656 input_latency.set_name ("InputLatency");
657 input_latency.set_flags (Gtk::CAN_FOCUS);
658 input_latency.set_digits (0);
659 input_latency.set_wrap (false);
660 input_latency.set_editable (true);
662 label = manage (left_aligned_label (_("Hardware input latency:")));
663 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
664 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
665 label = manage (left_aligned_label (_("samples")));
666 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
669 output_latency.set_name ("OutputLatency");
670 output_latency.set_flags (Gtk::CAN_FOCUS);
671 output_latency.set_digits (0);
672 output_latency.set_wrap (false);
673 output_latency.set_editable (true);
675 label = manage (left_aligned_label (_("Hardware output latency:")));
676 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
677 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
678 label = manage (left_aligned_label (_("samples")));
679 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
681 /* button spans 2 rows */
683 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
686 label = manage (left_aligned_label (_("MIDI System:")));
687 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
688 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
689 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
692 if (!autostart_packed) {
693 basic_packer.attach (try_autostart_button, 3, 4, row, row+1, xopt, xopt);
698 EngineControl::build_no_control_notebook ()
700 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
703 using namespace Notebook_Helpers;
705 vector<string> strings;
706 AttachOptions xopt = AttachOptions (FILL|EXPAND);
707 int row = 1; // row zero == backend combo
708 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
710 label = manage (new Label);
711 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
712 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
715 if (backend->can_change_sample_rate_when_running()) {
716 label = manage (left_aligned_label (_("Sample rate:")));
717 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
718 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
722 if (backend->can_change_buffer_size_when_running()) {
723 label = manage (left_aligned_label (_("Buffer size:")));
724 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
725 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
726 buffer_size_duration_label.set_alignment (0.0); /* left-align */
727 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
731 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
735 EngineControl::~EngineControl ()
737 ignore_changes = true;
741 EngineControl::disable_latency_tab ()
743 lm_input_channel_list->clear ();
744 lm_output_channel_list->clear ();
745 lm_measure_button.set_sensitive (false);
746 lm_use_button.set_sensitive (false);
750 EngineControl::enable_latency_tab ()
752 vector<string> outputs;
753 vector<string> inputs;
755 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
756 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
757 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
759 if (!ARDOUR::AudioEngine::instance()->running()) {
760 ArdourMessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
761 notebook.set_current_page (0);
765 else if (inputs.empty() || outputs.empty()) {
766 ArdourMessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
767 notebook.set_current_page (0);
772 lm_back_button_signal.disconnect();
774 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
777 lm_back_button_signal = lm_back_button.signal_clicked().connect(
778 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
782 lm_output_channel_list->clear ();
783 for (vector<string>::const_iterator i = outputs.begin(); i != outputs.end(); ++i) {
784 Gtk::TreeModel::iterator iter = lm_output_channel_list->append ();
785 Gtk::TreeModel::Row row = *iter;
786 row[lm_output_channel_cols.port_name] = *i;
787 std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*i);
789 pn = (*i).substr ((*i).find (':') + 1);
791 row[lm_output_channel_cols.pretty_name] = pn;
793 lm_output_channel_combo.set_active (0);
794 lm_output_channel_combo.set_sensitive (true);
796 lm_input_channel_list->clear ();
797 for (vector<string>::const_iterator i = inputs.begin(); i != inputs.end(); ++i) {
798 Gtk::TreeModel::iterator iter = lm_input_channel_list->append ();
799 Gtk::TreeModel::Row row = *iter;
800 row[lm_input_channel_cols.port_name] = *i;
801 std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*i);
803 pn = (*i).substr ((*i).find (':') + 1);
805 row[lm_input_channel_cols.pretty_name] = pn;
807 lm_input_channel_combo.set_active (0);
808 lm_input_channel_combo.set_sensitive (true);
810 lm_measure_button.set_sensitive (true);
814 EngineControl::setup_midi_tab_for_backend ()
816 string backend = backend_combo.get_active_text ();
818 Gtkmm2ext::container_clear (midi_vbox);
820 midi_vbox.set_border_width (12);
821 midi_device_table.set_border_width (12);
823 if (backend == "JACK") {
824 setup_midi_tab_for_jack ();
827 midi_vbox.pack_start (midi_device_table, true, true);
828 midi_vbox.pack_start (midi_back_button, false, false);
829 midi_vbox.show_all ();
833 EngineControl::update_sensitivity ()
835 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
837 start_stop_button.set_sensitive (false);
842 size_t devices_available = 0;
843 bool engine_running = ARDOUR::AudioEngine::instance()->running();
845 if (backend->use_separate_input_and_output_devices ()) {
846 devices_available += get_popdown_string_count (input_device_combo);
847 devices_available += get_popdown_string_count (output_device_combo);
849 devices_available += get_popdown_string_count (device_combo);
852 if (devices_available == 0) {
854 input_latency.set_sensitive (false);
855 output_latency.set_sensitive (false);
856 input_channels.set_sensitive (false);
857 output_channels.set_sensitive (false);
859 input_latency.set_sensitive (true);
860 output_latency.set_sensitive (true);
861 input_channels.set_sensitive (!engine_running);
862 output_channels.set_sensitive (!engine_running);
865 if (get_popdown_string_count (buffer_size_combo) > 0) {
866 if (!engine_running) {
867 buffer_size_combo.set_sensitive (valid);
868 } else if (backend->can_change_buffer_size_when_running ()) {
869 buffer_size_combo.set_sensitive (valid || !_have_control);
871 buffer_size_combo.set_sensitive (false);
874 buffer_size_combo.set_sensitive (false);
878 if (get_popdown_string_count (sample_rate_combo) > 0) {
879 bool allow_to_set_rate = false;
880 if (!engine_running) {
881 if (!ARDOUR_UI::instance()->the_session ()) {
882 // engine is not running, no session loaded -> anything goes.
883 allow_to_set_rate = true;
884 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
885 // only allow to change if the current setting is not the native session rate.
886 allow_to_set_rate = true;
889 sample_rate_combo.set_sensitive (allow_to_set_rate);
891 sample_rate_combo.set_sensitive (false);
895 if (get_popdown_string_count (nperiods_combo) > 0) {
896 if (!engine_running) {
897 nperiods_combo.set_sensitive (true);
899 nperiods_combo.set_sensitive (false);
902 nperiods_combo.set_sensitive (false);
906 start_stop_button.set_sensitive(true);
907 start_stop_button.show();
908 if (engine_running) {
909 start_stop_button.set_text("Stop");
910 update_devices_button.set_sensitive(false);
911 use_buffered_io_button.set_sensitive(false);
913 start_stop_button.set_text("Start");
914 update_devices_button.set_sensitive (backend->can_request_update_devices ());
915 use_buffered_io_button.set_sensitive (backend->can_use_buffered_io ());
918 start_stop_button.set_sensitive(false);
919 start_stop_button.hide();
922 if (engine_running && _have_control) {
923 input_device_combo.set_sensitive (false);
924 output_device_combo.set_sensitive (false);
925 device_combo.set_sensitive (false);
926 driver_combo.set_sensitive (false);
928 input_device_combo.set_sensitive (true);
929 output_device_combo.set_sensitive (true);
930 device_combo.set_sensitive (true);
931 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
932 driver_combo.set_sensitive (true);
934 driver_combo.set_sensitive (false);
938 midi_option_combo.set_sensitive (!engine_running);
942 EngineControl::setup_midi_tab_for_jack ()
947 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
949 device->input_latency = a->get_value();
951 device->output_latency = a->get_value();
954 if (ARDOUR::AudioEngine::instance()->running() && !_measure_midi) {
955 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
957 if (backend->can_change_systemic_latency_when_running () && device->enabled) {
959 backend->set_systemic_midi_input_latency (device->name, device->input_latency);
961 backend->set_systemic_midi_output_latency (device->name, device->output_latency);
968 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
969 b->set_active (!b->get_active());
970 device->enabled = b->get_active();
971 refresh_midi_display(device->name);
973 if (ARDOUR::AudioEngine::instance()->running()) {
974 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
976 backend->set_midi_device_enabled (device->name, device->enabled);
977 if (backend->can_change_systemic_latency_when_running () && device->enabled) {
978 backend->set_systemic_midi_input_latency (device->name, device->input_latency);
979 backend->set_systemic_midi_output_latency (device->name, device->output_latency);
985 EngineControl::refresh_midi_display (std::string focus)
987 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
991 AttachOptions xopt = AttachOptions (FILL|EXPAND);
994 Gtkmm2ext::container_clear (midi_device_table);
996 midi_device_table.set_spacings (6);
998 l = manage (new Label);
999 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
1000 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
1001 l->set_alignment (0.5, 0.5);
1005 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
1006 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
1007 l = manage (new Label (_("Systemic Latency [samples]"))); l->show (); l->set_alignment (0.5, 0.5);
1008 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
1010 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
1011 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
1012 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
1013 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
1016 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1021 bool enabled = (*p)->enabled;
1023 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
1024 m->set_name ("midi device");
1025 m->set_can_focus (true);
1026 m->add_events (Gdk::BUTTON_RELEASE_MASK);
1027 m->set_active (enabled);
1028 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
1029 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
1030 if ((*p)->name == focus) {
1034 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1035 s = manage (new Gtk::SpinButton (*a));
1036 a->set_value ((*p)->input_latency);
1037 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1038 s->set_sensitive (_can_set_midi_latencies && enabled);
1039 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1041 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1042 s = manage (new Gtk::SpinButton (*a));
1043 a->set_value ((*p)->output_latency);
1044 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1045 s->set_sensitive (_can_set_midi_latencies && enabled);
1046 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1048 b = manage (new Button (_("Calibrate")));
1049 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1050 b->set_sensitive (_can_set_midi_latencies && enabled);
1051 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1058 EngineControl::backend_changed ()
1060 SignalBlocker blocker (*this, "backend_changed");
1061 string backend_name = backend_combo.get_active_text();
1062 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1064 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1065 /* eh? setting the backend failed... how ? */
1066 /* A: stale config contains a backend that does not exist in current build */
1070 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1072 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1075 setup_midi_tab_for_backend ();
1076 _midi_devices.clear();
1078 if (backend->requires_driver_selection()) {
1079 if (set_driver_popdown_strings ()) {
1083 /* this will change the device text which will cause a call to
1084 * device changed which will set up parameters
1089 update_midi_options ();
1091 connect_disconnect_button.hide();
1093 midi_option_changed();
1095 started_at_least_once = false;
1097 /* changing the backend implies stopping the engine
1098 * ARDOUR::AudioEngine() may or may not emit this signal
1099 * depending on previous engine state
1101 engine_stopped (); // set "active/inactive"
1103 if (!_have_control) {
1104 // set settings from backend that we do have control over
1105 set_buffersize_popdown_strings ();
1106 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1109 if (_have_control && !ignore_changes) {
1110 // set driver & devices
1111 State state = get_matching_state (backend_combo.get_active_text());
1113 DEBUG_ECONTROL ("backend-changed(): found prior state for backend");
1114 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1115 set_current_state (state);
1117 DEBUG_ECONTROL ("backend-changed(): no prior state for backend");
1120 DEBUG_ECONTROL (string_compose ("backend-changed(): _have_control=%1 ignore_changes=%2", _have_control, ignore_changes));
1123 if (!ignore_changes) {
1124 maybe_display_saved_state ();
1129 EngineControl::update_midi_options ()
1131 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1132 vector<string> midi_options = backend->enumerate_midi_options();
1134 if (midi_options.size() == 1) {
1135 /* only contains the "none" option */
1136 set_popdown_strings (midi_option_combo, midi_options);
1137 midi_option_combo.set_sensitive (false);
1139 if (_have_control) {
1140 set_popdown_strings (midi_option_combo, midi_options);
1141 midi_option_combo.set_active_text (midi_options.front());
1142 midi_option_combo.set_sensitive (true);
1144 midi_option_combo.set_sensitive (false);
1150 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1152 if (ARDOUR::Profile->get_mixbus()) {
1156 uint32_t cnt = (uint32_t) sb->get_value();
1158 sb->set_text (_("all available channels"));
1161 snprintf (buf, sizeof (buf), "%d", cnt);
1167 // @return true if there are drivers available
1169 EngineControl::set_driver_popdown_strings ()
1171 DEBUG_ECONTROL ("set_driver_popdown_strings");
1172 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1173 vector<string> drivers = backend->enumerate_drivers();
1175 if (drivers.empty ()) {
1176 // This is an error...?
1180 string current_driver = backend->driver_name ();
1182 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1184 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1187 current_driver = drivers.front ();
1190 set_popdown_strings (driver_combo, drivers);
1192 string_compose ("driver_combo.set_active_text: %1", current_driver));
1193 driver_combo.set_active_text (current_driver);
1198 EngineControl::get_default_device(const string& current_device_name,
1199 const vector<string>& available_devices)
1201 // If the current device is available, use it as default
1202 if (std::find (available_devices.begin (),
1203 available_devices.end (),
1204 current_device_name) != available_devices.end ()) {
1206 return current_device_name;
1209 using namespace ARDOUR;
1211 string default_device_name =
1212 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1214 vector<string>::const_iterator i;
1216 // If there is a "Default" device available, use it
1217 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1218 if (*i == default_device_name) {
1223 string none_device_name =
1224 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1226 // Use the first device that isn't "None"
1227 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1228 if (*i != none_device_name) {
1233 // Use "None" if there are no other available
1234 return available_devices.front();
1237 // @return true if there are devices available
1239 EngineControl::set_device_popdown_strings ()
1241 DEBUG_ECONTROL ("set_device_popdown_strings");
1242 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1243 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1245 /* NOTE: Ardour currently does not display the "available" field of the
1248 * Doing so would require a different GUI widget than the combo
1249 * box/popdown that we currently use, since it has no way to list
1250 * items that are not selectable. Something more like a popup menu,
1251 * which could have unselectable items, would be appropriate.
1254 vector<string> available_devices;
1256 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1257 available_devices.push_back (i->name);
1260 if (available_devices.empty ()) {
1264 set_popdown_strings (device_combo, available_devices);
1266 std::string default_device =
1267 get_default_device(backend->device_name(), available_devices);
1270 string_compose ("set device_combo active text: %1", default_device));
1272 device_combo.set_active_text(default_device);
1276 // @return true if there are input devices available
1278 EngineControl::set_input_device_popdown_strings ()
1280 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1281 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1282 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1284 vector<string> available_devices;
1286 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1287 available_devices.push_back (i->name);
1290 if (available_devices.empty()) {
1294 set_popdown_strings (input_device_combo, available_devices);
1296 std::string default_device =
1297 get_default_device(backend->input_device_name(), available_devices);
1300 string_compose ("set input_device_combo active text: %1", default_device));
1301 input_device_combo.set_active_text(default_device);
1305 // @return true if there are output devices available
1307 EngineControl::set_output_device_popdown_strings ()
1309 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1310 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1311 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1313 vector<string> available_devices;
1315 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1316 available_devices.push_back (i->name);
1319 if (available_devices.empty()) {
1323 set_popdown_strings (output_device_combo, available_devices);
1325 std::string default_device =
1326 get_default_device(backend->output_device_name(), available_devices);
1329 string_compose ("set output_device_combo active text: %1", default_device));
1330 output_device_combo.set_active_text(default_device);
1335 EngineControl::list_devices ()
1337 DEBUG_ECONTROL ("list_devices");
1338 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1341 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1343 bool devices_available = false;
1345 if (backend->use_separate_input_and_output_devices ()) {
1346 bool input_devices_available = set_input_device_popdown_strings ();
1347 bool output_devices_available = set_output_device_popdown_strings ();
1348 devices_available = input_devices_available || output_devices_available;
1350 devices_available = set_device_popdown_strings ();
1353 if (devices_available) {
1356 device_combo.clear();
1357 input_device_combo.clear();
1358 output_device_combo.clear();
1360 update_sensitivity ();
1364 EngineControl::driver_changed ()
1366 SignalBlocker blocker (*this, "driver_changed");
1367 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1370 backend->set_driver (driver_combo.get_active_text());
1373 // TODO load LRU device(s) for backend + driver combo
1375 if (!ignore_changes) {
1376 maybe_display_saved_state ();
1381 EngineControl::get_sample_rates_for_all_devices ()
1383 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1384 ARDOUR::AudioEngine::instance ()->current_backend ();
1385 vector<float> all_rates;
1387 if (backend->use_separate_input_and_output_devices ()) {
1388 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1390 all_rates = backend->available_sample_rates (get_device_name ());
1396 EngineControl::get_default_sample_rates ()
1398 vector<float> rates;
1399 rates.push_back (8000.0f);
1400 rates.push_back (16000.0f);
1401 rates.push_back (32000.0f);
1402 rates.push_back (44100.0f);
1403 rates.push_back (48000.0f);
1404 rates.push_back (88200.0f);
1405 rates.push_back (96000.0f);
1406 rates.push_back (192000.0f);
1407 rates.push_back (384000.0f);
1412 EngineControl::set_samplerate_popdown_strings ()
1414 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1415 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1420 if (_have_control) {
1421 sr = get_sample_rates_for_all_devices ();
1423 sr = get_default_sample_rates ();
1426 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1427 s.push_back (rate_as_string (*x));
1428 if (*x == _desired_sample_rate) {
1433 set_popdown_strings (sample_rate_combo, s);
1436 if (ARDOUR::AudioEngine::instance()->running()) {
1437 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1438 } else if (ARDOUR_UI::instance()->the_session ()) {
1439 float active_sr = ARDOUR_UI::instance()->the_session()->nominal_sample_rate ();
1441 if (std::find (sr.begin (), sr.end (), active_sr) == sr.end ()) {
1442 active_sr = sr.front ();
1445 sample_rate_combo.set_active_text (rate_as_string (active_sr));
1446 } else if (desired.empty ()) {
1447 float new_active_sr = backend->default_sample_rate ();
1449 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1450 new_active_sr = sr.front ();
1453 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1455 sample_rate_combo.set_active_text (desired);
1458 update_sensitivity ();
1462 EngineControl::get_buffer_sizes_for_all_devices ()
1464 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1465 ARDOUR::AudioEngine::instance ()->current_backend ();
1466 vector<uint32_t> all_sizes;
1468 if (backend->use_separate_input_and_output_devices ()) {
1469 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1471 all_sizes = backend->available_buffer_sizes (get_device_name ());
1477 EngineControl::get_default_buffer_sizes ()
1479 vector<uint32_t> sizes;
1480 sizes.push_back (8);
1481 sizes.push_back (16);
1482 sizes.push_back (32);
1483 sizes.push_back (64);
1484 sizes.push_back (128);
1485 sizes.push_back (256);
1486 sizes.push_back (512);
1487 sizes.push_back (1024);
1488 sizes.push_back (2048);
1489 sizes.push_back (4096);
1490 sizes.push_back (8192);
1495 EngineControl::set_buffersize_popdown_strings ()
1497 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1498 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1499 vector<uint32_t> bs;
1502 if (_have_control) {
1503 bs = get_buffer_sizes_for_all_devices ();
1504 } else if (backend->can_change_buffer_size_when_running()) {
1505 bs = get_default_buffer_sizes ();
1508 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1509 s.push_back (bufsize_as_string (*x));
1512 uint32_t previous_size = backend->buffer_size ();
1513 if (!buffer_size_combo.get_active_text().empty()) {
1514 previous_size = get_buffer_size ();
1517 set_popdown_strings (buffer_size_combo, s);
1521 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1522 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1525 buffer_size_combo.set_active_text(s.front());
1527 uint32_t period = backend->buffer_size();
1528 if (0 == period && backend->use_separate_input_and_output_devices()) {
1529 period = backend->default_buffer_size(get_input_device_name());
1531 if (0 == period && backend->use_separate_input_and_output_devices()) {
1532 period = backend->default_buffer_size(get_output_device_name());
1534 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1535 period = backend->default_buffer_size(get_device_name());
1538 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1540 show_buffer_duration ();
1542 update_sensitivity ();
1546 EngineControl::set_nperiods_popdown_strings ()
1548 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1549 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1550 vector<uint32_t> np;
1553 if (backend->can_set_period_size()) {
1554 np = backend->available_period_sizes (get_driver());
1557 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1558 s.push_back (to_string (*x));
1561 set_popdown_strings (nperiods_combo, s);
1564 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1567 update_sensitivity ();
1571 EngineControl::device_changed ()
1573 SignalBlocker blocker (*this, "device_changed");
1574 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1577 string device_name_in;
1578 string device_name_out; // only used if backend support separate I/O devices
1580 if (backend->use_separate_input_and_output_devices()) {
1581 device_name_in = get_input_device_name ();
1582 device_name_out = get_output_device_name ();
1584 device_name_in = get_device_name ();
1587 /* we set the backend-device to query various device related intormation.
1588 * This has the side effect that backend->device_name() will match
1589 * the device_name and 'change_device' will never be true.
1590 * so work around this by setting...
1592 if (backend->use_separate_input_and_output_devices()) {
1593 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1594 queue_device_changed = true;
1597 if (device_name_in != backend->device_name()) {
1598 queue_device_changed = true;
1602 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1603 if (backend->use_separate_input_and_output_devices()) {
1604 backend->set_input_device_name (device_name_in);
1605 backend->set_output_device_name (device_name_out);
1607 backend->set_device_name(device_name_in);
1611 /* don't allow programmatic change to combos to cause a
1612 recursive call to this method.
1614 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1616 set_samplerate_popdown_strings ();
1617 set_buffersize_popdown_strings ();
1618 set_nperiods_popdown_strings ();
1620 /* TODO set min + max channel counts here */
1622 manage_control_app_sensitivity ();
1625 /* pick up any saved state for this device */
1627 if (!ignore_changes) {
1628 maybe_display_saved_state ();
1633 EngineControl::input_device_changed ()
1635 DEBUG_ECONTROL ("input_device_changed");
1637 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1638 if (backend && backend->match_input_output_devices_or_none ()) {
1639 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1641 if (get_output_device_name () != dev_none
1642 && get_input_device_name () != dev_none
1643 && get_input_device_name () != get_output_device_name ()) {
1644 block_changed_signals ();
1645 if (contains_value (output_device_combo, get_input_device_name ())) {
1646 output_device_combo.set_active_text (get_input_device_name ());
1648 assert (contains_value (output_device_combo, dev_none));
1649 output_device_combo.set_active_text (dev_none);
1651 unblock_changed_signals ();
1658 EngineControl::output_device_changed ()
1660 DEBUG_ECONTROL ("output_device_changed");
1661 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1662 if (backend && backend->match_input_output_devices_or_none ()) {
1663 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1665 if (get_input_device_name () != dev_none
1666 && get_input_device_name () != dev_none
1667 && get_input_device_name () != get_output_device_name ()) {
1668 block_changed_signals ();
1669 if (contains_value (input_device_combo, get_output_device_name ())) {
1670 input_device_combo.set_active_text (get_output_device_name ());
1672 assert (contains_value (input_device_combo, dev_none));
1673 input_device_combo.set_active_text (dev_none);
1675 unblock_changed_signals ();
1682 EngineControl::bufsize_as_string (uint32_t sz)
1684 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1688 EngineControl::sample_rate_changed ()
1690 DEBUG_ECONTROL ("sample_rate_changed");
1691 /* reset the strings for buffer size to show the correct msec value
1692 (reflecting the new sample rate).
1695 show_buffer_duration ();
1700 EngineControl::buffer_size_changed ()
1702 DEBUG_ECONTROL ("buffer_size_changed");
1703 if (ARDOUR::AudioEngine::instance()->running()) {
1704 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1705 if (backend && backend->can_change_buffer_size_when_running ()) {
1706 backend->set_buffer_size (get_buffer_size());
1709 show_buffer_duration ();
1713 EngineControl::nperiods_changed ()
1715 DEBUG_ECONTROL ("nperiods_changed");
1716 show_buffer_duration ();
1720 EngineControl::show_buffer_duration ()
1722 DEBUG_ECONTROL ("show_buffer_duration");
1723 /* buffer sizes - convert from just samples to samples + msecs for
1724 * the displayed string
1727 string bs_text = buffer_size_combo.get_active_text ();
1728 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1729 uint32_t rate = get_rate();
1731 /* Except for ALSA and Dummy backends, we don't know the number of periods
1732 * per cycle and settings.
1734 * jack1 vs jack2 have different default latencies since jack2 start
1735 * in async-mode unless --sync is given which adds an extra cycle
1736 * of latency. The value is not known if jackd is started externally..
1738 * So just display the period size, that's also what
1739 * ARDOUR_UI::update_sample_rate() does for the status bar.
1740 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1741 * but still, that's the buffer period, not [round-trip] latency)
1744 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1745 buffer_size_duration_label.set_text (buf);
1749 EngineControl::midi_option_changed ()
1751 DEBUG_ECONTROL ("midi_option_changed");
1752 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1755 backend->set_midi_option (get_midi_option());
1757 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1759 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1760 std::vector<MidiDeviceSettings> new_devices;
1762 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1763 MidiDeviceSettings mds = find_midi_device (i->name);
1764 if (i->available && !mds) {
1765 uint32_t input_latency = 0;
1766 uint32_t output_latency = 0;
1767 if (_can_set_midi_latencies) {
1768 input_latency = backend->systemic_midi_input_latency (i->name);
1769 output_latency = backend->systemic_midi_output_latency (i->name);
1771 bool enabled = backend->midi_device_enabled (i->name);
1772 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1773 new_devices.push_back (ptr);
1774 } else if (i->available) {
1775 new_devices.push_back (mds);
1778 _midi_devices = new_devices;
1780 if (_midi_devices.empty()) {
1781 midi_devices_button.set_sensitive (false);
1783 midi_devices_button.set_sensitive (true);
1788 EngineControl::parameter_changed ()
1792 EngineControl::State
1793 EngineControl::get_matching_state (const string& backend)
1795 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1796 if ((*i)->backend == backend) {
1803 EngineControl::State
1804 EngineControl::get_matching_state (
1805 const string& backend,
1806 const string& driver,
1807 const string& device)
1809 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1810 if ((*i)->backend == backend &&
1811 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1819 EngineControl::State
1820 EngineControl::get_matching_state (
1821 const string& backend,
1822 const string& driver,
1823 const string& input_device,
1824 const string& output_device)
1826 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1827 if ((*i)->backend == backend &&
1828 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1836 EngineControl::State
1837 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1839 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1842 if (backend->use_separate_input_and_output_devices ()) {
1843 return get_matching_state (backend_combo.get_active_text(),
1844 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1845 input_device_combo.get_active_text(),
1846 output_device_combo.get_active_text());
1848 return get_matching_state (backend_combo.get_active_text(),
1849 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1850 device_combo.get_active_text());
1854 return get_matching_state (backend_combo.get_active_text(),
1856 device_combo.get_active_text());
1859 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1860 const EngineControl::State& state2)
1862 if (state1->backend == state2->backend &&
1863 state1->driver == state2->driver &&
1864 state1->device == state2->device &&
1865 state1->input_device == state2->input_device &&
1866 state1->output_device == state2->output_device) {
1872 // sort active first, then most recently used to the beginning of the list
1874 EngineControl::state_sort_cmp (const State &a, const State &b) {
1878 else if (b->active) {
1882 return a->lru > b->lru;
1886 EngineControl::State
1887 EngineControl::save_state ()
1891 if (!_have_control) {
1892 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1894 state->lru = time (NULL) ;
1897 state.reset(new StateStruct);
1898 state->backend = get_backend ();
1900 state.reset(new StateStruct);
1901 store_state (state);
1904 for (StateList::iterator i = states.begin(); i != states.end();) {
1905 if (equivalent_states (*i, state)) {
1906 i = states.erase(i);
1912 states.push_back (state);
1914 states.sort (state_sort_cmp);
1920 EngineControl::store_state (State state)
1922 state->backend = get_backend ();
1923 state->driver = get_driver ();
1924 state->device = get_device_name ();
1925 state->input_device = get_input_device_name ();
1926 state->output_device = get_output_device_name ();
1927 state->sample_rate = get_rate ();
1928 state->buffer_size = get_buffer_size ();
1929 state->n_periods = get_nperiods ();
1930 state->input_latency = get_input_latency ();
1931 state->output_latency = get_output_latency ();
1932 state->input_channels = get_input_channels ();
1933 state->output_channels = get_output_channels ();
1934 state->midi_option = get_midi_option ();
1935 state->midi_devices = _midi_devices;
1936 state->use_buffered_io = get_use_buffered_io ();
1937 state->lru = time (NULL) ;
1941 EngineControl::maybe_display_saved_state ()
1943 if (!_have_control || ARDOUR::AudioEngine::instance()->running ()) {
1947 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1950 DEBUG_ECONTROL ("Restoring saved state");
1951 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1953 if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
1954 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1956 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1958 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1959 /* call this explicitly because we're ignoring changes to
1960 the controls at this point.
1962 show_buffer_duration ();
1963 input_latency.set_value (state->input_latency);
1964 output_latency.set_value (state->output_latency);
1966 use_buffered_io_button.set_active (state->use_buffered_io);
1968 if (!state->midi_option.empty()) {
1969 midi_option_combo.set_active_text (state->midi_option);
1970 _midi_devices = state->midi_devices;
1971 midi_option_changed ();
1974 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1979 EngineControl::get_state ()
1983 XMLNode* root = new XMLNode ("AudioMIDISetup");
1986 if (!states.empty()) {
1987 XMLNode* state_nodes = new XMLNode ("EngineStates");
1989 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1991 XMLNode* node = new XMLNode ("State");
1993 node->set_property ("backend", (*i)->backend);
1994 node->set_property ("driver", (*i)->driver);
1995 node->set_property ("device", (*i)->device);
1996 node->set_property ("input-device", (*i)->input_device);
1997 node->set_property ("output-device", (*i)->output_device);
1998 node->set_property ("sample-rate", (*i)->sample_rate);
1999 node->set_property ("buffer-size", (*i)->buffer_size);
2000 node->set_property ("n-periods", (*i)->n_periods);
2001 node->set_property ("input-latency", (*i)->input_latency);
2002 node->set_property ("output-latency", (*i)->output_latency);
2003 node->set_property ("input-channels", (*i)->input_channels);
2004 node->set_property ("output-channels", (*i)->output_channels);
2005 node->set_property ("active", (*i)->active);
2006 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
2007 node->set_property ("midi-option", (*i)->midi_option);
2008 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
2009 node->set_property ("lru", lru_val );
2011 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
2012 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
2013 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
2014 midi_device_stuff->set_property (X_("name"), (*p)->name);
2015 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
2016 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
2017 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
2018 midi_devices->add_child_nocopy (*midi_device_stuff);
2020 node->add_child_nocopy (*midi_devices);
2022 state_nodes->add_child_nocopy (*node);
2025 root->add_child_nocopy (*state_nodes);
2032 EngineControl::set_default_state ()
2034 vector<string> backend_names;
2035 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2037 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
2038 backend_names.push_back ((*b)->name);
2040 backend_combo.set_active_text (backend_names.front());
2042 // We could set default backends per platform etc here
2048 EngineControl::set_state (const XMLNode& root)
2050 XMLNodeList clist, cclist;
2051 XMLNodeConstIterator citer, cciter;
2052 XMLNode const * child;
2053 XMLNode const * grandchild;
2055 if (root.name() != "AudioMIDISetup") {
2059 clist = root.children();
2063 for (citer = clist.begin(); citer != clist.end(); ++citer) {
2067 if (child->name() != "EngineStates") {
2071 cclist = child->children();
2073 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2074 State state (new StateStruct);
2076 grandchild = *cciter;
2078 if (grandchild->name() != "State") {
2082 if (!grandchild->get_property ("backend", state->backend)) {
2086 // If any of the required properties are not found in the state node
2087 // then continue/skip to the next engine state
2088 if (!grandchild->get_property ("driver", state->driver) ||
2089 !grandchild->get_property ("device", state->device) ||
2090 !grandchild->get_property ("input-device", state->input_device) ||
2091 !grandchild->get_property ("output-device", state->output_device) ||
2092 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2093 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2094 !grandchild->get_property ("input-latency", state->input_latency) ||
2095 !grandchild->get_property ("output-latency", state->output_latency) ||
2096 !grandchild->get_property ("input-channels", state->input_channels) ||
2097 !grandchild->get_property ("output-channels", state->output_channels) ||
2098 !grandchild->get_property ("active", state->active) ||
2099 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2100 !grandchild->get_property ("midi-option", state->midi_option)) {
2104 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2105 // optional (new value in 4.5)
2106 state->n_periods = 0;
2109 state->midi_devices.clear();
2111 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2112 const XMLNodeList mnc = midinode->children();
2113 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2116 uint32_t input_latency;
2117 uint32_t output_latency;
2119 if (!(*n)->get_property (X_("name"), name) ||
2120 !(*n)->get_property (X_("enabled"), enabled) ||
2121 !(*n)->get_property (X_("input-latency"), input_latency) ||
2122 !(*n)->get_property (X_("output-latency"), output_latency)) {
2126 MidiDeviceSettings ptr (
2127 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2128 state->midi_devices.push_back (ptr);
2133 if (grandchild->get_property ("lru", lru_val)) {
2134 state->lru = lru_val;
2137 states.push_back (state);
2141 /* now see if there was an active state and switch the setup to it */
2143 /* purge states of backend that are not available in this built */
2144 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2145 vector<std::string> backend_names;
2147 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2148 backend_names.push_back((*i)->name);
2150 for (StateList::iterator i = states.begin(); i != states.end();) {
2151 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2152 i = states.erase(i);
2158 states.sort (state_sort_cmp);
2160 /* purge old states referring to the same backend */
2161 const time_t now = time (NULL);
2162 for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2164 for (StateList::iterator i = states.begin(); i != states.end();) {
2165 if ((*i)->backend != *bi) {
2168 // keep at latest one for every audio-system
2173 // also keep states used in the last 90 days.
2174 if ((now - (*i)->lru) < 86400 * 90) {
2177 assert (!(*i)->active);
2178 i = states.erase(i);
2182 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2185 return set_current_state (*i);
2192 EngineControl::set_current_state (const State& state)
2194 DEBUG_ECONTROL ("set_current_state");
2196 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2198 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (state->backend, downcase (std::string (PROGRAM_NAME)), ""))) {
2199 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2200 // this shouldn't happen as the invalid backend names should have been
2201 // removed from the list of states.
2205 // now reflect the change in the backend in the GUI so backend_changed will
2206 // do the right thing
2207 backend_combo.set_active_text (state->backend);
2209 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2211 // we don't have control don't restore state
2216 if (!state->driver.empty ()) {
2217 if (!backend->requires_driver_selection ()) {
2218 DEBUG_ECONTROL ("Backend should require driver selection");
2219 // A backend has changed from having driver selection to not having
2220 // it or someone has been manually editing a config file and messed
2225 if (backend->set_driver (state->driver) != 0) {
2226 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2227 // Driver names for a backend have changed and the name in the
2228 // config file is now invalid or support for driver is no longer
2229 // included in the backend
2232 // no need to set the driver_combo as backend_changed will use
2233 // backend->driver_name to set the active driver
2236 if (!state->device.empty ()) {
2237 if (backend->set_device_name (state->device) != 0) {
2239 string_compose ("Unable to set device name %1", state->device));
2240 // device is no longer available on the system
2243 // no need to set active device as it will be picked up in
2244 // via backend_changed ()/set_device_popdown_strings
2247 // backend supports separate input/output devices
2248 if (backend->set_input_device_name (state->input_device) != 0) {
2249 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2250 state->input_device));
2251 // input device is no longer available on the system
2255 if (backend->set_output_device_name (state->output_device) != 0) {
2256 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2257 state->input_device));
2258 // output device is no longer available on the system
2261 // no need to set active devices as it will be picked up in via
2262 // backend_changed ()/set_*_device_popdown_strings
2267 // Now restore the state of the rest of the controls
2269 // We don't use a SignalBlocker as set_current_state is currently only
2270 // called from set_state before any signals are connected. If at some point
2271 // a more general named state mechanism is implemented and
2272 // set_current_state is called while signals are connected then a
2273 // SignalBlocker will need to be instantiated before setting these.
2275 device_combo.set_active_text (state->device);
2276 input_device_combo.set_active_text (state->input_device);
2277 output_device_combo.set_active_text (state->output_device);
2278 if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
2279 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2281 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2282 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2283 input_latency.set_value (state->input_latency);
2284 output_latency.set_value (state->output_latency);
2285 midi_option_combo.set_active_text (state->midi_option);
2286 use_buffered_io_button.set_active (state->use_buffered_io);
2291 EngineControl::push_state_to_backend (bool start)
2293 DEBUG_ECONTROL ("push_state_to_backend");
2294 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2295 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2301 /* figure out what is going to change */
2303 bool restart_required = false;
2304 bool was_running = ARDOUR::AudioEngine::instance()->running();
2305 bool change_driver = false;
2306 bool change_device = false;
2307 bool change_rate = false;
2308 bool change_bufsize = false;
2309 bool change_nperiods = false;
2310 bool change_latency = false;
2311 bool change_channels = false;
2312 bool change_midi = false;
2313 bool change_buffered_io = false;
2315 uint32_t ochan = get_output_channels ();
2316 uint32_t ichan = get_input_channels ();
2318 if (_have_control) {
2320 if (started_at_least_once) {
2322 /* we can control the backend */
2324 if (backend->requires_driver_selection()) {
2325 if (get_driver() != backend->driver_name()) {
2326 change_driver = true;
2330 if (backend->use_separate_input_and_output_devices()) {
2331 if (get_input_device_name() != backend->input_device_name()) {
2332 change_device = true;
2334 if (get_output_device_name() != backend->output_device_name()) {
2335 change_device = true;
2338 if (get_device_name() != backend->device_name()) {
2339 change_device = true;
2343 if (queue_device_changed) {
2344 change_device = true;
2347 if (get_rate() != backend->sample_rate()) {
2351 if (get_buffer_size() != backend->buffer_size()) {
2352 change_bufsize = true;
2355 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2356 && get_nperiods() != backend->period_size()) {
2357 change_nperiods = true;
2360 if (get_midi_option() != backend->midi_option()) {
2364 if (backend->can_use_buffered_io()) {
2365 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2366 change_buffered_io = true;
2370 /* zero-requested channels means "all available" */
2373 ichan = backend->input_channels();
2377 ochan = backend->output_channels();
2380 if (ichan != backend->input_channels()) {
2381 change_channels = true;
2384 if (ochan != backend->output_channels()) {
2385 change_channels = true;
2388 if (get_input_latency() != backend->systemic_input_latency() ||
2389 get_output_latency() != backend->systemic_output_latency()) {
2390 change_latency = true;
2393 /* backend never started, so we have to force a group
2396 change_device = true;
2397 if (backend->requires_driver_selection()) {
2398 change_driver = true;
2401 change_bufsize = true;
2402 change_channels = true;
2403 change_latency = true;
2405 change_buffered_io = backend->can_use_buffered_io();
2406 change_channels = true;
2407 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2412 /* we have no control over the backend, meaning that we can
2413 * only possibly change sample rate and buffer size.
2417 if (get_rate() != backend->sample_rate()) {
2418 change_bufsize = true;
2421 if (get_buffer_size() != backend->buffer_size()) {
2422 change_bufsize = true;
2426 queue_device_changed = false;
2428 if (!_have_control) {
2430 /* We do not have control over the backend, so the best we can
2431 * do is try to change the sample rate and/or bufsize and get
2435 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2439 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2444 backend->set_sample_rate (get_rate());
2447 if (change_bufsize) {
2448 backend->set_buffer_size (get_buffer_size());
2452 if (ARDOUR::AudioEngine::instance()->start ()) {
2453 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2463 /* determine if we need to stop the backend before changing parameters */
2465 if (change_driver || change_device || change_channels || change_nperiods ||
2466 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2467 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2468 change_midi || change_buffered_io ||
2469 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2470 restart_required = true;
2472 restart_required = false;
2477 if (restart_required) {
2478 if (ARDOUR::AudioEngine::instance()->stop()) {
2484 if (change_driver && backend->set_driver (get_driver())) {
2485 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2488 if (backend->use_separate_input_and_output_devices()) {
2489 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2490 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2493 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2494 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2498 if (change_device && backend->set_device_name (get_device_name())) {
2499 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2503 if (change_rate && backend->set_sample_rate (get_rate())) {
2504 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2507 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2508 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2511 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2512 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2516 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2517 if (backend->set_input_channels (get_input_channels())) {
2518 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2521 if (backend->set_output_channels (get_output_channels())) {
2522 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2526 if (change_latency) {
2527 if (backend->set_systemic_input_latency (get_input_latency())) {
2528 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2531 if (backend->set_systemic_output_latency (get_output_latency())) {
2532 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2538 backend->set_midi_option (get_midi_option());
2541 if (change_buffered_io) {
2542 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2546 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2547 if (_measure_midi) {
2548 /* Disable other MIDI devices while measuring.
2549 * This is a hack to only show ports from the selected device */
2550 if (*p == _measure_midi) {
2551 backend->set_midi_device_enabled ((*p)->name, true);
2553 backend->set_midi_device_enabled ((*p)->name, false);
2557 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2558 if (backend->can_set_systemic_midi_latencies()) {
2559 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2560 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2565 if (start || (was_running && restart_required)) {
2566 if (ARDOUR::AudioEngine::instance()->start()) {
2577 EngineControl::post_push ()
2579 /* get a pointer to the current state object, creating one if
2583 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2586 state = save_state ();
2592 states.sort (state_sort_cmp);
2596 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2597 (*i)->active = false;
2600 /* mark this one active (to be used next time the dialog is
2604 state->active = true;
2606 if (_have_control) { // XXX
2607 manage_control_app_sensitivity ();
2610 /* schedule a redisplay of MIDI ports */
2611 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2616 EngineControl::get_rate () const
2618 float r = atof (sample_rate_combo.get_active_text ());
2619 /* the string may have been translated with an abbreviation for
2620 * thousands, so use a crude heuristic to fix this.
2630 EngineControl::get_buffer_size () const
2632 string txt = buffer_size_combo.get_active_text ();
2635 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2636 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2637 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2645 EngineControl::get_nperiods () const
2647 string txt = nperiods_combo.get_active_text ();
2648 return atoi (txt.c_str());
2652 EngineControl::get_midi_option () const
2654 return midi_option_combo.get_active_text();
2658 EngineControl::get_use_buffered_io () const
2660 return use_buffered_io_button.get_active();
2664 EngineControl::get_input_channels() const
2666 if (ARDOUR::Profile->get_mixbus()) {
2667 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2668 if (!backend) return 0;
2669 return backend->input_channels();
2671 return (uint32_t) input_channels_adjustment.get_value();
2675 EngineControl::get_output_channels() const
2677 if (ARDOUR::Profile->get_mixbus()) {
2678 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2679 if (!backend) return 0;
2680 return backend->input_channels();
2682 return (uint32_t) output_channels_adjustment.get_value();
2686 EngineControl::get_input_latency() const
2688 return (uint32_t) input_latency_adjustment.get_value();
2692 EngineControl::get_output_latency() const
2694 return (uint32_t) output_latency_adjustment.get_value();
2698 EngineControl::get_backend () const
2700 return backend_combo.get_active_text ();
2704 EngineControl::get_driver () const
2706 if (driver_combo.get_parent()) {
2707 return driver_combo.get_active_text ();
2714 EngineControl::get_device_name () const
2716 return device_combo.get_active_text ();
2720 EngineControl::get_input_device_name () const
2722 return input_device_combo.get_active_text ();
2726 EngineControl::get_output_device_name () const
2728 return output_device_combo.get_active_text ();
2732 EngineControl::control_app_button_clicked ()
2734 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2740 backend->launch_control_app ();
2744 EngineControl::on_response (int r)
2746 /* Do not run ArdourDialog::on_response() which will hide us. Leave
2747 * that to whoever invoked us, if they wish to hide us after "start".
2749 * StartupFSM does hide us after response(); Window > Audio/MIDI Setup
2753 Gtk::Dialog::on_response (r);
2757 EngineControl::start_stop_button_clicked ()
2759 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2765 if (ARDOUR::AudioEngine::instance()->running()) {
2766 ARDOUR::AudioEngine::instance()->stop ();
2768 /* whoever displayed this dialog is expected to do its own
2769 check on whether or not the engine is running.
2774 response (RESPONSE_OK);
2778 EngineControl::update_devices_button_clicked ()
2780 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2786 if (backend->update_devices()) {
2787 device_list_changed ();
2792 EngineControl::try_autostart_button_clicked ()
2794 ARDOUR::Config->set_try_autostart_engine (!try_autostart_button.get_active ());
2795 try_autostart_button.set_active (ARDOUR::Config->get_try_autostart_engine ());
2799 EngineControl::use_buffered_io_button_clicked ()
2801 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2807 bool set_buffered_io = !use_buffered_io_button.get_active();
2808 use_buffered_io_button.set_active (set_buffered_io);
2809 backend->set_use_buffered_io (set_buffered_io);
2813 EngineControl::manage_control_app_sensitivity ()
2815 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2821 string appname = backend->control_app_name();
2823 if (appname.empty()) {
2824 control_app_button.set_sensitive (false);
2826 control_app_button.set_sensitive (true);
2831 EngineControl::set_desired_sample_rate (uint32_t sr)
2833 _desired_sample_rate = sr;
2835 if (ARDOUR::AudioEngine::instance ()->running () && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2843 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2845 if (page_num == 0) {
2846 _measure_midi.reset();
2847 update_sensitivity ();
2850 if (page_num == midi_tab) {
2852 refresh_midi_display ();
2854 /* undo special case from push_state_to_backend() when measuring midi latency */
2855 if (_measure_midi && ARDOUR::AudioEngine::instance()->running ()) {
2856 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2857 if (backend->can_change_systemic_latency_when_running ()) {
2858 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2859 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2863 _measure_midi.reset();
2866 if (page_num == latency_tab) {
2869 if (ARDOUR::AudioEngine::instance()->running()) {
2874 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2876 /* save any existing latency values */
2878 uint32_t il = (uint32_t) input_latency.get_value ();
2879 uint32_t ol = (uint32_t) input_latency.get_value ();
2881 /* reset to zero so that our new test instance
2882 will be clean of any existing latency measures.
2884 NB. this should really be done by the backend
2885 when stated for latency measurement.
2888 input_latency.set_value (0);
2889 output_latency.set_value (0);
2891 push_state_to_backend (false);
2895 input_latency.set_value (il);
2896 output_latency.set_value (ol);
2899 // This should be done in push_state_to_backend()
2900 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2901 disable_latency_tab ();
2904 enable_latency_tab ();
2908 end_latency_detection ();
2913 /* latency measurement */
2916 EngineControl::check_audio_latency_measurement ()
2918 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2920 if (mtdm->resolve () < 0) {
2921 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2925 if (mtdm->get_peak () > 0.707f) {
2926 // get_peak() resets the peak-hold in the detector.
2927 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2928 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2932 if (mtdm->err () > 0.3) {
2938 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2940 if (sample_rate == 0) {
2941 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2942 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2946 int samples_total = mtdm->del();
2947 int extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2949 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2950 _("Detected roundtrip latency: "),
2951 samples_total, samples_total * 1000.0f/sample_rate,
2952 _("Systemic latency: "),
2953 extra, extra * 1000.0f/sample_rate);
2957 if (mtdm->err () > 0.2) {
2959 strcat (buf, _("(signal detection error)"));
2965 strcat (buf, _("(inverted - bad wiring)"));
2969 lm_results.set_markup (string_compose (results_markup, buf));
2972 have_lm_results = true;
2973 end_latency_detection ();
2974 lm_use_button.set_sensitive (true);
2982 EngineControl::check_midi_latency_measurement ()
2984 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2986 if (!mididm->have_signal () || mididm->latency () == 0) {
2987 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2992 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2994 if (sample_rate == 0) {
2995 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2996 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3000 ARDOUR::samplecnt_t samples_total = mididm->latency();
3001 ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3002 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
3003 _("Detected roundtrip latency: "),
3004 samples_total, samples_total * 1000.0f / sample_rate, mididm->deviation (),
3005 _("Systemic latency: "),
3006 extra, extra * 1000.0f / sample_rate);
3010 if (!mididm->ok ()) {
3012 strcat (buf, _("(averaging)"));
3016 if (mididm->deviation () > 50.0) {
3018 strcat (buf, _("(too large jitter)"));
3020 } else if (mididm->deviation () > 10.0) {
3022 strcat (buf, _("(large jitter)"));
3026 have_lm_results = true;
3027 end_latency_detection ();
3028 lm_use_button.set_sensitive (true);
3029 lm_results.set_markup (string_compose (results_markup, buf));
3031 } else if (mididm->processed () > 400) {
3032 have_lm_results = false;
3033 end_latency_detection ();
3034 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3038 lm_results.set_markup (string_compose (results_markup, buf));
3044 EngineControl::start_latency_detection ()
3046 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active ()->get_value (lm_input_channel_cols.port_name));
3047 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active ()->get_value (lm_output_channel_cols.port_name));
3049 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3050 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3051 if (_measure_midi) {
3052 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3054 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3056 lm_measure_label.set_text (_("Cancel"));
3057 have_lm_results = false;
3058 lm_use_button.set_sensitive (false);
3059 lm_input_channel_combo.set_sensitive (false);
3060 lm_output_channel_combo.set_sensitive (false);
3066 EngineControl::end_latency_detection ()
3068 latency_timeout.disconnect ();
3069 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3070 lm_measure_label.set_text (_("Measure"));
3071 if (!have_lm_results) {
3072 lm_use_button.set_sensitive (false);
3074 lm_input_channel_combo.set_sensitive (true);
3075 lm_output_channel_combo.set_sensitive (true);
3080 EngineControl::latency_button_clicked ()
3083 start_latency_detection ();
3085 end_latency_detection ();
3090 EngineControl::latency_back_button_clicked ()
3092 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3093 notebook.set_current_page(0);
3097 EngineControl::use_latency_button_clicked ()
3099 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3100 if (_measure_midi) {
3101 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3105 ARDOUR::samplecnt_t samples_total = mididm->latency();
3106 ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3107 uint32_t one_way = max ((ARDOUR::samplecnt_t) 0, extra / 2);
3108 _measure_midi->input_latency = one_way;
3109 _measure_midi->output_latency = one_way;
3110 if (backend->can_change_systemic_latency_when_running ()) {
3111 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3112 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3114 notebook.set_current_page (midi_tab);
3116 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3122 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3123 one_way = std::max (0., one_way);
3125 input_latency_adjustment.set_value (one_way);
3126 output_latency_adjustment.set_value (one_way);
3127 if (backend->can_change_systemic_latency_when_running ()) {
3128 backend->set_systemic_input_latency (one_way);
3129 backend->set_systemic_output_latency (one_way);
3132 /* back to settings page */
3133 notebook.set_current_page (0);
3138 EngineControl::on_delete_event (GdkEventAny* ev)
3140 if (lm_running || notebook.get_current_page() == 2) {
3141 /* currently measuring latency - be sure to clean up */
3142 end_latency_detection ();
3145 return ArdourDialog::on_delete_event (ev);
3149 EngineControl::engine_running ()
3151 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3154 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3155 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3157 if (backend->can_set_period_size ()) {
3158 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3161 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3162 connect_disconnect_button.show();
3164 started_at_least_once = true;
3165 if (_have_control) {
3166 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3168 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3170 update_sensitivity();
3174 EngineControl::engine_stopped ()
3176 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3179 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3180 connect_disconnect_button.show();
3182 if (_have_control) {
3183 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3185 engine_status.set_markup(X_(""));
3188 update_sensitivity();
3192 EngineControl::device_list_changed ()
3194 if (ignore_device_changes) {
3197 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3198 if (!ARDOUR::AudioEngine::instance()->running()) {
3202 midi_option_changed();
3204 if (notebook.get_current_page() == midi_tab) {
3205 if (_midi_devices.empty ()) {
3206 notebook.set_current_page (0);
3208 refresh_midi_display ();
3214 EngineControl::connect_disconnect_click()
3216 if (ARDOUR::AudioEngine::instance()->running()) {
3219 if (!ARDOUR_UI::instance()->the_session ()) {
3225 if (!ARDOUR_UI::instance()->the_session ()) {
3226 ArdourDialog::response (RESPONSE_OK);
3232 EngineControl::calibrate_audio_latency ()
3234 _measure_midi.reset ();
3235 have_lm_results = false;
3236 lm_use_button.set_sensitive (false);
3237 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3238 notebook.set_current_page (latency_tab);
3242 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3245 have_lm_results = false;
3246 lm_use_button.set_sensitive (false);
3247 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3248 notebook.set_current_page (latency_tab);
3252 EngineControl::configure_midi_devices ()
3254 notebook.set_current_page (midi_tab);