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 <gtkmm/messagedialog.h>
34 #include "pbd/error.h"
35 #include "pbd/locale_guard.h"
36 #include "pbd/xml++.h"
37 #include "pbd/unwind.h"
38 #include "pbd/failed_constructor.h"
40 #include <gtkmm/alignment.h>
41 #include <gtkmm/stock.h>
42 #include <gtkmm/notebook.h>
43 #include <gtkmm2ext/utils.h>
45 #include "widgets/tooltips.h"
47 #include "ardour/audio_backend.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/mtdm.h"
50 #include "ardour/mididm.h"
51 #include "ardour/rc_configuration.h"
52 #include "ardour/types.h"
53 #include "ardour/profile.h"
55 #include "pbd/convert.h"
56 #include "pbd/error.h"
60 #include "ardour_ui.h"
61 #include "engine_dialog.h"
62 #include "gui_thread.h"
63 #include "ui_config.h"
64 #include "public_editor.h"
71 using namespace Gtkmm2ext;
74 using namespace ArdourWidgets;
75 using namespace ARDOUR_UI_UTILS;
77 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
79 static const unsigned int midi_tab = 2;
80 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
82 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
84 EngineControl::EngineControl ()
85 : ArdourDialog (_("Audio/MIDI Setup"))
88 , input_latency_adjustment (0, 0, 99999, 1)
89 , input_latency (input_latency_adjustment)
90 , output_latency_adjustment (0, 0, 99999, 1)
91 , output_latency (output_latency_adjustment)
92 , input_channels_adjustment (0, 0, 256, 1)
93 , input_channels (input_channels_adjustment)
94 , output_channels_adjustment (0, 0, 256, 1)
95 , output_channels (output_channels_adjustment)
96 , ports_adjustment (128, 8, 1024, 1, 16)
97 , ports_spinner (ports_adjustment)
98 , control_app_button (_("Device Control Panel"))
99 , midi_devices_button (_("Midi Device Setup"))
100 , start_stop_button (_("Stop"))
101 , update_devices_button (_("Refresh Devices"))
102 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
103 , try_autostart_button (_("Autostart"), ArdourButton::led_default_elements)
104 , lm_measure_label (_("Measure"))
105 , lm_use_button (_("Use results"))
106 , lm_back_button (_("Back to settings ... (ignore results)"))
107 , lm_button_audio (_("Calibrate Audio"))
109 , have_lm_results (false)
111 , midi_back_button (_("Back to settings"))
113 , ignore_device_changes (0)
114 , _desired_sample_rate (0)
115 , started_at_least_once (false)
116 , queue_device_changed (false)
117 , _have_control (true)
120 using namespace Notebook_Helpers;
121 vector<string> backend_names;
123 AttachOptions xopt = AttachOptions (FILL|EXPAND);
126 set_name (X_("AudioMIDISetup"));
128 /* the backend combo is the one thing that is ALWAYS visible */
130 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
132 if (backends.empty()) {
133 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
135 throw failed_constructor ();
138 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
139 backend_names.push_back ((*b)->name);
142 set_popdown_strings (backend_combo, backend_names);
144 /* setup basic packing characteristics for the table used on the main
145 * tab of the notebook
148 basic_packer.set_spacings (6);
149 basic_packer.set_border_width (12);
150 basic_packer.set_homogeneous (false);
154 basic_hbox.pack_start (basic_packer, false, false);
156 /* latency measurement tab */
158 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
161 lm_table.set_row_spacings (12);
162 lm_table.set_col_spacings (6);
163 lm_table.set_homogeneous (false);
165 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
168 lm_preamble.set_width_chars (60);
169 lm_preamble.set_line_wrap (true);
170 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
172 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
175 Gtk::Label* preamble;
176 preamble = manage (new Label);
177 preamble->set_width_chars (60);
178 preamble->set_line_wrap (true);
179 preamble->set_markup (_("Select two channels below and connect them using a cable."));
181 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
184 label = manage (new Label (_("Output channel:")));
185 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
187 lm_output_channel_list = Gtk::ListStore::create (lm_output_channel_cols);
188 lm_output_channel_combo.set_model (lm_output_channel_list);
189 lm_output_channel_combo.pack_start (lm_output_channel_cols.pretty_name);
191 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
192 misc_align->add (lm_output_channel_combo);
193 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
196 label = manage (new Label (_("Input channel:")));
197 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
199 lm_input_channel_list = Gtk::ListStore::create (lm_input_channel_cols);
200 lm_input_channel_combo.set_model (lm_input_channel_list);
201 lm_input_channel_combo.pack_start (lm_input_channel_cols.pretty_name);
203 misc_align = manage (new Alignment (0.0, 0.5));
204 misc_align->add (lm_input_channel_combo);
205 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
208 lm_measure_label.set_padding (10, 10);
209 lm_measure_button.add (lm_measure_label);
210 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
211 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
212 lm_back_button_signal = lm_back_button.signal_clicked().connect(
213 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
215 lm_use_button.set_sensitive (false);
217 /* Increase the default spacing around the labels of these three
223 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
224 l->set_padding (10, 10);
227 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
228 l->set_padding (10, 10);
231 preamble = manage (new Label);
232 preamble->set_width_chars (60);
233 preamble->set_line_wrap (true);
234 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
235 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
238 preamble = manage (new Label);
239 preamble->set_width_chars (60);
240 preamble->set_line_wrap (true);
241 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
242 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
244 ++row; // skip a row in the table
245 ++row; // skip a row in the table
247 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
249 ++row; // skip a row in the table
250 ++row; // skip a row in the table
252 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
253 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
254 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
256 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
258 lm_vbox.set_border_width (12);
259 lm_vbox.pack_start (lm_table, false, false);
261 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
265 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
266 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
267 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
268 notebook.set_border_width (12);
270 notebook.set_show_tabs (false);
271 notebook.show_all ();
273 notebook.set_name ("SettingsNotebook");
275 /* packup the notebook */
277 get_vbox()->set_border_width (12);
278 get_vbox()->pack_start (notebook);
280 /* need a special function to print "all available channels" when the
281 * channel counts hit zero.
284 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
285 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
287 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
288 midi_devices_button.set_name ("generic button");
289 midi_devices_button.set_can_focus(true);
291 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
292 control_app_button.set_name ("generic button");
293 control_app_button.set_can_focus(true);
294 manage_control_app_sensitivity ();
296 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
297 start_stop_button.set_sensitive (false);
298 start_stop_button.set_name ("generic button");
299 start_stop_button.set_can_focus(true);
300 start_stop_button.set_can_default(true);
301 start_stop_button.set_act_on_release (false);
303 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
304 update_devices_button.set_sensitive (false);
305 update_devices_button.set_name ("generic button");
306 update_devices_button.set_can_focus(true);
308 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
309 use_buffered_io_button.set_sensitive (false);
310 use_buffered_io_button.set_name ("generic button");
311 use_buffered_io_button.set_can_focus(true);
313 try_autostart_button.signal_clicked.connect (mem_fun (*this, &EngineControl::try_autostart_button_clicked));
314 try_autostart_button.set_name ("generic button");
315 try_autostart_button.set_can_focus(true);
316 config_parameter_changed ("try-autostart-engine");
317 set_tooltip (try_autostart_button,
318 string_compose (_("Always try these settings when starting %1, if the same device is available"), PROGRAM_NAME));
320 ARDOUR::Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&EngineControl::config_parameter_changed, this, _1), gui_context());
322 /* Pick up any existing audio setup configuration, if appropriate */
324 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
326 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
327 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
328 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
329 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
332 if (!set_state (*audio_setup)) {
333 set_default_state ();
336 set_default_state ();
339 update_sensitivity ();
340 connect_changed_signals ();
342 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
344 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
346 connect_disconnect_button.set_no_show_all();
347 start_stop_button.set_no_show_all();
351 EngineControl::connect_changed_signals ()
353 backend_combo_connection = backend_combo.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::backend_changed));
355 driver_combo_connection = driver_combo.signal_changed ().connect (
356 sigc::mem_fun (*this, &EngineControl::driver_changed));
357 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
358 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
359 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
360 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
361 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
362 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
363 device_combo_connection = device_combo.signal_changed ().connect (
364 sigc::mem_fun (*this, &EngineControl::device_changed));
365 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
366 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
368 input_device_combo_connection = input_device_combo.signal_changed ().connect (
369 sigc::mem_fun (*this, &EngineControl::input_device_changed));
370 output_device_combo_connection = output_device_combo.signal_changed ().connect (
371 sigc::mem_fun (*this, &EngineControl::output_device_changed));
373 input_latency_connection = input_latency.signal_changed ().connect (
374 sigc::mem_fun (*this, &EngineControl::parameter_changed));
375 output_latency_connection = output_latency.signal_changed ().connect (
376 sigc::mem_fun (*this, &EngineControl::parameter_changed));
377 input_channels_connection = input_channels.signal_changed ().connect (
378 sigc::mem_fun (*this, &EngineControl::parameter_changed));
379 output_channels_connection = output_channels.signal_changed ().connect (
380 sigc::mem_fun (*this, &EngineControl::parameter_changed));
384 EngineControl::block_changed_signals ()
386 if (block_signals++ == 0) {
387 DEBUG_ECONTROL ("Blocking changed signals");
388 backend_combo_connection.block ();
389 driver_combo_connection.block ();
390 sample_rate_combo_connection.block ();
391 buffer_size_combo_connection.block ();
392 nperiods_combo_connection.block ();
393 device_combo_connection.block ();
394 input_device_combo_connection.block ();
395 output_device_combo_connection.block ();
396 midi_option_combo_connection.block ();
397 input_latency_connection.block ();
398 output_latency_connection.block ();
399 input_channels_connection.block ();
400 output_channels_connection.block ();
405 EngineControl::unblock_changed_signals ()
407 if (--block_signals == 0) {
408 DEBUG_ECONTROL ("Unblocking changed signals");
409 backend_combo_connection.unblock ();
410 driver_combo_connection.unblock ();
411 sample_rate_combo_connection.unblock ();
412 buffer_size_combo_connection.unblock ();
413 nperiods_combo_connection.unblock ();
414 device_combo_connection.unblock ();
415 input_device_combo_connection.unblock ();
416 output_device_combo_connection.unblock ();
417 midi_option_combo_connection.unblock ();
418 input_latency_connection.unblock ();
419 output_latency_connection.unblock ();
420 input_channels_connection.unblock ();
421 output_channels_connection.unblock ();
425 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
426 const std::string& reason)
427 : ec (engine_control)
430 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
431 ec.block_changed_signals ();
434 EngineControl::SignalBlocker::~SignalBlocker ()
436 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
437 ec.unblock_changed_signals ();
441 EngineControl::on_show ()
443 ArdourDialog::on_show ();
444 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
445 // re-check _have_control (jackd running) see #6041
449 start_stop_button.grab_focus();
453 EngineControl::on_map ()
455 if (!ARDOUR_UI::instance()->the_session () && !PublicEditor::_instance) {
456 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
457 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
458 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
460 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
462 ArdourDialog::on_map ();
466 EngineControl::config_parameter_changed (std::string const & p)
468 if (p == "try-autostart-engine") {
469 try_autostart_button.set_active (ARDOUR::Config->get_try_autostart_engine ());
474 EngineControl::try_autostart ()
476 if (!start_stop_button.get_sensitive()) {
479 if (ARDOUR::AudioEngine::instance()->running()) {
482 return start_engine ();
486 EngineControl::start_engine ()
488 if (push_state_to_backend(true) != 0) {
489 MessageDialog msg(*this,
490 ARDOUR::AudioEngine::instance()->get_last_backend_error());
498 EngineControl::stop_engine (bool for_latency)
500 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
501 MessageDialog msg(*this,
502 ARDOUR::AudioEngine::instance()->get_last_backend_error());
510 EngineControl::build_notebook ()
513 AttachOptions xopt = AttachOptions (FILL|EXPAND);
515 /* clear the table */
517 Gtkmm2ext::container_clear (basic_vbox);
518 Gtkmm2ext::container_clear (basic_packer);
520 if (control_app_button.get_parent()) {
521 control_app_button.get_parent()->remove (control_app_button);
524 label = manage (left_aligned_label (_("Audio System:")));
525 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
526 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
528 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
529 engine_status.show();
531 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
533 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
534 lm_button_audio.set_name ("generic button");
535 lm_button_audio.set_can_focus(true);
538 build_full_control_notebook ();
540 build_no_control_notebook ();
543 basic_vbox.pack_start (basic_hbox, false, false);
546 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
547 basic_vbox.show_all ();
552 EngineControl::build_full_control_notebook ()
554 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
557 using namespace Notebook_Helpers;
559 vector<string> strings;
560 AttachOptions xopt = AttachOptions (FILL|EXPAND);
561 int row = 1; // row zero == backend combo
562 int btn = 1; // row zero == start_stop_button
563 bool autostart_packed = false;
565 /* start packing it up */
567 if (backend->requires_driver_selection()) {
568 label = manage (left_aligned_label (_("Driver:")));
569 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
570 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 if (backend->use_separate_input_and_output_devices()) {
575 label = manage (left_aligned_label (_("Input Device:")));
576 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
577 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
579 label = manage (left_aligned_label (_("Output Device:")));
580 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
581 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
583 // reset so it isn't used in state comparisons
584 device_combo.set_active_text ("");
586 label = manage (left_aligned_label (_("Device:")));
587 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
588 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
590 // reset these so they don't get used in state comparisons
591 input_device_combo.set_active_text ("");
592 output_device_combo.set_active_text ("");
595 /* same line as Driver */
596 if (backend->can_use_buffered_io()) {
597 basic_packer.attach (use_buffered_io_button, 3, 4, btn, btn + 1, xopt, xopt);
601 /* same line as Device(s) */
602 if (backend->can_request_update_devices()) {
603 basic_packer.attach (update_devices_button, 3, 4, btn, btn + 1, xopt, xopt);
607 /* prefer "try autostart" below "Start" if possible */
609 basic_packer.attach (try_autostart_button, 3, 4, btn, btn + 1, xopt, xopt);
611 autostart_packed = true;
614 label = manage (left_aligned_label (_("Sample rate:")));
615 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
616 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
619 label = manage (left_aligned_label (_("Buffer size:")));
620 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
621 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
622 buffer_size_duration_label.set_alignment (0.0); /* left-align */
623 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
625 int ctrl_btn_span = 1;
626 if (backend->can_set_period_size ()) {
628 label = manage (left_aligned_label (_("Periods:")));
629 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
630 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
634 /* button spans 2 or 3 rows: Sample rate, Buffer size, Periods */
635 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
638 input_channels.set_name ("InputChannels");
639 input_channels.set_flags (Gtk::CAN_FOCUS);
640 input_channels.set_digits (0);
641 input_channels.set_wrap (false);
642 output_channels.set_editable (true);
644 if (!ARDOUR::Profile->get_mixbus()) {
645 label = manage (left_aligned_label (_("Input channels:")));
646 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
647 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
651 output_channels.set_name ("OutputChannels");
652 output_channels.set_flags (Gtk::CAN_FOCUS);
653 output_channels.set_digits (0);
654 output_channels.set_wrap (false);
655 output_channels.set_editable (true);
657 if (!ARDOUR::Profile->get_mixbus()) {
658 label = manage (left_aligned_label (_("Output channels:")));
659 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
660 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
664 /* Prefere next available vertical slot, 1 row */
666 basic_packer.attach (try_autostart_button, 3, 4, btn, btn + 1, xopt, xopt);
668 autostart_packed = true;
671 input_latency.set_name ("InputLatency");
672 input_latency.set_flags (Gtk::CAN_FOCUS);
673 input_latency.set_digits (0);
674 input_latency.set_wrap (false);
675 input_latency.set_editable (true);
677 label = manage (left_aligned_label (_("Hardware input latency:")));
678 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
679 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
680 label = manage (left_aligned_label (_("samples")));
681 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
684 output_latency.set_name ("OutputLatency");
685 output_latency.set_flags (Gtk::CAN_FOCUS);
686 output_latency.set_digits (0);
687 output_latency.set_wrap (false);
688 output_latency.set_editable (true);
690 label = manage (left_aligned_label (_("Hardware output latency:")));
691 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
692 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
693 label = manage (left_aligned_label (_("samples")));
694 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
696 /* button spans 2 rows */
698 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
701 label = manage (left_aligned_label (_("MIDI System:")));
702 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
703 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
704 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
707 if (!autostart_packed) {
708 basic_packer.attach (try_autostart_button, 3, 4, row, row+1, xopt, xopt);
713 EngineControl::build_no_control_notebook ()
715 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
718 using namespace Notebook_Helpers;
720 vector<string> strings;
721 AttachOptions xopt = AttachOptions (FILL|EXPAND);
722 int row = 1; // row zero == backend combo
723 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
725 label = manage (new Label);
726 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
727 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
730 if (backend->can_change_sample_rate_when_running()) {
731 label = manage (left_aligned_label (_("Sample rate:")));
732 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
733 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
737 if (backend->can_change_buffer_size_when_running()) {
738 label = manage (left_aligned_label (_("Buffer size:")));
739 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
740 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
741 buffer_size_duration_label.set_alignment (0.0); /* left-align */
742 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
746 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
750 EngineControl::~EngineControl ()
752 ignore_changes = true;
756 EngineControl::disable_latency_tab ()
758 lm_input_channel_list->clear ();
759 lm_output_channel_list->clear ();
760 lm_measure_button.set_sensitive (false);
761 lm_use_button.set_sensitive (false);
765 EngineControl::enable_latency_tab ()
767 vector<string> outputs;
768 vector<string> inputs;
770 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
771 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
772 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
774 if (!ARDOUR::AudioEngine::instance()->running()) {
775 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
776 notebook.set_current_page (0);
780 else if (inputs.empty() || outputs.empty()) {
781 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
782 notebook.set_current_page (0);
787 lm_back_button_signal.disconnect();
789 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
792 lm_back_button_signal = lm_back_button.signal_clicked().connect(
793 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
797 lm_output_channel_list->clear ();
798 for (vector<string>::const_iterator i = outputs.begin(); i != outputs.end(); ++i) {
799 Gtk::TreeModel::iterator iter = lm_output_channel_list->append ();
800 Gtk::TreeModel::Row row = *iter;
801 row[lm_output_channel_cols.port_name] = *i;
802 std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*i);
804 pn = (*i).substr ((*i).find (':') + 1);
806 row[lm_output_channel_cols.pretty_name] = pn;
808 lm_output_channel_combo.set_active (0);
809 lm_output_channel_combo.set_sensitive (true);
811 lm_input_channel_list->clear ();
812 for (vector<string>::const_iterator i = inputs.begin(); i != inputs.end(); ++i) {
813 Gtk::TreeModel::iterator iter = lm_input_channel_list->append ();
814 Gtk::TreeModel::Row row = *iter;
815 row[lm_input_channel_cols.port_name] = *i;
816 std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*i);
818 pn = (*i).substr ((*i).find (':') + 1);
820 row[lm_input_channel_cols.pretty_name] = pn;
822 lm_input_channel_combo.set_active (0);
823 lm_input_channel_combo.set_sensitive (true);
825 lm_measure_button.set_sensitive (true);
829 EngineControl::setup_midi_tab_for_backend ()
831 string backend = backend_combo.get_active_text ();
833 Gtkmm2ext::container_clear (midi_vbox);
835 midi_vbox.set_border_width (12);
836 midi_device_table.set_border_width (12);
838 if (backend == "JACK") {
839 setup_midi_tab_for_jack ();
842 midi_vbox.pack_start (midi_device_table, true, true);
843 midi_vbox.pack_start (midi_back_button, false, false);
844 midi_vbox.show_all ();
848 EngineControl::update_sensitivity ()
850 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
852 start_stop_button.set_sensitive (false);
857 size_t devices_available = 0;
858 bool engine_running = ARDOUR::AudioEngine::instance()->running();
860 if (backend->use_separate_input_and_output_devices ()) {
861 devices_available += get_popdown_string_count (input_device_combo);
862 devices_available += get_popdown_string_count (output_device_combo);
864 devices_available += get_popdown_string_count (device_combo);
867 if (devices_available == 0) {
869 input_latency.set_sensitive (false);
870 output_latency.set_sensitive (false);
871 input_channels.set_sensitive (false);
872 output_channels.set_sensitive (false);
874 input_latency.set_sensitive (true);
875 output_latency.set_sensitive (true);
876 input_channels.set_sensitive (!engine_running);
877 output_channels.set_sensitive (!engine_running);
880 if (get_popdown_string_count (buffer_size_combo) > 0) {
881 if (!engine_running) {
882 buffer_size_combo.set_sensitive (valid);
883 } else if (backend->can_change_buffer_size_when_running ()) {
884 buffer_size_combo.set_sensitive (valid || !_have_control);
886 buffer_size_combo.set_sensitive (false);
889 buffer_size_combo.set_sensitive (false);
893 if (get_popdown_string_count (sample_rate_combo) > 0) {
894 bool allow_to_set_rate = false;
895 if (!engine_running) {
896 if (!ARDOUR_UI::instance()->the_session ()) {
897 // engine is not running, no session loaded -> anything goes.
898 allow_to_set_rate = true;
899 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
900 // only allow to change if the current setting is not the native session rate.
901 allow_to_set_rate = true;
904 sample_rate_combo.set_sensitive (allow_to_set_rate);
906 sample_rate_combo.set_sensitive (false);
910 if (get_popdown_string_count (nperiods_combo) > 0) {
911 if (!engine_running) {
912 nperiods_combo.set_sensitive (true);
914 nperiods_combo.set_sensitive (false);
917 nperiods_combo.set_sensitive (false);
921 start_stop_button.set_sensitive(true);
922 start_stop_button.show();
923 if (engine_running) {
924 start_stop_button.set_text("Stop");
925 update_devices_button.set_sensitive(false);
926 use_buffered_io_button.set_sensitive(false);
928 start_stop_button.set_text("Start");
929 update_devices_button.set_sensitive (backend->can_request_update_devices ());
930 use_buffered_io_button.set_sensitive (backend->can_use_buffered_io ());
933 start_stop_button.set_sensitive(false);
934 start_stop_button.hide();
937 if (engine_running && _have_control) {
938 input_device_combo.set_sensitive (false);
939 output_device_combo.set_sensitive (false);
940 device_combo.set_sensitive (false);
941 driver_combo.set_sensitive (false);
943 input_device_combo.set_sensitive (true);
944 output_device_combo.set_sensitive (true);
945 device_combo.set_sensitive (true);
946 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
947 driver_combo.set_sensitive (true);
949 driver_combo.set_sensitive (false);
953 midi_option_combo.set_sensitive (!engine_running);
957 EngineControl::setup_midi_tab_for_jack ()
962 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
964 device->input_latency = a->get_value();
966 device->output_latency = a->get_value();
969 if (ARDOUR::AudioEngine::instance()->running() && !_measure_midi) {
970 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
972 if (backend->can_change_systemic_latency_when_running () && device->enabled) {
974 backend->set_systemic_midi_input_latency (device->name, device->input_latency);
976 backend->set_systemic_midi_output_latency (device->name, device->output_latency);
983 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
984 b->set_active (!b->get_active());
985 device->enabled = b->get_active();
986 refresh_midi_display(device->name);
988 if (ARDOUR::AudioEngine::instance()->running()) {
989 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
991 backend->set_midi_device_enabled (device->name, device->enabled);
992 if (backend->can_change_systemic_latency_when_running () && device->enabled) {
993 backend->set_systemic_midi_input_latency (device->name, device->input_latency);
994 backend->set_systemic_midi_output_latency (device->name, device->output_latency);
1000 EngineControl::refresh_midi_display (std::string focus)
1002 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1006 AttachOptions xopt = AttachOptions (FILL|EXPAND);
1009 Gtkmm2ext::container_clear (midi_device_table);
1011 midi_device_table.set_spacings (6);
1013 l = manage (new Label);
1014 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
1015 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
1016 l->set_alignment (0.5, 0.5);
1020 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
1021 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
1022 l = manage (new Label (_("Systemic Latency [samples]"))); l->show (); l->set_alignment (0.5, 0.5);
1023 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
1025 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
1026 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
1027 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
1028 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
1031 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1036 bool enabled = (*p)->enabled;
1038 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
1039 m->set_name ("midi device");
1040 m->set_can_focus (Gtk::CAN_FOCUS);
1041 m->add_events (Gdk::BUTTON_RELEASE_MASK);
1042 m->set_active (enabled);
1043 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
1044 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
1045 if ((*p)->name == focus) {
1049 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1050 s = manage (new Gtk::SpinButton (*a));
1051 a->set_value ((*p)->input_latency);
1052 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1053 s->set_sensitive (_can_set_midi_latencies && enabled);
1054 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1056 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1057 s = manage (new Gtk::SpinButton (*a));
1058 a->set_value ((*p)->output_latency);
1059 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1060 s->set_sensitive (_can_set_midi_latencies && enabled);
1061 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1063 b = manage (new Button (_("Calibrate")));
1064 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1065 b->set_sensitive (_can_set_midi_latencies && enabled);
1066 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1073 EngineControl::backend_changed ()
1075 SignalBlocker blocker (*this, "backend_changed");
1076 string backend_name = backend_combo.get_active_text();
1077 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1079 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1080 /* eh? setting the backend failed... how ? */
1081 /* A: stale config contains a backend that does not exist in current build */
1085 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1087 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1090 setup_midi_tab_for_backend ();
1091 _midi_devices.clear();
1093 if (backend->requires_driver_selection()) {
1094 if (set_driver_popdown_strings ()) {
1098 /* this will change the device text which will cause a call to
1099 * device changed which will set up parameters
1104 update_midi_options ();
1106 connect_disconnect_button.hide();
1108 midi_option_changed();
1110 started_at_least_once = false;
1112 /* changing the backend implies stopping the engine
1113 * ARDOUR::AudioEngine() may or may not emit this signal
1114 * depending on previous engine state
1116 engine_stopped (); // set "active/inactive"
1118 if (!_have_control) {
1119 // set settings from backend that we do have control over
1120 set_buffersize_popdown_strings ();
1121 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1124 if (_have_control && !ignore_changes) {
1125 // set driver & devices
1126 State state = get_matching_state (backend_combo.get_active_text());
1128 DEBUG_ECONTROL ("backend-changed(): found prior state for backend");
1129 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1130 set_current_state (state);
1132 DEBUG_ECONTROL ("backend-changed(): no prior state for backend");
1135 DEBUG_ECONTROL (string_compose ("backend-changed(): _have_control=%1 ignore_changes=%2", _have_control, ignore_changes));
1138 if (!ignore_changes) {
1139 maybe_display_saved_state ();
1144 EngineControl::update_midi_options ()
1146 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1147 vector<string> midi_options = backend->enumerate_midi_options();
1149 if (midi_options.size() == 1) {
1150 /* only contains the "none" option */
1151 set_popdown_strings (midi_option_combo, midi_options);
1152 midi_option_combo.set_sensitive (false);
1154 if (_have_control) {
1155 set_popdown_strings (midi_option_combo, midi_options);
1156 midi_option_combo.set_active_text (midi_options.front());
1157 midi_option_combo.set_sensitive (true);
1159 midi_option_combo.set_sensitive (false);
1165 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1167 if (ARDOUR::Profile->get_mixbus()) {
1171 uint32_t cnt = (uint32_t) sb->get_value();
1173 sb->set_text (_("all available channels"));
1176 snprintf (buf, sizeof (buf), "%d", cnt);
1182 // @return true if there are drivers available
1184 EngineControl::set_driver_popdown_strings ()
1186 DEBUG_ECONTROL ("set_driver_popdown_strings");
1187 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1188 vector<string> drivers = backend->enumerate_drivers();
1190 if (drivers.empty ()) {
1191 // This is an error...?
1195 string current_driver = backend->driver_name ();
1197 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1199 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1202 current_driver = drivers.front ();
1205 set_popdown_strings (driver_combo, drivers);
1207 string_compose ("driver_combo.set_active_text: %1", current_driver));
1208 driver_combo.set_active_text (current_driver);
1213 EngineControl::get_default_device(const string& current_device_name,
1214 const vector<string>& available_devices)
1216 // If the current device is available, use it as default
1217 if (std::find (available_devices.begin (),
1218 available_devices.end (),
1219 current_device_name) != available_devices.end ()) {
1221 return current_device_name;
1224 using namespace ARDOUR;
1226 string default_device_name =
1227 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1229 vector<string>::const_iterator i;
1231 // If there is a "Default" device available, use it
1232 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1233 if (*i == default_device_name) {
1238 string none_device_name =
1239 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1241 // Use the first device that isn't "None"
1242 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1243 if (*i != none_device_name) {
1248 // Use "None" if there are no other available
1249 return available_devices.front();
1252 // @return true if there are devices available
1254 EngineControl::set_device_popdown_strings ()
1256 DEBUG_ECONTROL ("set_device_popdown_strings");
1257 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1258 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1260 /* NOTE: Ardour currently does not display the "available" field of the
1263 * Doing so would require a different GUI widget than the combo
1264 * box/popdown that we currently use, since it has no way to list
1265 * items that are not selectable. Something more like a popup menu,
1266 * which could have unselectable items, would be appropriate.
1269 vector<string> available_devices;
1271 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1272 available_devices.push_back (i->name);
1275 if (available_devices.empty ()) {
1279 set_popdown_strings (device_combo, available_devices);
1281 std::string default_device =
1282 get_default_device(backend->device_name(), available_devices);
1285 string_compose ("set device_combo active text: %1", default_device));
1287 device_combo.set_active_text(default_device);
1291 // @return true if there are input devices available
1293 EngineControl::set_input_device_popdown_strings ()
1295 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1296 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1297 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1299 vector<string> available_devices;
1301 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1302 available_devices.push_back (i->name);
1305 if (available_devices.empty()) {
1309 set_popdown_strings (input_device_combo, available_devices);
1311 std::string default_device =
1312 get_default_device(backend->input_device_name(), available_devices);
1315 string_compose ("set input_device_combo active text: %1", default_device));
1316 input_device_combo.set_active_text(default_device);
1320 // @return true if there are output devices available
1322 EngineControl::set_output_device_popdown_strings ()
1324 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1325 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1326 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1328 vector<string> available_devices;
1330 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1331 available_devices.push_back (i->name);
1334 if (available_devices.empty()) {
1338 set_popdown_strings (output_device_combo, available_devices);
1340 std::string default_device =
1341 get_default_device(backend->output_device_name(), available_devices);
1344 string_compose ("set output_device_combo active text: %1", default_device));
1345 output_device_combo.set_active_text(default_device);
1350 EngineControl::list_devices ()
1352 DEBUG_ECONTROL ("list_devices");
1353 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1356 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1358 bool devices_available = false;
1360 if (backend->use_separate_input_and_output_devices ()) {
1361 bool input_devices_available = set_input_device_popdown_strings ();
1362 bool output_devices_available = set_output_device_popdown_strings ();
1363 devices_available = input_devices_available || output_devices_available;
1365 devices_available = set_device_popdown_strings ();
1368 if (devices_available) {
1371 device_combo.clear();
1372 input_device_combo.clear();
1373 output_device_combo.clear();
1375 update_sensitivity ();
1379 EngineControl::driver_changed ()
1381 SignalBlocker blocker (*this, "driver_changed");
1382 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1385 backend->set_driver (driver_combo.get_active_text());
1388 // TODO load LRU device(s) for backend + driver combo
1390 if (!ignore_changes) {
1391 maybe_display_saved_state ();
1396 EngineControl::get_sample_rates_for_all_devices ()
1398 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1399 ARDOUR::AudioEngine::instance ()->current_backend ();
1400 vector<float> all_rates;
1402 if (backend->use_separate_input_and_output_devices ()) {
1403 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1405 all_rates = backend->available_sample_rates (get_device_name ());
1411 EngineControl::get_default_sample_rates ()
1413 vector<float> rates;
1414 rates.push_back (8000.0f);
1415 rates.push_back (16000.0f);
1416 rates.push_back (32000.0f);
1417 rates.push_back (44100.0f);
1418 rates.push_back (48000.0f);
1419 rates.push_back (88200.0f);
1420 rates.push_back (96000.0f);
1421 rates.push_back (192000.0f);
1422 rates.push_back (384000.0f);
1427 EngineControl::set_samplerate_popdown_strings ()
1429 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1430 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1435 if (_have_control) {
1436 sr = get_sample_rates_for_all_devices ();
1438 sr = get_default_sample_rates ();
1441 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1442 s.push_back (rate_as_string (*x));
1443 if (*x == _desired_sample_rate) {
1448 set_popdown_strings (sample_rate_combo, s);
1451 if (ARDOUR::AudioEngine::instance()->running()) {
1452 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1453 } else if (ARDOUR_UI::instance()->the_session ()) {
1454 float active_sr = ARDOUR_UI::instance()->the_session()->nominal_sample_rate ();
1456 if (std::find (sr.begin (), sr.end (), active_sr) == sr.end ()) {
1457 active_sr = sr.front ();
1460 sample_rate_combo.set_active_text (rate_as_string (active_sr));
1461 } else if (desired.empty ()) {
1462 float new_active_sr = backend->default_sample_rate ();
1464 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1465 new_active_sr = sr.front ();
1468 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1470 sample_rate_combo.set_active_text (desired);
1473 update_sensitivity ();
1477 EngineControl::get_buffer_sizes_for_all_devices ()
1479 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1480 ARDOUR::AudioEngine::instance ()->current_backend ();
1481 vector<uint32_t> all_sizes;
1483 if (backend->use_separate_input_and_output_devices ()) {
1484 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1486 all_sizes = backend->available_buffer_sizes (get_device_name ());
1492 EngineControl::get_default_buffer_sizes ()
1494 vector<uint32_t> sizes;
1495 sizes.push_back (8);
1496 sizes.push_back (16);
1497 sizes.push_back (32);
1498 sizes.push_back (64);
1499 sizes.push_back (128);
1500 sizes.push_back (256);
1501 sizes.push_back (512);
1502 sizes.push_back (1024);
1503 sizes.push_back (2048);
1504 sizes.push_back (4096);
1505 sizes.push_back (8192);
1510 EngineControl::set_buffersize_popdown_strings ()
1512 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1513 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1514 vector<uint32_t> bs;
1517 if (_have_control) {
1518 bs = get_buffer_sizes_for_all_devices ();
1519 } else if (backend->can_change_buffer_size_when_running()) {
1520 bs = get_default_buffer_sizes ();
1523 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1524 s.push_back (bufsize_as_string (*x));
1527 uint32_t previous_size = backend->buffer_size ();
1528 if (!buffer_size_combo.get_active_text().empty()) {
1529 previous_size = get_buffer_size ();
1532 set_popdown_strings (buffer_size_combo, s);
1536 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1537 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1540 buffer_size_combo.set_active_text(s.front());
1542 uint32_t period = backend->buffer_size();
1543 if (0 == period && backend->use_separate_input_and_output_devices()) {
1544 period = backend->default_buffer_size(get_input_device_name());
1546 if (0 == period && backend->use_separate_input_and_output_devices()) {
1547 period = backend->default_buffer_size(get_output_device_name());
1549 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1550 period = backend->default_buffer_size(get_device_name());
1553 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1555 show_buffer_duration ();
1557 update_sensitivity ();
1561 EngineControl::set_nperiods_popdown_strings ()
1563 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1564 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1565 vector<uint32_t> np;
1568 if (backend->can_set_period_size()) {
1569 np = backend->available_period_sizes (get_driver());
1572 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1573 s.push_back (to_string (*x));
1576 set_popdown_strings (nperiods_combo, s);
1579 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1582 update_sensitivity ();
1586 EngineControl::device_changed ()
1588 SignalBlocker blocker (*this, "device_changed");
1589 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1592 string device_name_in;
1593 string device_name_out; // only used if backend support separate I/O devices
1595 if (backend->use_separate_input_and_output_devices()) {
1596 device_name_in = get_input_device_name ();
1597 device_name_out = get_output_device_name ();
1599 device_name_in = get_device_name ();
1602 /* we set the backend-device to query various device related intormation.
1603 * This has the side effect that backend->device_name() will match
1604 * the device_name and 'change_device' will never be true.
1605 * so work around this by setting...
1607 if (backend->use_separate_input_and_output_devices()) {
1608 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1609 queue_device_changed = true;
1612 if (device_name_in != backend->device_name()) {
1613 queue_device_changed = true;
1617 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1618 if (backend->use_separate_input_and_output_devices()) {
1619 backend->set_input_device_name (device_name_in);
1620 backend->set_output_device_name (device_name_out);
1622 backend->set_device_name(device_name_in);
1626 /* don't allow programmatic change to combos to cause a
1627 recursive call to this method.
1629 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1631 set_samplerate_popdown_strings ();
1632 set_buffersize_popdown_strings ();
1633 set_nperiods_popdown_strings ();
1635 /* TODO set min + max channel counts here */
1637 manage_control_app_sensitivity ();
1640 /* pick up any saved state for this device */
1642 if (!ignore_changes) {
1643 maybe_display_saved_state ();
1648 EngineControl::input_device_changed ()
1650 DEBUG_ECONTROL ("input_device_changed");
1652 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1653 if (backend && backend->match_input_output_devices_or_none ()) {
1654 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1656 if (get_output_device_name () != dev_none
1657 && get_input_device_name () != dev_none
1658 && get_input_device_name () != get_output_device_name ()) {
1659 block_changed_signals ();
1660 if (contains_value (output_device_combo, get_input_device_name ())) {
1661 output_device_combo.set_active_text (get_input_device_name ());
1663 assert (contains_value (output_device_combo, dev_none));
1664 output_device_combo.set_active_text (dev_none);
1666 unblock_changed_signals ();
1673 EngineControl::output_device_changed ()
1675 DEBUG_ECONTROL ("output_device_changed");
1676 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1677 if (backend && backend->match_input_output_devices_or_none ()) {
1678 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1680 if (get_input_device_name () != dev_none
1681 && get_input_device_name () != dev_none
1682 && get_input_device_name () != get_output_device_name ()) {
1683 block_changed_signals ();
1684 if (contains_value (input_device_combo, get_output_device_name ())) {
1685 input_device_combo.set_active_text (get_output_device_name ());
1687 assert (contains_value (input_device_combo, dev_none));
1688 input_device_combo.set_active_text (dev_none);
1690 unblock_changed_signals ();
1697 EngineControl::bufsize_as_string (uint32_t sz)
1699 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1703 EngineControl::sample_rate_changed ()
1705 DEBUG_ECONTROL ("sample_rate_changed");
1706 /* reset the strings for buffer size to show the correct msec value
1707 (reflecting the new sample rate).
1710 show_buffer_duration ();
1715 EngineControl::buffer_size_changed ()
1717 DEBUG_ECONTROL ("buffer_size_changed");
1718 if (ARDOUR::AudioEngine::instance()->running()) {
1719 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1720 if (backend && backend->can_change_buffer_size_when_running ()) {
1721 backend->set_buffer_size (get_buffer_size());
1724 show_buffer_duration ();
1728 EngineControl::nperiods_changed ()
1730 DEBUG_ECONTROL ("nperiods_changed");
1731 show_buffer_duration ();
1735 EngineControl::show_buffer_duration ()
1737 DEBUG_ECONTROL ("show_buffer_duration");
1738 /* buffer sizes - convert from just samples to samples + msecs for
1739 * the displayed string
1742 string bs_text = buffer_size_combo.get_active_text ();
1743 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1744 uint32_t rate = get_rate();
1746 /* Except for ALSA and Dummy backends, we don't know the number of periods
1747 * per cycle and settings.
1749 * jack1 vs jack2 have different default latencies since jack2 start
1750 * in async-mode unless --sync is given which adds an extra cycle
1751 * of latency. The value is not known if jackd is started externally..
1753 * So just display the period size, that's also what
1754 * ARDOUR_UI::update_sample_rate() does for the status bar.
1755 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1756 * but still, that's the buffer period, not [round-trip] latency)
1759 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1760 buffer_size_duration_label.set_text (buf);
1764 EngineControl::midi_option_changed ()
1766 DEBUG_ECONTROL ("midi_option_changed");
1767 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1770 backend->set_midi_option (get_midi_option());
1772 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1774 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1775 std::vector<MidiDeviceSettings> new_devices;
1777 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1778 MidiDeviceSettings mds = find_midi_device (i->name);
1779 if (i->available && !mds) {
1780 uint32_t input_latency = 0;
1781 uint32_t output_latency = 0;
1782 if (_can_set_midi_latencies) {
1783 input_latency = backend->systemic_midi_input_latency (i->name);
1784 output_latency = backend->systemic_midi_output_latency (i->name);
1786 bool enabled = backend->midi_device_enabled (i->name);
1787 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1788 new_devices.push_back (ptr);
1789 } else if (i->available) {
1790 new_devices.push_back (mds);
1793 _midi_devices = new_devices;
1795 if (_midi_devices.empty()) {
1796 midi_devices_button.set_sensitive (false);
1798 midi_devices_button.set_sensitive (true);
1803 EngineControl::parameter_changed ()
1807 EngineControl::State
1808 EngineControl::get_matching_state (const string& backend)
1810 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1811 if ((*i)->backend == backend) {
1818 EngineControl::State
1819 EngineControl::get_matching_state (
1820 const string& backend,
1821 const string& driver,
1822 const string& device)
1824 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1825 if ((*i)->backend == backend &&
1826 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1834 EngineControl::State
1835 EngineControl::get_matching_state (
1836 const string& backend,
1837 const string& driver,
1838 const string& input_device,
1839 const string& output_device)
1841 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1842 if ((*i)->backend == backend &&
1843 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1851 EngineControl::State
1852 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1854 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1857 if (backend->use_separate_input_and_output_devices ()) {
1858 return get_matching_state (backend_combo.get_active_text(),
1859 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1860 input_device_combo.get_active_text(),
1861 output_device_combo.get_active_text());
1863 return get_matching_state (backend_combo.get_active_text(),
1864 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1865 device_combo.get_active_text());
1869 return get_matching_state (backend_combo.get_active_text(),
1871 device_combo.get_active_text());
1874 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1875 const EngineControl::State& state2)
1877 if (state1->backend == state2->backend &&
1878 state1->driver == state2->driver &&
1879 state1->device == state2->device &&
1880 state1->input_device == state2->input_device &&
1881 state1->output_device == state2->output_device) {
1887 // sort active first, then most recently used to the beginning of the list
1889 EngineControl::state_sort_cmp (const State &a, const State &b) {
1893 else if (b->active) {
1897 return a->lru > b->lru;
1901 EngineControl::State
1902 EngineControl::save_state ()
1906 if (!_have_control) {
1907 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1909 state->lru = time (NULL) ;
1912 state.reset(new StateStruct);
1913 state->backend = get_backend ();
1915 state.reset(new StateStruct);
1916 store_state (state);
1919 for (StateList::iterator i = states.begin(); i != states.end();) {
1920 if (equivalent_states (*i, state)) {
1921 i = states.erase(i);
1927 states.push_back (state);
1929 states.sort (state_sort_cmp);
1935 EngineControl::store_state (State state)
1937 state->backend = get_backend ();
1938 state->driver = get_driver ();
1939 state->device = get_device_name ();
1940 state->input_device = get_input_device_name ();
1941 state->output_device = get_output_device_name ();
1942 state->sample_rate = get_rate ();
1943 state->buffer_size = get_buffer_size ();
1944 state->n_periods = get_nperiods ();
1945 state->input_latency = get_input_latency ();
1946 state->output_latency = get_output_latency ();
1947 state->input_channels = get_input_channels ();
1948 state->output_channels = get_output_channels ();
1949 state->midi_option = get_midi_option ();
1950 state->midi_devices = _midi_devices;
1951 state->use_buffered_io = get_use_buffered_io ();
1952 state->lru = time (NULL) ;
1956 EngineControl::maybe_display_saved_state ()
1958 if (!_have_control || ARDOUR::AudioEngine::instance()->running ()) {
1962 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1965 DEBUG_ECONTROL ("Restoring saved state");
1966 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1968 if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
1969 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1971 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1973 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1974 /* call this explicitly because we're ignoring changes to
1975 the controls at this point.
1977 show_buffer_duration ();
1978 input_latency.set_value (state->input_latency);
1979 output_latency.set_value (state->output_latency);
1981 use_buffered_io_button.set_active (state->use_buffered_io);
1983 if (!state->midi_option.empty()) {
1984 midi_option_combo.set_active_text (state->midi_option);
1985 _midi_devices = state->midi_devices;
1986 midi_option_changed ();
1989 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1994 EngineControl::get_state ()
1998 XMLNode* root = new XMLNode ("AudioMIDISetup");
2001 if (!states.empty()) {
2002 XMLNode* state_nodes = new XMLNode ("EngineStates");
2004 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2006 XMLNode* node = new XMLNode ("State");
2008 node->set_property ("backend", (*i)->backend);
2009 node->set_property ("driver", (*i)->driver);
2010 node->set_property ("device", (*i)->device);
2011 node->set_property ("input-device", (*i)->input_device);
2012 node->set_property ("output-device", (*i)->output_device);
2013 node->set_property ("sample-rate", (*i)->sample_rate);
2014 node->set_property ("buffer-size", (*i)->buffer_size);
2015 node->set_property ("n-periods", (*i)->n_periods);
2016 node->set_property ("input-latency", (*i)->input_latency);
2017 node->set_property ("output-latency", (*i)->output_latency);
2018 node->set_property ("input-channels", (*i)->input_channels);
2019 node->set_property ("output-channels", (*i)->output_channels);
2020 node->set_property ("active", (*i)->active);
2021 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
2022 node->set_property ("midi-option", (*i)->midi_option);
2023 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
2024 node->set_property ("lru", lru_val );
2026 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
2027 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
2028 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
2029 midi_device_stuff->set_property (X_("name"), (*p)->name);
2030 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
2031 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
2032 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
2033 midi_devices->add_child_nocopy (*midi_device_stuff);
2035 node->add_child_nocopy (*midi_devices);
2037 state_nodes->add_child_nocopy (*node);
2040 root->add_child_nocopy (*state_nodes);
2047 EngineControl::set_default_state ()
2049 vector<string> backend_names;
2050 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2052 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
2053 backend_names.push_back ((*b)->name);
2055 backend_combo.set_active_text (backend_names.front());
2057 // We could set default backends per platform etc here
2063 EngineControl::set_state (const XMLNode& root)
2065 XMLNodeList clist, cclist;
2066 XMLNodeConstIterator citer, cciter;
2067 XMLNode const * child;
2068 XMLNode const * grandchild;
2070 if (root.name() != "AudioMIDISetup") {
2074 clist = root.children();
2078 for (citer = clist.begin(); citer != clist.end(); ++citer) {
2082 if (child->name() != "EngineStates") {
2086 cclist = child->children();
2088 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2089 State state (new StateStruct);
2091 grandchild = *cciter;
2093 if (grandchild->name() != "State") {
2097 if (!grandchild->get_property ("backend", state->backend)) {
2101 // If any of the required properties are not found in the state node
2102 // then continue/skip to the next engine state
2103 if (!grandchild->get_property ("driver", state->driver) ||
2104 !grandchild->get_property ("device", state->device) ||
2105 !grandchild->get_property ("input-device", state->input_device) ||
2106 !grandchild->get_property ("output-device", state->output_device) ||
2107 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2108 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2109 !grandchild->get_property ("input-latency", state->input_latency) ||
2110 !grandchild->get_property ("output-latency", state->output_latency) ||
2111 !grandchild->get_property ("input-channels", state->input_channels) ||
2112 !grandchild->get_property ("output-channels", state->output_channels) ||
2113 !grandchild->get_property ("active", state->active) ||
2114 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2115 !grandchild->get_property ("midi-option", state->midi_option)) {
2119 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2120 // optional (new value in 4.5)
2121 state->n_periods = 0;
2124 state->midi_devices.clear();
2126 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2127 const XMLNodeList mnc = midinode->children();
2128 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2131 uint32_t input_latency;
2132 uint32_t output_latency;
2134 if (!(*n)->get_property (X_("name"), name) ||
2135 !(*n)->get_property (X_("enabled"), enabled) ||
2136 !(*n)->get_property (X_("input-latency"), input_latency) ||
2137 !(*n)->get_property (X_("output-latency"), output_latency)) {
2141 MidiDeviceSettings ptr (
2142 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2143 state->midi_devices.push_back (ptr);
2148 if (grandchild->get_property ("lru", lru_val)) {
2149 state->lru = lru_val;
2152 states.push_back (state);
2156 /* now see if there was an active state and switch the setup to it */
2158 /* purge states of backend that are not available in this built */
2159 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2160 vector<std::string> backend_names;
2162 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2163 backend_names.push_back((*i)->name);
2165 for (StateList::iterator i = states.begin(); i != states.end();) {
2166 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2167 i = states.erase(i);
2173 states.sort (state_sort_cmp);
2175 /* purge old states referring to the same backend */
2176 const time_t now = time (NULL);
2177 for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2179 for (StateList::iterator i = states.begin(); i != states.end();) {
2180 if ((*i)->backend != *bi) {
2183 // keep at latest one for every audio-system
2188 // also keep states used in the last 90 days.
2189 if ((now - (*i)->lru) < 86400 * 90) {
2192 assert (!(*i)->active);
2193 i = states.erase(i);
2197 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2200 return set_current_state (*i);
2207 EngineControl::set_current_state (const State& state)
2209 DEBUG_ECONTROL ("set_current_state");
2211 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2213 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2214 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2215 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2216 // this shouldn't happen as the invalid backend names should have been
2217 // removed from the list of states.
2221 // now reflect the change in the backend in the GUI so backend_changed will
2222 // do the right thing
2223 backend_combo.set_active_text (state->backend);
2225 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2227 // we don't have control don't restore state
2232 if (!state->driver.empty ()) {
2233 if (!backend->requires_driver_selection ()) {
2234 DEBUG_ECONTROL ("Backend should require driver selection");
2235 // A backend has changed from having driver selection to not having
2236 // it or someone has been manually editing a config file and messed
2241 if (backend->set_driver (state->driver) != 0) {
2242 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2243 // Driver names for a backend have changed and the name in the
2244 // config file is now invalid or support for driver is no longer
2245 // included in the backend
2248 // no need to set the driver_combo as backend_changed will use
2249 // backend->driver_name to set the active driver
2252 if (!state->device.empty ()) {
2253 if (backend->set_device_name (state->device) != 0) {
2255 string_compose ("Unable to set device name %1", state->device));
2256 // device is no longer available on the system
2259 // no need to set active device as it will be picked up in
2260 // via backend_changed ()/set_device_popdown_strings
2263 // backend supports separate input/output devices
2264 if (backend->set_input_device_name (state->input_device) != 0) {
2265 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2266 state->input_device));
2267 // input device is no longer available on the system
2271 if (backend->set_output_device_name (state->output_device) != 0) {
2272 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2273 state->input_device));
2274 // output device is no longer available on the system
2277 // no need to set active devices as it will be picked up in via
2278 // backend_changed ()/set_*_device_popdown_strings
2283 // Now restore the state of the rest of the controls
2285 // We don't use a SignalBlocker as set_current_state is currently only
2286 // called from set_state before any signals are connected. If at some point
2287 // a more general named state mechanism is implemented and
2288 // set_current_state is called while signals are connected then a
2289 // SignalBlocker will need to be instantiated before setting these.
2291 device_combo.set_active_text (state->device);
2292 input_device_combo.set_active_text (state->input_device);
2293 output_device_combo.set_active_text (state->output_device);
2294 if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
2295 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2297 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2298 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2299 input_latency.set_value (state->input_latency);
2300 output_latency.set_value (state->output_latency);
2301 midi_option_combo.set_active_text (state->midi_option);
2302 use_buffered_io_button.set_active (state->use_buffered_io);
2307 EngineControl::push_state_to_backend (bool start)
2309 DEBUG_ECONTROL ("push_state_to_backend");
2310 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2311 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2317 /* figure out what is going to change */
2319 bool restart_required = false;
2320 bool was_running = ARDOUR::AudioEngine::instance()->running();
2321 bool change_driver = false;
2322 bool change_device = false;
2323 bool change_rate = false;
2324 bool change_bufsize = false;
2325 bool change_nperiods = false;
2326 bool change_latency = false;
2327 bool change_channels = false;
2328 bool change_midi = false;
2329 bool change_buffered_io = false;
2331 uint32_t ochan = get_output_channels ();
2332 uint32_t ichan = get_input_channels ();
2334 if (_have_control) {
2336 if (started_at_least_once) {
2338 /* we can control the backend */
2340 if (backend->requires_driver_selection()) {
2341 if (get_driver() != backend->driver_name()) {
2342 change_driver = true;
2346 if (backend->use_separate_input_and_output_devices()) {
2347 if (get_input_device_name() != backend->input_device_name()) {
2348 change_device = true;
2350 if (get_output_device_name() != backend->output_device_name()) {
2351 change_device = true;
2354 if (get_device_name() != backend->device_name()) {
2355 change_device = true;
2359 if (queue_device_changed) {
2360 change_device = true;
2363 if (get_rate() != backend->sample_rate()) {
2367 if (get_buffer_size() != backend->buffer_size()) {
2368 change_bufsize = true;
2371 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2372 && get_nperiods() != backend->period_size()) {
2373 change_nperiods = true;
2376 if (get_midi_option() != backend->midi_option()) {
2380 if (backend->can_use_buffered_io()) {
2381 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2382 change_buffered_io = true;
2386 /* zero-requested channels means "all available" */
2389 ichan = backend->input_channels();
2393 ochan = backend->output_channels();
2396 if (ichan != backend->input_channels()) {
2397 change_channels = true;
2400 if (ochan != backend->output_channels()) {
2401 change_channels = true;
2404 if (get_input_latency() != backend->systemic_input_latency() ||
2405 get_output_latency() != backend->systemic_output_latency()) {
2406 change_latency = true;
2409 /* backend never started, so we have to force a group
2412 change_device = true;
2413 if (backend->requires_driver_selection()) {
2414 change_driver = true;
2417 change_bufsize = true;
2418 change_channels = true;
2419 change_latency = true;
2421 change_buffered_io = backend->can_use_buffered_io();
2422 change_channels = true;
2423 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2428 /* we have no control over the backend, meaning that we can
2429 * only possibly change sample rate and buffer size.
2433 if (get_rate() != backend->sample_rate()) {
2434 change_bufsize = true;
2437 if (get_buffer_size() != backend->buffer_size()) {
2438 change_bufsize = true;
2442 queue_device_changed = false;
2444 if (!_have_control) {
2446 /* We do not have control over the backend, so the best we can
2447 * do is try to change the sample rate and/or bufsize and get
2451 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2455 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2460 backend->set_sample_rate (get_rate());
2463 if (change_bufsize) {
2464 backend->set_buffer_size (get_buffer_size());
2468 if (ARDOUR::AudioEngine::instance()->start ()) {
2469 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2479 /* determine if we need to stop the backend before changing parameters */
2481 if (change_driver || change_device || change_channels || change_nperiods ||
2482 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2483 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2484 change_midi || change_buffered_io ||
2485 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2486 restart_required = true;
2488 restart_required = false;
2493 if (restart_required) {
2494 if (ARDOUR::AudioEngine::instance()->stop()) {
2500 if (change_driver && backend->set_driver (get_driver())) {
2501 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2504 if (backend->use_separate_input_and_output_devices()) {
2505 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2506 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2509 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2510 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2514 if (change_device && backend->set_device_name (get_device_name())) {
2515 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2519 if (change_rate && backend->set_sample_rate (get_rate())) {
2520 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2523 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2524 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2527 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2528 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2532 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2533 if (backend->set_input_channels (get_input_channels())) {
2534 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2537 if (backend->set_output_channels (get_output_channels())) {
2538 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2542 if (change_latency) {
2543 if (backend->set_systemic_input_latency (get_input_latency())) {
2544 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2547 if (backend->set_systemic_output_latency (get_output_latency())) {
2548 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2554 backend->set_midi_option (get_midi_option());
2557 if (change_buffered_io) {
2558 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2562 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2563 if (_measure_midi) {
2564 /* Disable other MIDI devices while measuring.
2565 * This is a hack to only show ports from the selected device */
2566 if (*p == _measure_midi) {
2567 backend->set_midi_device_enabled ((*p)->name, true);
2569 backend->set_midi_device_enabled ((*p)->name, false);
2573 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2574 if (backend->can_set_systemic_midi_latencies()) {
2575 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2576 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2581 if (start || (was_running && restart_required)) {
2582 if (ARDOUR::AudioEngine::instance()->start()) {
2593 EngineControl::post_push ()
2595 /* get a pointer to the current state object, creating one if
2599 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2602 state = save_state ();
2608 states.sort (state_sort_cmp);
2612 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2613 (*i)->active = false;
2616 /* mark this one active (to be used next time the dialog is
2620 state->active = true;
2622 if (_have_control) { // XXX
2623 manage_control_app_sensitivity ();
2626 /* schedule a redisplay of MIDI ports */
2627 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2632 EngineControl::get_rate () const
2634 float r = atof (sample_rate_combo.get_active_text ());
2635 /* the string may have been translated with an abbreviation for
2636 * thousands, so use a crude heuristic to fix this.
2646 EngineControl::get_buffer_size () const
2648 string txt = buffer_size_combo.get_active_text ();
2651 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2652 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2653 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2661 EngineControl::get_nperiods () const
2663 string txt = nperiods_combo.get_active_text ();
2664 return atoi (txt.c_str());
2668 EngineControl::get_midi_option () const
2670 return midi_option_combo.get_active_text();
2674 EngineControl::get_use_buffered_io () const
2676 return use_buffered_io_button.get_active();
2680 EngineControl::get_input_channels() const
2682 if (ARDOUR::Profile->get_mixbus()) {
2683 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2684 if (!backend) return 0;
2685 return backend->input_channels();
2687 return (uint32_t) input_channels_adjustment.get_value();
2691 EngineControl::get_output_channels() const
2693 if (ARDOUR::Profile->get_mixbus()) {
2694 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2695 if (!backend) return 0;
2696 return backend->input_channels();
2698 return (uint32_t) output_channels_adjustment.get_value();
2702 EngineControl::get_input_latency() const
2704 return (uint32_t) input_latency_adjustment.get_value();
2708 EngineControl::get_output_latency() const
2710 return (uint32_t) output_latency_adjustment.get_value();
2714 EngineControl::get_backend () const
2716 return backend_combo.get_active_text ();
2720 EngineControl::get_driver () const
2722 if (driver_combo.get_parent()) {
2723 return driver_combo.get_active_text ();
2730 EngineControl::get_device_name () const
2732 return device_combo.get_active_text ();
2736 EngineControl::get_input_device_name () const
2738 return input_device_combo.get_active_text ();
2742 EngineControl::get_output_device_name () const
2744 return output_device_combo.get_active_text ();
2748 EngineControl::control_app_button_clicked ()
2750 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2756 backend->launch_control_app ();
2760 EngineControl::start_stop_button_clicked ()
2762 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2768 if (ARDOUR::AudioEngine::instance()->running()) {
2769 ARDOUR::AudioEngine::instance()->stop ();
2771 if (!ARDOUR_UI::instance()->the_session ()) {
2777 if (!ARDOUR_UI::instance()->the_session ()) {
2778 ArdourDialog::on_response (RESPONSE_OK);
2784 EngineControl::update_devices_button_clicked ()
2786 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2792 if (backend->update_devices()) {
2793 device_list_changed ();
2798 EngineControl::try_autostart_button_clicked ()
2800 ARDOUR::Config->set_try_autostart_engine (!try_autostart_button.get_active ());
2801 try_autostart_button.set_active (ARDOUR::Config->get_try_autostart_engine ());
2805 EngineControl::use_buffered_io_button_clicked ()
2807 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2813 bool set_buffered_io = !use_buffered_io_button.get_active();
2814 use_buffered_io_button.set_active (set_buffered_io);
2815 backend->set_use_buffered_io (set_buffered_io);
2819 EngineControl::manage_control_app_sensitivity ()
2821 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2827 string appname = backend->control_app_name();
2829 if (appname.empty()) {
2830 control_app_button.set_sensitive (false);
2832 control_app_button.set_sensitive (true);
2837 EngineControl::set_desired_sample_rate (uint32_t sr)
2839 _desired_sample_rate = sr;
2840 if (ARDOUR::AudioEngine::instance ()->running ()
2841 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2848 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2850 if (page_num == 0) {
2851 _measure_midi.reset();
2852 update_sensitivity ();
2855 if (page_num == midi_tab) {
2857 refresh_midi_display ();
2859 /* undo special case from push_state_to_backend() when measuring midi latency */
2860 if (_measure_midi && ARDOUR::AudioEngine::instance()->running ()) {
2861 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2862 if (backend->can_change_systemic_latency_when_running ()) {
2863 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2864 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2868 _measure_midi.reset();
2871 if (page_num == latency_tab) {
2874 if (ARDOUR::AudioEngine::instance()->running()) {
2879 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2881 /* save any existing latency values */
2883 uint32_t il = (uint32_t) input_latency.get_value ();
2884 uint32_t ol = (uint32_t) input_latency.get_value ();
2886 /* reset to zero so that our new test instance
2887 will be clean of any existing latency measures.
2889 NB. this should really be done by the backend
2890 when stated for latency measurement.
2893 input_latency.set_value (0);
2894 output_latency.set_value (0);
2896 push_state_to_backend (false);
2900 input_latency.set_value (il);
2901 output_latency.set_value (ol);
2904 // This should be done in push_state_to_backend()
2905 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2906 disable_latency_tab ();
2909 enable_latency_tab ();
2913 end_latency_detection ();
2918 /* latency measurement */
2921 EngineControl::check_audio_latency_measurement ()
2923 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2925 if (mtdm->resolve () < 0) {
2926 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2930 if (mtdm->get_peak () > 0.707f) {
2931 // get_peak() resets the peak-hold in the detector.
2932 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2933 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2937 if (mtdm->err () > 0.3) {
2943 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2945 if (sample_rate == 0) {
2946 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2947 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2951 int samples_total = mtdm->del();
2952 int extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2954 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2955 _("Detected roundtrip latency: "),
2956 samples_total, samples_total * 1000.0f/sample_rate,
2957 _("Systemic latency: "),
2958 extra, extra * 1000.0f/sample_rate);
2962 if (mtdm->err () > 0.2) {
2964 strcat (buf, _("(signal detection error)"));
2970 strcat (buf, _("(inverted - bad wiring)"));
2974 lm_results.set_markup (string_compose (results_markup, buf));
2977 have_lm_results = true;
2978 end_latency_detection ();
2979 lm_use_button.set_sensitive (true);
2987 EngineControl::check_midi_latency_measurement ()
2989 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2991 if (!mididm->have_signal () || mididm->latency () == 0) {
2992 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2997 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2999 if (sample_rate == 0) {
3000 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
3001 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3005 ARDOUR::samplecnt_t samples_total = mididm->latency();
3006 ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3007 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
3008 _("Detected roundtrip latency: "),
3009 samples_total, samples_total * 1000.0f / sample_rate, mididm->deviation (),
3010 _("Systemic latency: "),
3011 extra, extra * 1000.0f / sample_rate);
3015 if (!mididm->ok ()) {
3017 strcat (buf, _("(averaging)"));
3021 if (mididm->deviation () > 50.0) {
3023 strcat (buf, _("(too large jitter)"));
3025 } else if (mididm->deviation () > 10.0) {
3027 strcat (buf, _("(large jitter)"));
3031 have_lm_results = true;
3032 end_latency_detection ();
3033 lm_use_button.set_sensitive (true);
3034 lm_results.set_markup (string_compose (results_markup, buf));
3036 } else if (mididm->processed () > 400) {
3037 have_lm_results = false;
3038 end_latency_detection ();
3039 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3043 lm_results.set_markup (string_compose (results_markup, buf));
3049 EngineControl::start_latency_detection ()
3051 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active ()->get_value (lm_input_channel_cols.port_name));
3052 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active ()->get_value (lm_output_channel_cols.port_name));
3054 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3055 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3056 if (_measure_midi) {
3057 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3059 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3061 lm_measure_label.set_text (_("Cancel"));
3062 have_lm_results = false;
3063 lm_use_button.set_sensitive (false);
3064 lm_input_channel_combo.set_sensitive (false);
3065 lm_output_channel_combo.set_sensitive (false);
3071 EngineControl::end_latency_detection ()
3073 latency_timeout.disconnect ();
3074 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3075 lm_measure_label.set_text (_("Measure"));
3076 if (!have_lm_results) {
3077 lm_use_button.set_sensitive (false);
3079 lm_input_channel_combo.set_sensitive (true);
3080 lm_output_channel_combo.set_sensitive (true);
3085 EngineControl::latency_button_clicked ()
3088 start_latency_detection ();
3090 end_latency_detection ();
3095 EngineControl::latency_back_button_clicked ()
3097 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3098 notebook.set_current_page(0);
3102 EngineControl::use_latency_button_clicked ()
3104 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3105 if (_measure_midi) {
3106 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3110 ARDOUR::samplecnt_t samples_total = mididm->latency();
3111 ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3112 uint32_t one_way = max ((ARDOUR::samplecnt_t) 0, extra / 2);
3113 _measure_midi->input_latency = one_way;
3114 _measure_midi->output_latency = one_way;
3115 if (backend->can_change_systemic_latency_when_running ()) {
3116 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3117 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3119 notebook.set_current_page (midi_tab);
3121 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3127 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3128 one_way = std::max (0., one_way);
3130 input_latency_adjustment.set_value (one_way);
3131 output_latency_adjustment.set_value (one_way);
3132 if (backend->can_change_systemic_latency_when_running ()) {
3133 backend->set_systemic_input_latency (one_way);
3134 backend->set_systemic_output_latency (one_way);
3137 /* back to settings page */
3138 notebook.set_current_page (0);
3143 EngineControl::on_response (int rid)
3145 /* this gets called if this Dialog is running under gtk_dialog_run()
3146 rather than in the toplevel loop. This happens during program
3150 if (rid == RESPONSE_DELETE_EVENT) {
3151 on_delete_event ((GdkEventAny*) 0);
3155 ArdourDialog::on_response (rid);
3159 EngineControl::on_delete_event (GdkEventAny* ev)
3161 if (lm_running || notebook.get_current_page() == 2) {
3162 /* currently measuring latency - be sure to clean up */
3163 end_latency_detection ();
3166 return ArdourDialog::on_delete_event (ev);
3170 EngineControl::engine_running ()
3172 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3175 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3176 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3178 if (backend->can_set_period_size ()) {
3179 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3182 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3183 connect_disconnect_button.show();
3185 started_at_least_once = true;
3186 if (_have_control) {
3187 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3189 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3191 update_sensitivity();
3195 EngineControl::engine_stopped ()
3197 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3200 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3201 connect_disconnect_button.show();
3203 if (_have_control) {
3204 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3206 engine_status.set_markup(X_(""));
3209 update_sensitivity();
3213 EngineControl::device_list_changed ()
3215 if (ignore_device_changes) {
3218 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3219 if (!ARDOUR::AudioEngine::instance()->running()) {
3223 midi_option_changed();
3225 if (notebook.get_current_page() == midi_tab) {
3226 if (_midi_devices.empty ()) {
3227 notebook.set_current_page (0);
3229 refresh_midi_display ();
3235 EngineControl::connect_disconnect_click()
3237 if (ARDOUR::AudioEngine::instance()->running()) {
3240 if (!ARDOUR_UI::instance()->the_session ()) {
3246 if (!ARDOUR_UI::instance()->the_session ()) {
3247 ArdourDialog::on_response (RESPONSE_OK);
3253 EngineControl::calibrate_audio_latency ()
3255 _measure_midi.reset ();
3256 have_lm_results = false;
3257 lm_use_button.set_sensitive (false);
3258 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3259 notebook.set_current_page (latency_tab);
3263 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3266 have_lm_results = false;
3267 lm_use_button.set_sensitive (false);
3268 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3269 notebook.set_current_page (latency_tab);
3273 EngineControl::configure_midi_devices ()
3275 notebook.set_current_page (midi_tab);