2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/locale_guard.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
56 #include "ui_config.h"
57 #include "public_editor.h"
64 using namespace Gtkmm2ext;
67 using namespace ARDOUR_UI_UTILS;
69 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
71 static const unsigned int midi_tab = 2;
72 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
74 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
76 EngineControl::EngineControl ()
77 : ArdourDialog (_("Audio/MIDI Setup"))
80 , input_latency_adjustment (0, 0, 99999, 1)
81 , input_latency (input_latency_adjustment)
82 , output_latency_adjustment (0, 0, 99999, 1)
83 , output_latency (output_latency_adjustment)
84 , input_channels_adjustment (0, 0, 256, 1)
85 , input_channels (input_channels_adjustment)
86 , output_channels_adjustment (0, 0, 256, 1)
87 , output_channels (output_channels_adjustment)
88 , ports_adjustment (128, 8, 1024, 1, 16)
89 , ports_spinner (ports_adjustment)
90 , control_app_button (_("Device Control Panel"))
91 , midi_devices_button (_("Midi Device Setup"))
92 , start_stop_button (_("Stop"))
93 , update_devices_button (_("Refresh Devices"))
94 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
95 , lm_measure_label (_("Measure"))
96 , lm_use_button (_("Use results"))
97 , lm_back_button (_("Back to settings ... (ignore results)"))
98 , lm_button_audio (_("Calibrate Audio"))
100 , have_lm_results (false)
102 , midi_back_button (_("Back to settings"))
104 , ignore_device_changes (0)
105 , _desired_sample_rate (0)
106 , started_at_least_once (false)
107 , queue_device_changed (false)
108 , _have_control (true)
111 using namespace Notebook_Helpers;
112 vector<string> backend_names;
114 AttachOptions xopt = AttachOptions (FILL|EXPAND);
117 set_name (X_("AudioMIDISetup"));
119 /* the backend combo is the one thing that is ALWAYS visible */
121 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
123 if (backends.empty()) {
124 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));
126 throw failed_constructor ();
129 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
130 backend_names.push_back ((*b)->name);
133 set_popdown_strings (backend_combo, backend_names);
135 /* setup basic packing characteristics for the table used on the main
136 * tab of the notebook
139 basic_packer.set_spacings (6);
140 basic_packer.set_border_width (12);
141 basic_packer.set_homogeneous (false);
145 basic_hbox.pack_start (basic_packer, false, false);
147 /* latency measurement tab */
149 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
152 lm_table.set_row_spacings (12);
153 lm_table.set_col_spacings (6);
154 lm_table.set_homogeneous (false);
156 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
159 lm_preamble.set_width_chars (60);
160 lm_preamble.set_line_wrap (true);
161 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
163 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
166 Gtk::Label* preamble;
167 preamble = manage (new Label);
168 preamble->set_width_chars (60);
169 preamble->set_line_wrap (true);
170 preamble->set_markup (_("Select two channels below and connect them using a cable."));
172 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
175 label = manage (new Label (_("Output channel")));
176 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
178 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
179 misc_align->add (lm_output_channel_combo);
180 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
183 label = manage (new Label (_("Input channel")));
184 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
186 misc_align = manage (new Alignment (0.0, 0.5));
187 misc_align->add (lm_input_channel_combo);
188 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
191 lm_measure_label.set_padding (10, 10);
192 lm_measure_button.add (lm_measure_label);
193 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
194 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
195 lm_back_button_signal = lm_back_button.signal_clicked().connect(
196 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
198 lm_use_button.set_sensitive (false);
200 /* Increase the default spacing around the labels of these three
206 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
207 l->set_padding (10, 10);
210 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
211 l->set_padding (10, 10);
214 preamble = manage (new Label);
215 preamble->set_width_chars (60);
216 preamble->set_line_wrap (true);
217 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
218 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
221 preamble = manage (new Label);
222 preamble->set_width_chars (60);
223 preamble->set_line_wrap (true);
224 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
225 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 ++row; // skip a row in the table
228 ++row; // skip a row in the table
230 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 ++row; // skip a row in the table
233 ++row; // skip a row in the table
235 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
236 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
237 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
239 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
241 lm_vbox.set_border_width (12);
242 lm_vbox.pack_start (lm_table, false, false);
244 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
248 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
249 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
250 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
251 notebook.set_border_width (12);
253 notebook.set_show_tabs (false);
254 notebook.show_all ();
256 notebook.set_name ("SettingsNotebook");
258 /* packup the notebook */
260 get_vbox()->set_border_width (12);
261 get_vbox()->pack_start (notebook);
263 /* need a special function to print "all available channels" when the
264 * channel counts hit zero.
267 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
268 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
270 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
271 midi_devices_button.set_name ("generic button");
272 midi_devices_button.set_can_focus(true);
274 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
275 control_app_button.set_name ("generic button");
276 control_app_button.set_can_focus(true);
277 manage_control_app_sensitivity ();
279 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
280 start_stop_button.set_sensitive (false);
281 start_stop_button.set_name ("generic button");
282 start_stop_button.set_can_focus(true);
283 start_stop_button.set_can_default(true);
284 start_stop_button.set_act_on_release (false);
286 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
287 update_devices_button.set_sensitive (false);
288 update_devices_button.set_name ("generic button");
289 update_devices_button.set_can_focus(true);
291 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
292 use_buffered_io_button.set_sensitive (false);
293 use_buffered_io_button.set_name ("generic button");
294 use_buffered_io_button.set_can_focus(true);
296 /* Pick up any existing audio setup configuration, if appropriate */
298 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
300 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
301 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
302 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
303 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
306 if (!set_state (*audio_setup)) {
307 set_default_state ();
310 set_default_state ();
313 update_sensitivity ();
314 connect_changed_signals ();
316 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
318 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
320 connect_disconnect_button.set_no_show_all();
321 use_buffered_io_button.set_no_show_all();
322 update_devices_button.set_no_show_all();
323 start_stop_button.set_no_show_all();
324 midi_devices_button.set_no_show_all();
328 EngineControl::connect_changed_signals ()
330 backend_combo_connection = backend_combo.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::backend_changed));
332 driver_combo_connection = driver_combo.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::driver_changed));
334 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
336 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
338 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
340 device_combo_connection = device_combo.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::device_changed));
342 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
345 input_device_combo_connection = input_device_combo.signal_changed ().connect (
346 sigc::mem_fun (*this, &EngineControl::input_device_changed));
347 output_device_combo_connection = output_device_combo.signal_changed ().connect (
348 sigc::mem_fun (*this, &EngineControl::output_device_changed));
350 input_latency_connection = input_latency.signal_changed ().connect (
351 sigc::mem_fun (*this, &EngineControl::parameter_changed));
352 output_latency_connection = output_latency.signal_changed ().connect (
353 sigc::mem_fun (*this, &EngineControl::parameter_changed));
354 input_channels_connection = input_channels.signal_changed ().connect (
355 sigc::mem_fun (*this, &EngineControl::parameter_changed));
356 output_channels_connection = output_channels.signal_changed ().connect (
357 sigc::mem_fun (*this, &EngineControl::parameter_changed));
361 EngineControl::block_changed_signals ()
363 if (block_signals++ == 0) {
364 DEBUG_ECONTROL ("Blocking changed signals");
365 backend_combo_connection.block ();
366 driver_combo_connection.block ();
367 sample_rate_combo_connection.block ();
368 buffer_size_combo_connection.block ();
369 nperiods_combo_connection.block ();
370 device_combo_connection.block ();
371 input_device_combo_connection.block ();
372 output_device_combo_connection.block ();
373 midi_option_combo_connection.block ();
374 input_latency_connection.block ();
375 output_latency_connection.block ();
376 input_channels_connection.block ();
377 output_channels_connection.block ();
382 EngineControl::unblock_changed_signals ()
384 if (--block_signals == 0) {
385 DEBUG_ECONTROL ("Unblocking changed signals");
386 backend_combo_connection.unblock ();
387 driver_combo_connection.unblock ();
388 sample_rate_combo_connection.unblock ();
389 buffer_size_combo_connection.unblock ();
390 nperiods_combo_connection.unblock ();
391 device_combo_connection.unblock ();
392 input_device_combo_connection.unblock ();
393 output_device_combo_connection.unblock ();
394 midi_option_combo_connection.unblock ();
395 input_latency_connection.unblock ();
396 output_latency_connection.unblock ();
397 input_channels_connection.unblock ();
398 output_channels_connection.unblock ();
402 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
403 const std::string& reason)
404 : ec (engine_control)
407 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
408 ec.block_changed_signals ();
411 EngineControl::SignalBlocker::~SignalBlocker ()
413 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
414 ec.unblock_changed_signals ();
418 EngineControl::on_show ()
420 ArdourDialog::on_show ();
421 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
422 // re-check _have_control (jackd running) see #6041
426 start_stop_button.grab_focus();
430 EngineControl::on_map ()
432 if (!ARDOUR_UI::instance()->session_loaded && !PublicEditor::_instance) {
433 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
434 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
435 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
437 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
439 ArdourDialog::on_map ();
443 EngineControl::try_autostart ()
445 if (!start_stop_button.get_sensitive()) {
448 if (ARDOUR::AudioEngine::instance()->running()) {
451 return start_engine ();
455 EngineControl::start_engine ()
457 if (push_state_to_backend(true) != 0) {
458 MessageDialog msg(*this,
459 ARDOUR::AudioEngine::instance()->get_last_backend_error());
467 EngineControl::stop_engine (bool for_latency)
469 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
470 MessageDialog msg(*this,
471 ARDOUR::AudioEngine::instance()->get_last_backend_error());
479 EngineControl::build_notebook ()
482 AttachOptions xopt = AttachOptions (FILL|EXPAND);
484 /* clear the table */
486 Gtkmm2ext::container_clear (basic_vbox);
487 Gtkmm2ext::container_clear (basic_packer);
489 if (control_app_button.get_parent()) {
490 control_app_button.get_parent()->remove (control_app_button);
493 label = manage (left_aligned_label (_("Audio System:")));
494 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
495 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
497 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
498 engine_status.show();
500 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
501 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
502 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
504 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
505 lm_button_audio.set_name ("generic button");
506 lm_button_audio.set_can_focus(true);
509 build_full_control_notebook ();
511 build_no_control_notebook ();
514 basic_vbox.pack_start (basic_hbox, false, false);
517 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
518 basic_vbox.show_all ();
523 EngineControl::build_full_control_notebook ()
525 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
528 using namespace Notebook_Helpers;
530 vector<string> strings;
531 AttachOptions xopt = AttachOptions (FILL|EXPAND);
532 int row = 1; // row zero == backend combo
534 /* start packing it up */
536 if (backend->requires_driver_selection()) {
537 label = manage (left_aligned_label (_("Driver:")));
538 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
539 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
543 if (backend->use_separate_input_and_output_devices()) {
544 label = manage (left_aligned_label (_("Input Device:")));
545 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
546 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
548 label = manage (left_aligned_label (_("Output Device:")));
549 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
550 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
552 // reset so it isn't used in state comparisons
553 device_combo.set_active_text ("");
555 label = manage (left_aligned_label (_("Device:")));
556 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
557 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
559 // reset these so they don't get used in state comparisons
560 input_device_combo.set_active_text ("");
561 output_device_combo.set_active_text ("");
564 label = manage (left_aligned_label (_("Sample rate:")));
565 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
570 label = manage (left_aligned_label (_("Buffer size:")));
571 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
572 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
573 buffer_size_duration_label.set_alignment (0.0); /* left-align */
574 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
576 int ctrl_btn_span = 1;
577 if (backend->can_set_period_size ()) {
579 label = manage (left_aligned_label (_("Periods:")));
580 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
581 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
585 /* button spans 2 or 3 rows */
587 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
590 input_channels.set_name ("InputChannels");
591 input_channels.set_flags (Gtk::CAN_FOCUS);
592 input_channels.set_digits (0);
593 input_channels.set_wrap (false);
594 output_channels.set_editable (true);
596 if (!ARDOUR::Profile->get_mixbus()) {
597 label = manage (left_aligned_label (_("Input Channels:")));
598 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
599 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
603 output_channels.set_name ("OutputChannels");
604 output_channels.set_flags (Gtk::CAN_FOCUS);
605 output_channels.set_digits (0);
606 output_channels.set_wrap (false);
607 output_channels.set_editable (true);
609 if (!ARDOUR::Profile->get_mixbus()) {
610 label = manage (left_aligned_label (_("Output Channels:")));
611 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
612 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
616 input_latency.set_name ("InputLatency");
617 input_latency.set_flags (Gtk::CAN_FOCUS);
618 input_latency.set_digits (0);
619 input_latency.set_wrap (false);
620 input_latency.set_editable (true);
622 label = manage (left_aligned_label (_("Hardware input latency:")));
623 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
624 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
625 label = manage (left_aligned_label (_("samples")));
626 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
629 output_latency.set_name ("OutputLatency");
630 output_latency.set_flags (Gtk::CAN_FOCUS);
631 output_latency.set_digits (0);
632 output_latency.set_wrap (false);
633 output_latency.set_editable (true);
635 label = manage (left_aligned_label (_("Hardware output latency:")));
636 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
637 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
638 label = manage (left_aligned_label (_("samples")));
639 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
641 /* button spans 2 rows */
643 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
646 label = manage (left_aligned_label (_("MIDI System:")));
647 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
648 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
649 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
654 EngineControl::build_no_control_notebook ()
656 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
659 using namespace Notebook_Helpers;
661 vector<string> strings;
662 AttachOptions xopt = AttachOptions (FILL|EXPAND);
663 int row = 1; // row zero == backend combo
664 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
666 label = manage (new Label);
667 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
668 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
671 if (backend->can_change_sample_rate_when_running()) {
672 label = manage (left_aligned_label (_("Sample rate:")));
673 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
674 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
678 if (backend->can_change_buffer_size_when_running()) {
679 label = manage (left_aligned_label (_("Buffer size:")));
680 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
681 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
682 buffer_size_duration_label.set_alignment (0.0); /* left-align */
683 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
687 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
691 EngineControl::~EngineControl ()
693 ignore_changes = true;
697 EngineControl::disable_latency_tab ()
699 vector<string> empty;
700 set_popdown_strings (lm_output_channel_combo, empty);
701 set_popdown_strings (lm_input_channel_combo, empty);
702 lm_measure_button.set_sensitive (false);
703 lm_use_button.set_sensitive (false);
707 EngineControl::enable_latency_tab ()
709 vector<string> outputs;
710 vector<string> inputs;
712 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
713 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
714 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
716 if (!ARDOUR::AudioEngine::instance()->running()) {
717 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
718 notebook.set_current_page (0);
722 else if (inputs.empty() || outputs.empty()) {
723 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
724 notebook.set_current_page (0);
729 lm_back_button_signal.disconnect();
731 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
734 lm_back_button_signal = lm_back_button.signal_clicked().connect(
735 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
739 set_popdown_strings (lm_output_channel_combo, outputs);
740 lm_output_channel_combo.set_active_text (outputs.front());
741 lm_output_channel_combo.set_sensitive (true);
743 set_popdown_strings (lm_input_channel_combo, inputs);
744 lm_input_channel_combo.set_active_text (inputs.front());
745 lm_input_channel_combo.set_sensitive (true);
747 lm_measure_button.set_sensitive (true);
751 EngineControl::setup_midi_tab_for_backend ()
753 string backend = backend_combo.get_active_text ();
755 Gtkmm2ext::container_clear (midi_vbox);
757 midi_vbox.set_border_width (12);
758 midi_device_table.set_border_width (12);
760 if (backend == "JACK") {
761 setup_midi_tab_for_jack ();
764 midi_vbox.pack_start (midi_device_table, true, true);
765 midi_vbox.pack_start (midi_back_button, false, false);
766 midi_vbox.show_all ();
770 EngineControl::update_sensitivity ()
772 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
774 start_stop_button.set_sensitive (false);
779 size_t devices_available = 0;
780 bool engine_running = ARDOUR::AudioEngine::instance()->running();
782 if (backend->use_separate_input_and_output_devices ()) {
783 devices_available += get_popdown_string_count (input_device_combo);
784 devices_available += get_popdown_string_count (output_device_combo);
786 devices_available += get_popdown_string_count (device_combo);
789 if (devices_available == 0) {
791 input_latency.set_sensitive (false);
792 output_latency.set_sensitive (false);
793 input_channels.set_sensitive (false);
794 output_channels.set_sensitive (false);
796 input_latency.set_sensitive (true);
797 output_latency.set_sensitive (true);
798 input_channels.set_sensitive (!engine_running);
799 output_channels.set_sensitive (!engine_running);
802 if (get_popdown_string_count (buffer_size_combo) > 0) {
803 if (!engine_running) {
804 buffer_size_combo.set_sensitive (valid);
805 } else if (backend->can_change_sample_rate_when_running()) {
806 buffer_size_combo.set_sensitive (valid || !_have_control);
810 * Currently there is no way to manually stop the
811 * engine in order to re-configure it.
812 * This needs to remain sensitive for now.
814 * (it's also handy to implicily
815 * re-start the engine)
817 buffer_size_combo.set_sensitive (true);
819 buffer_size_combo.set_sensitive (false);
823 buffer_size_combo.set_sensitive (false);
827 if (get_popdown_string_count (sample_rate_combo) > 0) {
828 bool allow_to_set_rate = false;
829 if (!engine_running) {
830 if (!ARDOUR_UI::instance()->session_loaded) {
831 // engine is not running, no session loaded -> anything goes.
832 allow_to_set_rate = true;
833 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
834 // only allow to change if the current setting is not the native session rate.
835 allow_to_set_rate = true;
838 sample_rate_combo.set_sensitive (allow_to_set_rate);
840 sample_rate_combo.set_sensitive (false);
844 if (get_popdown_string_count (nperiods_combo) > 0) {
845 if (!engine_running) {
846 nperiods_combo.set_sensitive (true);
848 nperiods_combo.set_sensitive (false);
851 nperiods_combo.set_sensitive (false);
855 start_stop_button.set_sensitive(true);
856 start_stop_button.show();
857 if (engine_running) {
858 start_stop_button.set_text("Stop");
859 update_devices_button.set_sensitive(false);
860 use_buffered_io_button.set_sensitive(false);
862 if (backend->can_request_update_devices()) {
863 update_devices_button.show();
865 update_devices_button.hide();
867 if (backend->can_use_buffered_io()) {
868 use_buffered_io_button.show();
870 use_buffered_io_button.hide();
872 start_stop_button.set_text("Start");
873 update_devices_button.set_sensitive(true);
874 use_buffered_io_button.set_sensitive(true);
877 update_devices_button.set_sensitive(false);
878 update_devices_button.hide();
879 use_buffered_io_button.set_sensitive(false);
880 use_buffered_io_button.hide();
881 start_stop_button.set_sensitive(false);
882 start_stop_button.hide();
885 if (engine_running && _have_control) {
886 input_device_combo.set_sensitive (false);
887 output_device_combo.set_sensitive (false);
888 device_combo.set_sensitive (false);
889 driver_combo.set_sensitive (false);
891 input_device_combo.set_sensitive (true);
892 output_device_combo.set_sensitive (true);
893 device_combo.set_sensitive (true);
894 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
895 driver_combo.set_sensitive (true);
897 driver_combo.set_sensitive (false);
901 midi_option_combo.set_sensitive (!engine_running);
905 EngineControl::setup_midi_tab_for_jack ()
910 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
912 device->input_latency = a->get_value();
914 device->output_latency = a->get_value();
919 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
920 b->set_active (!b->get_active());
921 device->enabled = b->get_active();
922 refresh_midi_display(device->name);
926 EngineControl::refresh_midi_display (std::string focus)
928 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
932 AttachOptions xopt = AttachOptions (FILL|EXPAND);
935 Gtkmm2ext::container_clear (midi_device_table);
937 midi_device_table.set_spacings (6);
939 l = manage (new Label);
940 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
941 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
942 l->set_alignment (0.5, 0.5);
946 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
947 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
948 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
949 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
951 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
952 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
953 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
954 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
957 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
962 bool enabled = (*p)->enabled;
964 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
965 m->set_name ("midi device");
966 m->set_can_focus (Gtk::CAN_FOCUS);
967 m->add_events (Gdk::BUTTON_RELEASE_MASK);
968 m->set_active (enabled);
969 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
970 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
971 if ((*p)->name == focus) {
975 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
976 s = manage (new Gtk::SpinButton (*a));
977 a->set_value ((*p)->input_latency);
978 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
979 s->set_sensitive (_can_set_midi_latencies && enabled);
980 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
982 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
983 s = manage (new Gtk::SpinButton (*a));
984 a->set_value ((*p)->output_latency);
985 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
986 s->set_sensitive (_can_set_midi_latencies && enabled);
987 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
989 b = manage (new Button (_("Calibrate")));
990 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
991 b->set_sensitive (_can_set_midi_latencies && enabled);
992 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
999 EngineControl::backend_changed ()
1001 SignalBlocker blocker (*this, "backend_changed");
1002 string backend_name = backend_combo.get_active_text();
1003 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1005 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1006 /* eh? setting the backend failed... how ? */
1007 /* A: stale config contains a backend that does not exist in current build */
1011 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1013 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1016 setup_midi_tab_for_backend ();
1017 _midi_devices.clear();
1019 if (backend->requires_driver_selection()) {
1020 if (set_driver_popdown_strings ()) {
1024 /* this will change the device text which will cause a call to
1025 * device changed which will set up parameters
1030 update_midi_options ();
1032 connect_disconnect_button.hide();
1034 midi_option_changed();
1036 started_at_least_once = false;
1038 /* changing the backend implies stopping the engine
1039 * ARDOUR::AudioEngine() may or may not emit this signal
1040 * depending on previous engine state
1042 engine_stopped (); // set "active/inactive"
1044 if (!_have_control) {
1045 // set settings from backend that we do have control over
1046 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1049 if (_have_control && !ignore_changes) {
1050 // set driver & devices
1051 State state = get_matching_state (backend_combo.get_active_text());
1053 DEBUG_ECONTROL ("backend-changed(): found prior state for backend");
1054 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1055 set_current_state (state);
1057 DEBUG_ECONTROL ("backend-changed(): no prior state for backend");
1060 DEBUG_ECONTROL (string_compose ("backend-changed(): _have_control=%1 ignore_changes=%2", _have_control, ignore_changes));
1063 if (!ignore_changes) {
1064 maybe_display_saved_state ();
1069 EngineControl::update_midi_options ()
1071 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1072 vector<string> midi_options = backend->enumerate_midi_options();
1074 if (midi_options.size() == 1) {
1075 /* only contains the "none" option */
1076 midi_option_combo.set_sensitive (false);
1078 if (_have_control) {
1079 set_popdown_strings (midi_option_combo, midi_options);
1080 midi_option_combo.set_active_text (midi_options.front());
1081 midi_option_combo.set_sensitive (true);
1083 midi_option_combo.set_sensitive (false);
1089 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1091 if (ARDOUR::Profile->get_mixbus()) {
1095 uint32_t cnt = (uint32_t) sb->get_value();
1097 sb->set_text (_("all available channels"));
1100 snprintf (buf, sizeof (buf), "%d", cnt);
1106 // @return true if there are drivers available
1108 EngineControl::set_driver_popdown_strings ()
1110 DEBUG_ECONTROL ("set_driver_popdown_strings");
1111 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1112 vector<string> drivers = backend->enumerate_drivers();
1114 if (drivers.empty ()) {
1115 // This is an error...?
1119 string current_driver = backend->driver_name ();
1121 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1123 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1126 current_driver = drivers.front ();
1129 set_popdown_strings (driver_combo, drivers);
1131 string_compose ("driver_combo.set_active_text: %1", current_driver));
1132 driver_combo.set_active_text (current_driver);
1137 EngineControl::get_default_device(const string& current_device_name,
1138 const vector<string>& available_devices)
1140 // If the current device is available, use it as default
1141 if (std::find (available_devices.begin (),
1142 available_devices.end (),
1143 current_device_name) != available_devices.end ()) {
1145 return current_device_name;
1148 using namespace ARDOUR;
1150 string default_device_name =
1151 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1153 vector<string>::const_iterator i;
1155 // If there is a "Default" device available, use it
1156 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1157 if (*i == default_device_name) {
1162 string none_device_name =
1163 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1165 // Use the first device that isn't "None"
1166 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1167 if (*i != none_device_name) {
1172 // Use "None" if there are no other available
1173 return available_devices.front();
1176 // @return true if there are devices available
1178 EngineControl::set_device_popdown_strings ()
1180 DEBUG_ECONTROL ("set_device_popdown_strings");
1181 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1182 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1184 /* NOTE: Ardour currently does not display the "available" field of the
1187 * Doing so would require a different GUI widget than the combo
1188 * box/popdown that we currently use, since it has no way to list
1189 * items that are not selectable. Something more like a popup menu,
1190 * which could have unselectable items, would be appropriate.
1193 vector<string> available_devices;
1195 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1196 available_devices.push_back (i->name);
1199 if (available_devices.empty ()) {
1203 set_popdown_strings (device_combo, available_devices);
1205 std::string default_device =
1206 get_default_device(backend->device_name(), available_devices);
1209 string_compose ("set device_combo active text: %1", default_device));
1211 device_combo.set_active_text(default_device);
1215 // @return true if there are input devices available
1217 EngineControl::set_input_device_popdown_strings ()
1219 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1220 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1221 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1223 vector<string> available_devices;
1225 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1226 available_devices.push_back (i->name);
1229 if (available_devices.empty()) {
1233 set_popdown_strings (input_device_combo, available_devices);
1235 std::string default_device =
1236 get_default_device(backend->input_device_name(), available_devices);
1239 string_compose ("set input_device_combo active text: %1", default_device));
1240 input_device_combo.set_active_text(default_device);
1244 // @return true if there are output devices available
1246 EngineControl::set_output_device_popdown_strings ()
1248 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1249 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1250 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1252 vector<string> available_devices;
1254 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1255 available_devices.push_back (i->name);
1258 if (available_devices.empty()) {
1262 set_popdown_strings (output_device_combo, available_devices);
1264 std::string default_device =
1265 get_default_device(backend->output_device_name(), available_devices);
1268 string_compose ("set output_device_combo active text: %1", default_device));
1269 output_device_combo.set_active_text(default_device);
1274 EngineControl::list_devices ()
1276 DEBUG_ECONTROL ("list_devices");
1277 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1280 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1282 bool devices_available = false;
1284 if (backend->use_separate_input_and_output_devices ()) {
1285 bool input_devices_available = set_input_device_popdown_strings ();
1286 bool output_devices_available = set_output_device_popdown_strings ();
1287 devices_available = input_devices_available || output_devices_available;
1289 devices_available = set_device_popdown_strings ();
1292 if (devices_available) {
1295 device_combo.clear();
1296 input_device_combo.clear();
1297 output_device_combo.clear();
1299 update_sensitivity ();
1303 EngineControl::driver_changed ()
1305 SignalBlocker blocker (*this, "driver_changed");
1306 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1309 backend->set_driver (driver_combo.get_active_text());
1312 // TODO load LRU device(s) for backend + driver combo
1314 if (!ignore_changes) {
1315 maybe_display_saved_state ();
1320 EngineControl::get_sample_rates_for_all_devices ()
1322 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1323 ARDOUR::AudioEngine::instance ()->current_backend ();
1324 vector<float> all_rates;
1326 if (backend->use_separate_input_and_output_devices ()) {
1327 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1329 all_rates = backend->available_sample_rates (get_device_name ());
1335 EngineControl::get_default_sample_rates ()
1337 vector<float> rates;
1338 rates.push_back (8000.0f);
1339 rates.push_back (16000.0f);
1340 rates.push_back (32000.0f);
1341 rates.push_back (44100.0f);
1342 rates.push_back (48000.0f);
1343 rates.push_back (88200.0f);
1344 rates.push_back (96000.0f);
1345 rates.push_back (192000.0f);
1346 rates.push_back (384000.0f);
1351 EngineControl::set_samplerate_popdown_strings ()
1353 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1354 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1359 if (_have_control) {
1360 sr = get_sample_rates_for_all_devices ();
1362 sr = get_default_sample_rates ();
1365 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1366 s.push_back (rate_as_string (*x));
1367 if (*x == _desired_sample_rate) {
1372 set_popdown_strings (sample_rate_combo, s);
1375 if (ARDOUR::AudioEngine::instance()->running()) {
1376 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1378 else if (desired.empty ()) {
1379 float new_active_sr = backend->default_sample_rate ();
1381 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1382 new_active_sr = sr.front ();
1385 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1387 sample_rate_combo.set_active_text (desired);
1391 update_sensitivity ();
1395 EngineControl::get_buffer_sizes_for_all_devices ()
1397 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1398 ARDOUR::AudioEngine::instance ()->current_backend ();
1399 vector<uint32_t> all_sizes;
1401 if (backend->use_separate_input_and_output_devices ()) {
1402 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1404 all_sizes = backend->available_buffer_sizes (get_device_name ());
1410 EngineControl::get_default_buffer_sizes ()
1412 vector<uint32_t> sizes;
1413 sizes.push_back (8);
1414 sizes.push_back (16);
1415 sizes.push_back (32);
1416 sizes.push_back (64);
1417 sizes.push_back (128);
1418 sizes.push_back (256);
1419 sizes.push_back (512);
1420 sizes.push_back (1024);
1421 sizes.push_back (2048);
1422 sizes.push_back (4096);
1423 sizes.push_back (8192);
1428 EngineControl::set_buffersize_popdown_strings ()
1430 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1431 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1432 vector<uint32_t> bs;
1435 if (_have_control) {
1436 bs = get_buffer_sizes_for_all_devices ();
1437 } else if (backend->can_change_buffer_size_when_running()) {
1438 bs = get_default_buffer_sizes ();
1441 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1442 s.push_back (bufsize_as_string (*x));
1445 uint32_t previous_size = 0;
1446 if (!buffer_size_combo.get_active_text().empty()) {
1447 previous_size = get_buffer_size ();
1450 set_popdown_strings (buffer_size_combo, s);
1454 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1455 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1458 buffer_size_combo.set_active_text(s.front());
1460 uint32_t period = backend->buffer_size();
1461 if (0 == period && backend->use_separate_input_and_output_devices()) {
1462 period = backend->default_buffer_size(get_input_device_name());
1464 if (0 == period && backend->use_separate_input_and_output_devices()) {
1465 period = backend->default_buffer_size(get_output_device_name());
1467 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1468 period = backend->default_buffer_size(get_device_name());
1471 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1473 show_buffer_duration ();
1475 update_sensitivity ();
1479 EngineControl::set_nperiods_popdown_strings ()
1481 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1482 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1483 vector<uint32_t> np;
1486 if (backend->can_set_period_size()) {
1487 np = backend->available_period_sizes (get_driver());
1490 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1491 s.push_back (to_string (*x));
1494 set_popdown_strings (nperiods_combo, s);
1497 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1500 update_sensitivity ();
1504 EngineControl::device_changed ()
1506 SignalBlocker blocker (*this, "device_changed");
1507 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1510 string device_name_in;
1511 string device_name_out; // only used if backend support separate I/O devices
1513 if (backend->use_separate_input_and_output_devices()) {
1514 device_name_in = get_input_device_name ();
1515 device_name_out = get_output_device_name ();
1517 device_name_in = get_device_name ();
1520 /* we set the backend-device to query various device related intormation.
1521 * This has the side effect that backend->device_name() will match
1522 * the device_name and 'change_device' will never be true.
1523 * so work around this by setting...
1525 if (backend->use_separate_input_and_output_devices()) {
1526 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1527 queue_device_changed = true;
1530 if (device_name_in != backend->device_name()) {
1531 queue_device_changed = true;
1535 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1536 if (backend->use_separate_input_and_output_devices()) {
1537 backend->set_input_device_name (device_name_in);
1538 backend->set_output_device_name (device_name_out);
1540 backend->set_device_name(device_name_in);
1544 /* don't allow programmatic change to combos to cause a
1545 recursive call to this method.
1547 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1549 set_samplerate_popdown_strings ();
1550 set_buffersize_popdown_strings ();
1551 set_nperiods_popdown_strings ();
1553 /* TODO set min + max channel counts here */
1555 manage_control_app_sensitivity ();
1558 /* pick up any saved state for this device */
1560 if (!ignore_changes) {
1561 maybe_display_saved_state ();
1566 EngineControl::input_device_changed ()
1568 DEBUG_ECONTROL ("input_device_changed");
1570 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1571 if (backend && backend->match_input_output_devices_or_none ()) {
1572 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1574 if (get_output_device_name () != dev_none
1575 && get_input_device_name () != dev_none
1576 && get_input_device_name () != get_output_device_name ()) {
1577 block_changed_signals ();
1578 if (contains_value (output_device_combo, get_input_device_name ())) {
1579 output_device_combo.set_active_text (get_input_device_name ());
1581 assert (contains_value (output_device_combo, dev_none));
1582 output_device_combo.set_active_text (dev_none);
1584 unblock_changed_signals ();
1591 EngineControl::output_device_changed ()
1593 DEBUG_ECONTROL ("output_device_changed");
1594 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1595 if (backend && backend->match_input_output_devices_or_none ()) {
1596 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1598 if (get_input_device_name () != dev_none
1599 && get_input_device_name () != dev_none
1600 && get_input_device_name () != get_output_device_name ()) {
1601 block_changed_signals ();
1602 if (contains_value (input_device_combo, get_output_device_name ())) {
1603 input_device_combo.set_active_text (get_output_device_name ());
1605 assert (contains_value (input_device_combo, dev_none));
1606 input_device_combo.set_active_text (dev_none);
1608 unblock_changed_signals ();
1615 EngineControl::bufsize_as_string (uint32_t sz)
1617 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1621 EngineControl::sample_rate_changed ()
1623 DEBUG_ECONTROL ("sample_rate_changed");
1624 /* reset the strings for buffer size to show the correct msec value
1625 (reflecting the new sample rate).
1628 show_buffer_duration ();
1633 EngineControl::buffer_size_changed ()
1635 DEBUG_ECONTROL ("buffer_size_changed");
1636 show_buffer_duration ();
1640 EngineControl::nperiods_changed ()
1642 DEBUG_ECONTROL ("nperiods_changed");
1643 show_buffer_duration ();
1647 EngineControl::show_buffer_duration ()
1649 DEBUG_ECONTROL ("show_buffer_duration");
1650 /* buffer sizes - convert from just samples to samples + msecs for
1651 * the displayed string
1654 string bs_text = buffer_size_combo.get_active_text ();
1655 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1656 uint32_t rate = get_rate();
1658 /* Except for ALSA and Dummy backends, we don't know the number of periods
1659 * per cycle and settings.
1661 * jack1 vs jack2 have different default latencies since jack2 start
1662 * in async-mode unless --sync is given which adds an extra cycle
1663 * of latency. The value is not known if jackd is started externally..
1665 * So just display the period size, that's also what
1666 * ARDOUR_UI::update_sample_rate() does for the status bar.
1667 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1668 * but still, that's the buffer period, not [round-trip] latency)
1671 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1672 buffer_size_duration_label.set_text (buf);
1676 EngineControl::midi_option_changed ()
1678 DEBUG_ECONTROL ("midi_option_changed");
1679 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1682 backend->set_midi_option (get_midi_option());
1684 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1686 //_midi_devices.clear(); // TODO merge with state-saved settings..
1687 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1688 std::vector<MidiDeviceSettings> new_devices;
1690 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1691 MidiDeviceSettings mds = find_midi_device (i->name);
1692 if (i->available && !mds) {
1693 uint32_t input_latency = 0;
1694 uint32_t output_latency = 0;
1695 if (_can_set_midi_latencies) {
1696 input_latency = backend->systemic_midi_input_latency (i->name);
1697 output_latency = backend->systemic_midi_output_latency (i->name);
1699 bool enabled = backend->midi_device_enabled (i->name);
1700 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1701 new_devices.push_back (ptr);
1702 } else if (i->available) {
1703 new_devices.push_back (mds);
1706 _midi_devices = new_devices;
1708 if (_midi_devices.empty()) {
1709 midi_devices_button.hide ();
1711 midi_devices_button.show ();
1716 EngineControl::parameter_changed ()
1720 EngineControl::State
1721 EngineControl::get_matching_state (const string& backend)
1723 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1724 if ((*i)->backend == backend) {
1731 EngineControl::State
1732 EngineControl::get_matching_state (
1733 const string& backend,
1734 const string& driver,
1735 const string& device)
1737 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1738 if ((*i)->backend == backend &&
1739 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1747 EngineControl::State
1748 EngineControl::get_matching_state (
1749 const string& backend,
1750 const string& driver,
1751 const string& input_device,
1752 const string& output_device)
1754 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1755 if ((*i)->backend == backend &&
1756 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1764 EngineControl::State
1765 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1767 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1770 if (backend->use_separate_input_and_output_devices ()) {
1771 return get_matching_state (backend_combo.get_active_text(),
1772 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1773 input_device_combo.get_active_text(),
1774 output_device_combo.get_active_text());
1776 return get_matching_state (backend_combo.get_active_text(),
1777 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1778 device_combo.get_active_text());
1782 return get_matching_state (backend_combo.get_active_text(),
1784 device_combo.get_active_text());
1787 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1788 const EngineControl::State& state2)
1790 if (state1->backend == state2->backend &&
1791 state1->driver == state2->driver &&
1792 state1->device == state2->device &&
1793 state1->input_device == state2->input_device &&
1794 state1->output_device == state2->output_device) {
1800 // sort active first, then most recently used to the beginning of the list
1802 EngineControl::state_sort_cmp (const State &a, const State &b) {
1806 else if (b->active) {
1810 return a->lru > b->lru;
1814 EngineControl::State
1815 EngineControl::save_state ()
1819 if (!_have_control) {
1820 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1822 state->lru = time (NULL) ;
1825 state.reset(new StateStruct);
1826 state->backend = get_backend ();
1828 state.reset(new StateStruct);
1829 store_state (state);
1832 for (StateList::iterator i = states.begin(); i != states.end();) {
1833 if (equivalent_states (*i, state)) {
1834 i = states.erase(i);
1840 states.push_back (state);
1842 states.sort (state_sort_cmp);
1848 EngineControl::store_state (State state)
1850 state->backend = get_backend ();
1851 state->driver = get_driver ();
1852 state->device = get_device_name ();
1853 state->input_device = get_input_device_name ();
1854 state->output_device = get_output_device_name ();
1855 state->sample_rate = get_rate ();
1856 state->buffer_size = get_buffer_size ();
1857 state->n_periods = get_nperiods ();
1858 state->input_latency = get_input_latency ();
1859 state->output_latency = get_output_latency ();
1860 state->input_channels = get_input_channels ();
1861 state->output_channels = get_output_channels ();
1862 state->midi_option = get_midi_option ();
1863 state->midi_devices = _midi_devices;
1864 state->use_buffered_io = get_use_buffered_io ();
1865 state->lru = time (NULL) ;
1869 EngineControl::maybe_display_saved_state ()
1871 if (!_have_control) {
1875 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1878 DEBUG_ECONTROL ("Restoring saved state");
1879 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1881 if (!_desired_sample_rate) {
1882 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1884 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1886 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1887 /* call this explicitly because we're ignoring changes to
1888 the controls at this point.
1890 show_buffer_duration ();
1891 input_latency.set_value (state->input_latency);
1892 output_latency.set_value (state->output_latency);
1894 use_buffered_io_button.set_active (state->use_buffered_io);
1896 if (!state->midi_option.empty()) {
1897 midi_option_combo.set_active_text (state->midi_option);
1898 _midi_devices = state->midi_devices;
1901 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1906 EngineControl::get_state ()
1910 XMLNode* root = new XMLNode ("AudioMIDISetup");
1913 if (!states.empty()) {
1914 XMLNode* state_nodes = new XMLNode ("EngineStates");
1916 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1918 XMLNode* node = new XMLNode ("State");
1920 node->set_property ("backend", (*i)->backend);
1921 node->set_property ("driver", (*i)->driver);
1922 node->set_property ("device", (*i)->device);
1923 node->set_property ("input-device", (*i)->input_device);
1924 node->set_property ("output-device", (*i)->output_device);
1925 node->set_property ("sample-rate", (*i)->sample_rate);
1926 node->set_property ("buffer-size", (*i)->buffer_size);
1927 node->set_property ("n-periods", (*i)->n_periods);
1928 node->set_property ("input-latency", (*i)->input_latency);
1929 node->set_property ("output-latency", (*i)->output_latency);
1930 node->set_property ("input-channels", (*i)->input_channels);
1931 node->set_property ("output-channels", (*i)->output_channels);
1932 node->set_property ("active", (*i)->active);
1933 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1934 node->set_property ("midi-option", (*i)->midi_option);
1935 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1936 node->set_property ("lru", lru_val );
1938 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1939 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1940 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1941 midi_device_stuff->set_property (X_("name"), (*p)->name);
1942 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1943 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1944 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1945 midi_devices->add_child_nocopy (*midi_device_stuff);
1947 node->add_child_nocopy (*midi_devices);
1949 state_nodes->add_child_nocopy (*node);
1952 root->add_child_nocopy (*state_nodes);
1959 EngineControl::set_default_state ()
1961 vector<string> backend_names;
1962 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1964 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1965 backend_names.push_back ((*b)->name);
1967 backend_combo.set_active_text (backend_names.front());
1969 // We could set default backends per platform etc here
1975 EngineControl::set_state (const XMLNode& root)
1977 XMLNodeList clist, cclist;
1978 XMLNodeConstIterator citer, cciter;
1979 XMLNode const * child;
1980 XMLNode const * grandchild;
1982 if (root.name() != "AudioMIDISetup") {
1986 clist = root.children();
1990 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1994 if (child->name() != "EngineStates") {
1998 cclist = child->children();
2000 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2001 State state (new StateStruct);
2003 grandchild = *cciter;
2005 if (grandchild->name() != "State") {
2009 if (!grandchild->get_property ("backend", state->backend)) {
2013 // If any of the required properties are not found in the state node
2014 // then continue/skip to the next engine state
2015 if (!grandchild->get_property ("driver", state->driver) ||
2016 !grandchild->get_property ("device", state->device) ||
2017 !grandchild->get_property ("input-device", state->input_device) ||
2018 !grandchild->get_property ("output-device", state->output_device) ||
2019 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2020 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2021 !grandchild->get_property ("input-latency", state->input_latency) ||
2022 !grandchild->get_property ("output-latency", state->output_latency) ||
2023 !grandchild->get_property ("input-channels", state->input_channels) ||
2024 !grandchild->get_property ("output-channels", state->output_channels) ||
2025 !grandchild->get_property ("active", state->active) ||
2026 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2027 !grandchild->get_property ("midi-option", state->midi_option)) {
2031 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2032 // optional (new value in 4.5)
2033 state->n_periods = 0;
2036 state->midi_devices.clear();
2038 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2039 const XMLNodeList mnc = midinode->children();
2040 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2043 uint32_t input_latency;
2044 uint32_t output_latency;
2046 if (!(*n)->get_property (X_("name"), name) ||
2047 !(*n)->get_property (X_("enabled"), enabled) ||
2048 !(*n)->get_property (X_("input-latency"), input_latency) ||
2049 !(*n)->get_property (X_("output-latency"), output_latency)) {
2053 MidiDeviceSettings ptr (
2054 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2055 state->midi_devices.push_back (ptr);
2060 if (grandchild->get_property ("lru", lru_val)) {
2061 state->lru = lru_val;
2064 states.push_back (state);
2068 /* now see if there was an active state and switch the setup to it */
2070 /* purge states of backend that are not available in this built */
2071 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2072 vector<std::string> backend_names;
2074 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2075 backend_names.push_back((*i)->name);
2077 for (StateList::iterator i = states.begin(); i != states.end();) {
2078 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2079 i = states.erase(i);
2085 states.sort (state_sort_cmp);
2087 /* purge old states referring to the same backend */
2088 const time_t now = time (NULL);
2089 for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2091 for (StateList::iterator i = states.begin(); i != states.end();) {
2092 if ((*i)->backend != *bi) {
2095 // keep at latest one for every audio-system
2100 // also keep states used in the last 90 days.
2101 if ((now - (*i)->lru) < 86400 * 90) {
2104 assert (!(*i)->active);
2105 i = states.erase(i);
2109 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2112 return set_current_state (*i);
2119 EngineControl::set_current_state (const State& state)
2121 DEBUG_ECONTROL ("set_current_state");
2123 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2125 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2126 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2127 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2128 // this shouldn't happen as the invalid backend names should have been
2129 // removed from the list of states.
2133 // now reflect the change in the backend in the GUI so backend_changed will
2134 // do the right thing
2135 backend_combo.set_active_text (state->backend);
2137 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2139 // we don't have control don't restore state
2144 if (!state->driver.empty ()) {
2145 if (!backend->requires_driver_selection ()) {
2146 DEBUG_ECONTROL ("Backend should require driver selection");
2147 // A backend has changed from having driver selection to not having
2148 // it or someone has been manually editing a config file and messed
2153 if (backend->set_driver (state->driver) != 0) {
2154 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2155 // Driver names for a backend have changed and the name in the
2156 // config file is now invalid or support for driver is no longer
2157 // included in the backend
2160 // no need to set the driver_combo as backend_changed will use
2161 // backend->driver_name to set the active driver
2164 if (!state->device.empty ()) {
2165 if (backend->set_device_name (state->device) != 0) {
2167 string_compose ("Unable to set device name %1", state->device));
2168 // device is no longer available on the system
2171 // no need to set active device as it will be picked up in
2172 // via backend_changed ()/set_device_popdown_strings
2175 // backend supports separate input/output devices
2176 if (backend->set_input_device_name (state->input_device) != 0) {
2177 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2178 state->input_device));
2179 // input device is no longer available on the system
2183 if (backend->set_output_device_name (state->output_device) != 0) {
2184 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2185 state->input_device));
2186 // output device is no longer available on the system
2189 // no need to set active devices as it will be picked up in via
2190 // backend_changed ()/set_*_device_popdown_strings
2195 // Now restore the state of the rest of the controls
2197 // We don't use a SignalBlocker as set_current_state is currently only
2198 // called from set_state before any signals are connected. If at some point
2199 // a more general named state mechanism is implemented and
2200 // set_current_state is called while signals are connected then a
2201 // SignalBlocker will need to be instantiated before setting these.
2203 device_combo.set_active_text (state->device);
2204 input_device_combo.set_active_text (state->input_device);
2205 output_device_combo.set_active_text (state->output_device);
2206 if (!_desired_sample_rate) {
2207 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2209 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2210 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2211 input_latency.set_value (state->input_latency);
2212 output_latency.set_value (state->output_latency);
2213 midi_option_combo.set_active_text (state->midi_option);
2214 use_buffered_io_button.set_active (state->use_buffered_io);
2219 EngineControl::push_state_to_backend (bool start)
2221 DEBUG_ECONTROL ("push_state_to_backend");
2222 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2223 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2229 /* figure out what is going to change */
2231 bool restart_required = false;
2232 bool was_running = ARDOUR::AudioEngine::instance()->running();
2233 bool change_driver = false;
2234 bool change_device = false;
2235 bool change_rate = false;
2236 bool change_bufsize = false;
2237 bool change_nperiods = false;
2238 bool change_latency = false;
2239 bool change_channels = false;
2240 bool change_midi = false;
2241 bool change_buffered_io = false;
2243 uint32_t ochan = get_output_channels ();
2244 uint32_t ichan = get_input_channels ();
2246 if (_have_control) {
2248 if (started_at_least_once) {
2250 /* we can control the backend */
2252 if (backend->requires_driver_selection()) {
2253 if (get_driver() != backend->driver_name()) {
2254 change_driver = true;
2258 if (backend->use_separate_input_and_output_devices()) {
2259 if (get_input_device_name() != backend->input_device_name()) {
2260 change_device = true;
2262 if (get_output_device_name() != backend->output_device_name()) {
2263 change_device = true;
2266 if (get_device_name() != backend->device_name()) {
2267 change_device = true;
2271 if (queue_device_changed) {
2272 change_device = true;
2275 if (get_rate() != backend->sample_rate()) {
2279 if (get_buffer_size() != backend->buffer_size()) {
2280 change_bufsize = true;
2283 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2284 && get_nperiods() != backend->period_size()) {
2285 change_nperiods = true;
2288 if (get_midi_option() != backend->midi_option()) {
2292 if (backend->can_use_buffered_io()) {
2293 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2294 change_buffered_io = true;
2298 /* zero-requested channels means "all available" */
2301 ichan = backend->input_channels();
2305 ochan = backend->output_channels();
2308 if (ichan != backend->input_channels()) {
2309 change_channels = true;
2312 if (ochan != backend->output_channels()) {
2313 change_channels = true;
2316 if (get_input_latency() != backend->systemic_input_latency() ||
2317 get_output_latency() != backend->systemic_output_latency()) {
2318 change_latency = true;
2321 /* backend never started, so we have to force a group
2324 change_device = true;
2325 if (backend->requires_driver_selection()) {
2326 change_driver = true;
2329 change_bufsize = true;
2330 change_channels = true;
2331 change_latency = true;
2333 change_buffered_io = backend->can_use_buffered_io();
2334 change_channels = true;
2335 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2340 /* we have no control over the backend, meaning that we can
2341 * only possibly change sample rate and buffer size.
2345 if (get_rate() != backend->sample_rate()) {
2346 change_bufsize = true;
2349 if (get_buffer_size() != backend->buffer_size()) {
2350 change_bufsize = true;
2354 queue_device_changed = false;
2356 if (!_have_control) {
2358 /* We do not have control over the backend, so the best we can
2359 * do is try to change the sample rate and/or bufsize and get
2363 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2367 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2372 backend->set_sample_rate (get_rate());
2375 if (change_bufsize) {
2376 backend->set_buffer_size (get_buffer_size());
2380 if (ARDOUR::AudioEngine::instance()->start ()) {
2381 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2391 /* determine if we need to stop the backend before changing parameters */
2393 if (change_driver || change_device || change_channels || change_nperiods ||
2394 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2395 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2396 change_midi || change_buffered_io ||
2397 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2398 restart_required = true;
2400 restart_required = false;
2405 if (restart_required) {
2406 if (ARDOUR::AudioEngine::instance()->stop()) {
2412 if (change_driver && backend->set_driver (get_driver())) {
2413 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2416 if (backend->use_separate_input_and_output_devices()) {
2417 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2418 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2421 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2422 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2426 if (change_device && backend->set_device_name (get_device_name())) {
2427 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2431 if (change_rate && backend->set_sample_rate (get_rate())) {
2432 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2435 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2436 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2439 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2440 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2444 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2445 if (backend->set_input_channels (get_input_channels())) {
2446 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2449 if (backend->set_output_channels (get_output_channels())) {
2450 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2454 if (change_latency) {
2455 if (backend->set_systemic_input_latency (get_input_latency())) {
2456 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2459 if (backend->set_systemic_output_latency (get_output_latency())) {
2460 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2466 backend->set_midi_option (get_midi_option());
2469 if (change_buffered_io) {
2470 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2474 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2475 if (_measure_midi) {
2476 if (*p == _measure_midi) {
2477 backend->set_midi_device_enabled ((*p)->name, true);
2479 backend->set_midi_device_enabled ((*p)->name, false);
2481 if (backend->can_change_systemic_latency_when_running ()) {
2482 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2483 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2487 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2488 if (backend->can_set_systemic_midi_latencies()) {
2489 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2490 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2495 if (start || (was_running && restart_required)) {
2496 if (ARDOUR::AudioEngine::instance()->start()) {
2507 EngineControl::post_push ()
2509 /* get a pointer to the current state object, creating one if
2513 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2516 state = save_state ();
2522 states.sort (state_sort_cmp);
2526 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2527 (*i)->active = false;
2530 /* mark this one active (to be used next time the dialog is
2534 state->active = true;
2536 if (_have_control) { // XXX
2537 manage_control_app_sensitivity ();
2540 /* schedule a redisplay of MIDI ports */
2541 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2546 EngineControl::get_rate () const
2548 float r = atof (sample_rate_combo.get_active_text ());
2549 /* the string may have been translated with an abbreviation for
2550 * thousands, so use a crude heuristic to fix this.
2560 EngineControl::get_buffer_size () const
2562 string txt = buffer_size_combo.get_active_text ();
2565 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2566 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2567 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2575 EngineControl::get_nperiods () const
2577 string txt = nperiods_combo.get_active_text ();
2578 return atoi (txt.c_str());
2582 EngineControl::get_midi_option () const
2584 return midi_option_combo.get_active_text();
2588 EngineControl::get_use_buffered_io () const
2590 return use_buffered_io_button.get_active();
2594 EngineControl::get_input_channels() const
2596 if (ARDOUR::Profile->get_mixbus()) {
2597 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2598 if (!backend) return 0;
2599 return backend->input_channels();
2601 return (uint32_t) input_channels_adjustment.get_value();
2605 EngineControl::get_output_channels() const
2607 if (ARDOUR::Profile->get_mixbus()) {
2608 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2609 if (!backend) return 0;
2610 return backend->input_channels();
2612 return (uint32_t) output_channels_adjustment.get_value();
2616 EngineControl::get_input_latency() const
2618 return (uint32_t) input_latency_adjustment.get_value();
2622 EngineControl::get_output_latency() const
2624 return (uint32_t) output_latency_adjustment.get_value();
2628 EngineControl::get_backend () const
2630 return backend_combo.get_active_text ();
2634 EngineControl::get_driver () const
2636 if (driver_combo.get_parent()) {
2637 return driver_combo.get_active_text ();
2644 EngineControl::get_device_name () const
2646 return device_combo.get_active_text ();
2650 EngineControl::get_input_device_name () const
2652 return input_device_combo.get_active_text ();
2656 EngineControl::get_output_device_name () const
2658 return output_device_combo.get_active_text ();
2662 EngineControl::control_app_button_clicked ()
2664 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2670 backend->launch_control_app ();
2674 EngineControl::start_stop_button_clicked ()
2676 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2682 if (ARDOUR::AudioEngine::instance()->running()) {
2683 ARDOUR::AudioEngine::instance()->stop ();
2685 if (!ARDOUR_UI::instance()->session_loaded) {
2691 if (!ARDOUR_UI::instance()->session_loaded) {
2692 ArdourDialog::on_response (RESPONSE_OK);
2698 EngineControl::update_devices_button_clicked ()
2700 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2706 if (backend->update_devices()) {
2707 device_list_changed ();
2712 EngineControl::use_buffered_io_button_clicked ()
2714 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2720 bool set_buffered_io = !use_buffered_io_button.get_active();
2721 use_buffered_io_button.set_active (set_buffered_io);
2722 backend->set_use_buffered_io (set_buffered_io);
2726 EngineControl::manage_control_app_sensitivity ()
2728 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2734 string appname = backend->control_app_name();
2736 if (appname.empty()) {
2737 control_app_button.set_sensitive (false);
2739 control_app_button.set_sensitive (true);
2744 EngineControl::set_desired_sample_rate (uint32_t sr)
2746 _desired_sample_rate = sr;
2747 if (ARDOUR::AudioEngine::instance ()->running ()
2748 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2755 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2757 if (page_num == 0) {
2758 _measure_midi.reset();
2759 update_sensitivity ();
2762 if (page_num == midi_tab) {
2764 refresh_midi_display ();
2767 if (page_num == latency_tab) {
2770 if (ARDOUR::AudioEngine::instance()->running()) {
2775 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2777 /* save any existing latency values */
2779 uint32_t il = (uint32_t) input_latency.get_value ();
2780 uint32_t ol = (uint32_t) input_latency.get_value ();
2782 /* reset to zero so that our new test instance
2783 will be clean of any existing latency measures.
2785 NB. this should really be done by the backend
2786 when stated for latency measurement.
2789 input_latency.set_value (0);
2790 output_latency.set_value (0);
2792 push_state_to_backend (false);
2796 input_latency.set_value (il);
2797 output_latency.set_value (ol);
2800 // This should be done in push_state_to_backend()
2801 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2802 disable_latency_tab ();
2805 enable_latency_tab ();
2809 end_latency_detection ();
2810 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2815 /* latency measurement */
2818 EngineControl::check_audio_latency_measurement ()
2820 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2822 if (mtdm->resolve () < 0) {
2823 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2827 if (mtdm->get_peak () > 0.707f) {
2828 // get_peak() resets the peak-hold in the detector.
2829 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2830 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2834 if (mtdm->err () > 0.3) {
2840 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2842 if (sample_rate == 0) {
2843 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2844 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2848 int frames_total = mtdm->del();
2849 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2851 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2852 _("Detected roundtrip latency: "),
2853 frames_total, frames_total * 1000.0f/sample_rate,
2854 _("Systemic latency: "),
2855 extra, extra * 1000.0f/sample_rate);
2859 if (mtdm->err () > 0.2) {
2861 strcat (buf, _("(signal detection error)"));
2867 strcat (buf, _("(inverted - bad wiring)"));
2871 lm_results.set_markup (string_compose (results_markup, buf));
2874 have_lm_results = true;
2875 end_latency_detection ();
2876 lm_use_button.set_sensitive (true);
2884 EngineControl::check_midi_latency_measurement ()
2886 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2888 if (!mididm->have_signal () || mididm->latency () == 0) {
2889 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2894 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2896 if (sample_rate == 0) {
2897 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2898 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2902 ARDOUR::framecnt_t frames_total = mididm->latency();
2903 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2904 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2905 _("Detected roundtrip latency: "),
2906 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2907 _("Systemic latency: "),
2908 extra, extra * 1000.0f / sample_rate);
2912 if (!mididm->ok ()) {
2914 strcat (buf, _("(averaging)"));
2918 if (mididm->deviation () > 50.0) {
2920 strcat (buf, _("(too large jitter)"));
2922 } else if (mididm->deviation () > 10.0) {
2924 strcat (buf, _("(large jitter)"));
2928 have_lm_results = true;
2929 end_latency_detection ();
2930 lm_use_button.set_sensitive (true);
2931 lm_results.set_markup (string_compose (results_markup, buf));
2933 } else if (mididm->processed () > 400) {
2934 have_lm_results = false;
2935 end_latency_detection ();
2936 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2940 lm_results.set_markup (string_compose (results_markup, buf));
2946 EngineControl::start_latency_detection ()
2948 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2949 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2951 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2952 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2953 if (_measure_midi) {
2954 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2956 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2958 lm_measure_label.set_text (_("Cancel"));
2959 have_lm_results = false;
2960 lm_use_button.set_sensitive (false);
2961 lm_input_channel_combo.set_sensitive (false);
2962 lm_output_channel_combo.set_sensitive (false);
2968 EngineControl::end_latency_detection ()
2970 latency_timeout.disconnect ();
2971 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2972 lm_measure_label.set_text (_("Measure"));
2973 if (!have_lm_results) {
2974 lm_use_button.set_sensitive (false);
2976 lm_input_channel_combo.set_sensitive (true);
2977 lm_output_channel_combo.set_sensitive (true);
2982 EngineControl::latency_button_clicked ()
2985 start_latency_detection ();
2987 end_latency_detection ();
2992 EngineControl::latency_back_button_clicked ()
2994 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2995 notebook.set_current_page(0);
2999 EngineControl::use_latency_button_clicked ()
3001 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3002 if (_measure_midi) {
3003 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3007 ARDOUR::framecnt_t frames_total = mididm->latency();
3008 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3009 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3010 _measure_midi->input_latency = one_way;
3011 _measure_midi->output_latency = one_way;
3012 if (backend->can_change_systemic_latency_when_running ()) {
3013 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3014 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3016 notebook.set_current_page (midi_tab);
3018 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3024 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3025 one_way = std::max (0., one_way);
3027 input_latency_adjustment.set_value (one_way);
3028 output_latency_adjustment.set_value (one_way);
3029 if (backend->can_change_systemic_latency_when_running ()) {
3030 backend->set_systemic_input_latency (one_way);
3031 backend->set_systemic_output_latency (one_way);
3034 /* back to settings page */
3035 notebook.set_current_page (0);
3040 EngineControl::on_delete_event (GdkEventAny* ev)
3042 if (notebook.get_current_page() == 2) {
3043 /* currently on latency tab - be sure to clean up */
3044 end_latency_detection ();
3046 return ArdourDialog::on_delete_event (ev);
3050 EngineControl::engine_running ()
3052 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3055 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3056 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3058 if (backend->can_set_period_size ()) {
3059 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3062 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3063 connect_disconnect_button.show();
3065 started_at_least_once = true;
3066 if (_have_control) {
3067 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3069 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3071 update_sensitivity();
3075 EngineControl::engine_stopped ()
3077 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3080 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3081 connect_disconnect_button.show();
3083 if (_have_control) {
3084 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3086 engine_status.set_markup(X_(""));
3089 update_sensitivity();
3093 EngineControl::device_list_changed ()
3095 if (ignore_device_changes) {
3098 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3100 midi_option_changed();
3104 EngineControl::connect_disconnect_click()
3106 if (ARDOUR::AudioEngine::instance()->running()) {
3109 if (!ARDOUR_UI::instance()->session_loaded) {
3115 if (!ARDOUR_UI::instance()->session_loaded) {
3116 ArdourDialog::on_response (RESPONSE_OK);
3122 EngineControl::calibrate_audio_latency ()
3124 _measure_midi.reset ();
3125 have_lm_results = false;
3126 lm_use_button.set_sensitive (false);
3127 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3128 notebook.set_current_page (latency_tab);
3132 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3135 have_lm_results = false;
3136 lm_use_button.set_sensitive (false);
3137 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3138 notebook.set_current_page (latency_tab);
3142 EngineControl::configure_midi_devices ()
3144 notebook.set_current_page (midi_tab);