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 ArdourWidgets;
68 using namespace ARDOUR_UI_UTILS;
70 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
72 static const unsigned int midi_tab = 2;
73 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
75 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
77 EngineControl::EngineControl ()
78 : ArdourDialog (_("Audio/MIDI Setup"))
81 , input_latency_adjustment (0, 0, 99999, 1)
82 , input_latency (input_latency_adjustment)
83 , output_latency_adjustment (0, 0, 99999, 1)
84 , output_latency (output_latency_adjustment)
85 , input_channels_adjustment (0, 0, 256, 1)
86 , input_channels (input_channels_adjustment)
87 , output_channels_adjustment (0, 0, 256, 1)
88 , output_channels (output_channels_adjustment)
89 , ports_adjustment (128, 8, 1024, 1, 16)
90 , ports_spinner (ports_adjustment)
91 , control_app_button (_("Device Control Panel"))
92 , midi_devices_button (_("Midi Device Setup"))
93 , start_stop_button (_("Stop"))
94 , update_devices_button (_("Refresh Devices"))
95 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
96 , lm_measure_label (_("Measure"))
97 , lm_use_button (_("Use results"))
98 , lm_back_button (_("Back to settings ... (ignore results)"))
99 , lm_button_audio (_("Calibrate Audio"))
101 , have_lm_results (false)
103 , midi_back_button (_("Back to settings"))
105 , ignore_device_changes (0)
106 , _desired_sample_rate (0)
107 , started_at_least_once (false)
108 , queue_device_changed (false)
109 , _have_control (true)
112 using namespace Notebook_Helpers;
113 vector<string> backend_names;
115 AttachOptions xopt = AttachOptions (FILL|EXPAND);
118 set_name (X_("AudioMIDISetup"));
120 /* the backend combo is the one thing that is ALWAYS visible */
122 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
124 if (backends.empty()) {
125 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));
127 throw failed_constructor ();
130 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
131 backend_names.push_back ((*b)->name);
134 set_popdown_strings (backend_combo, backend_names);
136 /* setup basic packing characteristics for the table used on the main
137 * tab of the notebook
140 basic_packer.set_spacings (6);
141 basic_packer.set_border_width (12);
142 basic_packer.set_homogeneous (false);
146 basic_hbox.pack_start (basic_packer, false, false);
148 /* latency measurement tab */
150 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
153 lm_table.set_row_spacings (12);
154 lm_table.set_col_spacings (6);
155 lm_table.set_homogeneous (false);
157 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
160 lm_preamble.set_width_chars (60);
161 lm_preamble.set_line_wrap (true);
162 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
164 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
167 Gtk::Label* preamble;
168 preamble = manage (new Label);
169 preamble->set_width_chars (60);
170 preamble->set_line_wrap (true);
171 preamble->set_markup (_("Select two channels below and connect them using a cable."));
173 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
176 label = manage (new Label (_("Output channel")));
177 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
179 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
180 misc_align->add (lm_output_channel_combo);
181 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
184 label = manage (new Label (_("Input channel")));
185 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
187 misc_align = manage (new Alignment (0.0, 0.5));
188 misc_align->add (lm_input_channel_combo);
189 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
192 lm_measure_label.set_padding (10, 10);
193 lm_measure_button.add (lm_measure_label);
194 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
195 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
196 lm_back_button_signal = lm_back_button.signal_clicked().connect(
197 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
199 lm_use_button.set_sensitive (false);
201 /* Increase the default spacing around the labels of these three
207 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
208 l->set_padding (10, 10);
211 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
212 l->set_padding (10, 10);
215 preamble = manage (new Label);
216 preamble->set_width_chars (60);
217 preamble->set_line_wrap (true);
218 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
219 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222 preamble = manage (new Label);
223 preamble->set_width_chars (60);
224 preamble->set_line_wrap (true);
225 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
226 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 ++row; // skip a row in the table
229 ++row; // skip a row in the table
231 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 ++row; // skip a row in the table
234 ++row; // skip a row in the table
236 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
237 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
238 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
240 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
242 lm_vbox.set_border_width (12);
243 lm_vbox.pack_start (lm_table, false, false);
245 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
249 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
250 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
251 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
252 notebook.set_border_width (12);
254 notebook.set_show_tabs (false);
255 notebook.show_all ();
257 notebook.set_name ("SettingsNotebook");
259 /* packup the notebook */
261 get_vbox()->set_border_width (12);
262 get_vbox()->pack_start (notebook);
264 /* need a special function to print "all available channels" when the
265 * channel counts hit zero.
268 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
269 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
271 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
272 midi_devices_button.set_name ("generic button");
273 midi_devices_button.set_can_focus(true);
275 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
276 control_app_button.set_name ("generic button");
277 control_app_button.set_can_focus(true);
278 manage_control_app_sensitivity ();
280 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
281 start_stop_button.set_sensitive (false);
282 start_stop_button.set_name ("generic button");
283 start_stop_button.set_can_focus(true);
284 start_stop_button.set_can_default(true);
285 start_stop_button.set_act_on_release (false);
287 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
288 update_devices_button.set_sensitive (false);
289 update_devices_button.set_name ("generic button");
290 update_devices_button.set_can_focus(true);
292 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
293 use_buffered_io_button.set_sensitive (false);
294 use_buffered_io_button.set_name ("generic button");
295 use_buffered_io_button.set_can_focus(true);
297 /* Pick up any existing audio setup configuration, if appropriate */
299 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
301 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
302 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
303 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
304 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
307 if (!set_state (*audio_setup)) {
308 set_default_state ();
311 set_default_state ();
314 update_sensitivity ();
315 connect_changed_signals ();
317 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
319 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
321 connect_disconnect_button.set_no_show_all();
322 use_buffered_io_button.set_no_show_all();
323 update_devices_button.set_no_show_all();
324 start_stop_button.set_no_show_all();
325 midi_devices_button.set_no_show_all();
329 EngineControl::connect_changed_signals ()
331 backend_combo_connection = backend_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::backend_changed));
333 driver_combo_connection = driver_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::driver_changed));
335 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
337 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
339 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
341 device_combo_connection = device_combo.signal_changed ().connect (
342 sigc::mem_fun (*this, &EngineControl::device_changed));
343 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
344 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
346 input_device_combo_connection = input_device_combo.signal_changed ().connect (
347 sigc::mem_fun (*this, &EngineControl::input_device_changed));
348 output_device_combo_connection = output_device_combo.signal_changed ().connect (
349 sigc::mem_fun (*this, &EngineControl::output_device_changed));
351 input_latency_connection = input_latency.signal_changed ().connect (
352 sigc::mem_fun (*this, &EngineControl::parameter_changed));
353 output_latency_connection = output_latency.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::parameter_changed));
355 input_channels_connection = input_channels.signal_changed ().connect (
356 sigc::mem_fun (*this, &EngineControl::parameter_changed));
357 output_channels_connection = output_channels.signal_changed ().connect (
358 sigc::mem_fun (*this, &EngineControl::parameter_changed));
362 EngineControl::block_changed_signals ()
364 if (block_signals++ == 0) {
365 DEBUG_ECONTROL ("Blocking changed signals");
366 backend_combo_connection.block ();
367 driver_combo_connection.block ();
368 sample_rate_combo_connection.block ();
369 buffer_size_combo_connection.block ();
370 nperiods_combo_connection.block ();
371 device_combo_connection.block ();
372 input_device_combo_connection.block ();
373 output_device_combo_connection.block ();
374 midi_option_combo_connection.block ();
375 input_latency_connection.block ();
376 output_latency_connection.block ();
377 input_channels_connection.block ();
378 output_channels_connection.block ();
383 EngineControl::unblock_changed_signals ()
385 if (--block_signals == 0) {
386 DEBUG_ECONTROL ("Unblocking changed signals");
387 backend_combo_connection.unblock ();
388 driver_combo_connection.unblock ();
389 sample_rate_combo_connection.unblock ();
390 buffer_size_combo_connection.unblock ();
391 nperiods_combo_connection.unblock ();
392 device_combo_connection.unblock ();
393 input_device_combo_connection.unblock ();
394 output_device_combo_connection.unblock ();
395 midi_option_combo_connection.unblock ();
396 input_latency_connection.unblock ();
397 output_latency_connection.unblock ();
398 input_channels_connection.unblock ();
399 output_channels_connection.unblock ();
403 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
404 const std::string& reason)
405 : ec (engine_control)
408 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
409 ec.block_changed_signals ();
412 EngineControl::SignalBlocker::~SignalBlocker ()
414 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
415 ec.unblock_changed_signals ();
419 EngineControl::on_show ()
421 ArdourDialog::on_show ();
422 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
423 // re-check _have_control (jackd running) see #6041
427 start_stop_button.grab_focus();
431 EngineControl::on_map ()
433 if (!ARDOUR_UI::instance()->session_loaded && !PublicEditor::_instance) {
434 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
435 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
436 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
438 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
440 ArdourDialog::on_map ();
444 EngineControl::try_autostart ()
446 if (!start_stop_button.get_sensitive()) {
449 if (ARDOUR::AudioEngine::instance()->running()) {
452 return start_engine ();
456 EngineControl::start_engine ()
458 if (push_state_to_backend(true) != 0) {
459 MessageDialog msg(*this,
460 ARDOUR::AudioEngine::instance()->get_last_backend_error());
468 EngineControl::stop_engine (bool for_latency)
470 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
471 MessageDialog msg(*this,
472 ARDOUR::AudioEngine::instance()->get_last_backend_error());
480 EngineControl::build_notebook ()
483 AttachOptions xopt = AttachOptions (FILL|EXPAND);
485 /* clear the table */
487 Gtkmm2ext::container_clear (basic_vbox);
488 Gtkmm2ext::container_clear (basic_packer);
490 if (control_app_button.get_parent()) {
491 control_app_button.get_parent()->remove (control_app_button);
494 label = manage (left_aligned_label (_("Audio System:")));
495 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
496 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
498 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
499 engine_status.show();
501 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
502 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
503 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
505 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
506 lm_button_audio.set_name ("generic button");
507 lm_button_audio.set_can_focus(true);
510 build_full_control_notebook ();
512 build_no_control_notebook ();
515 basic_vbox.pack_start (basic_hbox, false, false);
518 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
519 basic_vbox.show_all ();
524 EngineControl::build_full_control_notebook ()
526 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
529 using namespace Notebook_Helpers;
531 vector<string> strings;
532 AttachOptions xopt = AttachOptions (FILL|EXPAND);
533 int row = 1; // row zero == backend combo
535 /* start packing it up */
537 if (backend->requires_driver_selection()) {
538 label = manage (left_aligned_label (_("Driver:")));
539 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
540 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
544 if (backend->use_separate_input_and_output_devices()) {
545 label = manage (left_aligned_label (_("Input Device:")));
546 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
547 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
549 label = manage (left_aligned_label (_("Output Device:")));
550 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
551 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
553 // reset so it isn't used in state comparisons
554 device_combo.set_active_text ("");
556 label = manage (left_aligned_label (_("Device:")));
557 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
558 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
560 // reset these so they don't get used in state comparisons
561 input_device_combo.set_active_text ("");
562 output_device_combo.set_active_text ("");
565 label = manage (left_aligned_label (_("Sample rate:")));
566 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
567 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
571 label = manage (left_aligned_label (_("Buffer size:")));
572 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 buffer_size_duration_label.set_alignment (0.0); /* left-align */
575 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
577 int ctrl_btn_span = 1;
578 if (backend->can_set_period_size ()) {
580 label = manage (left_aligned_label (_("Periods:")));
581 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
582 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
586 /* button spans 2 or 3 rows */
588 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
591 input_channels.set_name ("InputChannels");
592 input_channels.set_flags (Gtk::CAN_FOCUS);
593 input_channels.set_digits (0);
594 input_channels.set_wrap (false);
595 output_channels.set_editable (true);
597 if (!ARDOUR::Profile->get_mixbus()) {
598 label = manage (left_aligned_label (_("Input Channels:")));
599 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
600 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
604 output_channels.set_name ("OutputChannels");
605 output_channels.set_flags (Gtk::CAN_FOCUS);
606 output_channels.set_digits (0);
607 output_channels.set_wrap (false);
608 output_channels.set_editable (true);
610 if (!ARDOUR::Profile->get_mixbus()) {
611 label = manage (left_aligned_label (_("Output Channels:")));
612 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
613 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
617 input_latency.set_name ("InputLatency");
618 input_latency.set_flags (Gtk::CAN_FOCUS);
619 input_latency.set_digits (0);
620 input_latency.set_wrap (false);
621 input_latency.set_editable (true);
623 label = manage (left_aligned_label (_("Hardware input latency:")));
624 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
625 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
626 label = manage (left_aligned_label (_("samples")));
627 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
630 output_latency.set_name ("OutputLatency");
631 output_latency.set_flags (Gtk::CAN_FOCUS);
632 output_latency.set_digits (0);
633 output_latency.set_wrap (false);
634 output_latency.set_editable (true);
636 label = manage (left_aligned_label (_("Hardware output latency:")));
637 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
638 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
639 label = manage (left_aligned_label (_("samples")));
640 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
642 /* button spans 2 rows */
644 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
647 label = manage (left_aligned_label (_("MIDI System:")));
648 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
649 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
650 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
655 EngineControl::build_no_control_notebook ()
657 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
660 using namespace Notebook_Helpers;
662 vector<string> strings;
663 AttachOptions xopt = AttachOptions (FILL|EXPAND);
664 int row = 1; // row zero == backend combo
665 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
667 label = manage (new Label);
668 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
669 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
672 if (backend->can_change_sample_rate_when_running()) {
673 label = manage (left_aligned_label (_("Sample rate:")));
674 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
675 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
679 if (backend->can_change_buffer_size_when_running()) {
680 label = manage (left_aligned_label (_("Buffer size:")));
681 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
682 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
683 buffer_size_duration_label.set_alignment (0.0); /* left-align */
684 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
688 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
692 EngineControl::~EngineControl ()
694 ignore_changes = true;
698 EngineControl::disable_latency_tab ()
700 vector<string> empty;
701 set_popdown_strings (lm_output_channel_combo, empty);
702 set_popdown_strings (lm_input_channel_combo, empty);
703 lm_measure_button.set_sensitive (false);
704 lm_use_button.set_sensitive (false);
708 EngineControl::enable_latency_tab ()
710 vector<string> outputs;
711 vector<string> inputs;
713 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
714 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
715 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
717 if (!ARDOUR::AudioEngine::instance()->running()) {
718 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
719 notebook.set_current_page (0);
723 else if (inputs.empty() || outputs.empty()) {
724 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
725 notebook.set_current_page (0);
730 lm_back_button_signal.disconnect();
732 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
735 lm_back_button_signal = lm_back_button.signal_clicked().connect(
736 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
740 set_popdown_strings (lm_output_channel_combo, outputs);
741 lm_output_channel_combo.set_active_text (outputs.front());
742 lm_output_channel_combo.set_sensitive (true);
744 set_popdown_strings (lm_input_channel_combo, inputs);
745 lm_input_channel_combo.set_active_text (inputs.front());
746 lm_input_channel_combo.set_sensitive (true);
748 lm_measure_button.set_sensitive (true);
752 EngineControl::setup_midi_tab_for_backend ()
754 string backend = backend_combo.get_active_text ();
756 Gtkmm2ext::container_clear (midi_vbox);
758 midi_vbox.set_border_width (12);
759 midi_device_table.set_border_width (12);
761 if (backend == "JACK") {
762 setup_midi_tab_for_jack ();
765 midi_vbox.pack_start (midi_device_table, true, true);
766 midi_vbox.pack_start (midi_back_button, false, false);
767 midi_vbox.show_all ();
771 EngineControl::update_sensitivity ()
773 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
775 start_stop_button.set_sensitive (false);
780 size_t devices_available = 0;
781 bool engine_running = ARDOUR::AudioEngine::instance()->running();
783 if (backend->use_separate_input_and_output_devices ()) {
784 devices_available += get_popdown_string_count (input_device_combo);
785 devices_available += get_popdown_string_count (output_device_combo);
787 devices_available += get_popdown_string_count (device_combo);
790 if (devices_available == 0) {
792 input_latency.set_sensitive (false);
793 output_latency.set_sensitive (false);
794 input_channels.set_sensitive (false);
795 output_channels.set_sensitive (false);
797 input_latency.set_sensitive (true);
798 output_latency.set_sensitive (true);
799 input_channels.set_sensitive (!engine_running);
800 output_channels.set_sensitive (!engine_running);
803 if (get_popdown_string_count (buffer_size_combo) > 0) {
804 if (!engine_running) {
805 buffer_size_combo.set_sensitive (valid);
806 } else if (backend->can_change_sample_rate_when_running()) {
807 buffer_size_combo.set_sensitive (valid || !_have_control);
811 * Currently there is no way to manually stop the
812 * engine in order to re-configure it.
813 * This needs to remain sensitive for now.
815 * (it's also handy to implicily
816 * re-start the engine)
818 buffer_size_combo.set_sensitive (true);
820 buffer_size_combo.set_sensitive (false);
824 buffer_size_combo.set_sensitive (false);
828 if (get_popdown_string_count (sample_rate_combo) > 0) {
829 bool allow_to_set_rate = false;
830 if (!engine_running) {
831 if (!ARDOUR_UI::instance()->session_loaded) {
832 // engine is not running, no session loaded -> anything goes.
833 allow_to_set_rate = true;
834 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
835 // only allow to change if the current setting is not the native session rate.
836 allow_to_set_rate = true;
839 sample_rate_combo.set_sensitive (allow_to_set_rate);
841 sample_rate_combo.set_sensitive (false);
845 if (get_popdown_string_count (nperiods_combo) > 0) {
846 if (!engine_running) {
847 nperiods_combo.set_sensitive (true);
849 nperiods_combo.set_sensitive (false);
852 nperiods_combo.set_sensitive (false);
856 start_stop_button.set_sensitive(true);
857 start_stop_button.show();
858 if (engine_running) {
859 start_stop_button.set_text("Stop");
860 update_devices_button.set_sensitive(false);
861 use_buffered_io_button.set_sensitive(false);
863 if (backend->can_request_update_devices()) {
864 update_devices_button.show();
866 update_devices_button.hide();
868 if (backend->can_use_buffered_io()) {
869 use_buffered_io_button.show();
871 use_buffered_io_button.hide();
873 start_stop_button.set_text("Start");
874 update_devices_button.set_sensitive(true);
875 use_buffered_io_button.set_sensitive(true);
878 update_devices_button.set_sensitive(false);
879 update_devices_button.hide();
880 use_buffered_io_button.set_sensitive(false);
881 use_buffered_io_button.hide();
882 start_stop_button.set_sensitive(false);
883 start_stop_button.hide();
886 if (engine_running && _have_control) {
887 input_device_combo.set_sensitive (false);
888 output_device_combo.set_sensitive (false);
889 device_combo.set_sensitive (false);
890 driver_combo.set_sensitive (false);
892 input_device_combo.set_sensitive (true);
893 output_device_combo.set_sensitive (true);
894 device_combo.set_sensitive (true);
895 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
896 driver_combo.set_sensitive (true);
898 driver_combo.set_sensitive (false);
902 midi_option_combo.set_sensitive (!engine_running);
906 EngineControl::setup_midi_tab_for_jack ()
911 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
913 device->input_latency = a->get_value();
915 device->output_latency = a->get_value();
920 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
921 b->set_active (!b->get_active());
922 device->enabled = b->get_active();
923 refresh_midi_display(device->name);
927 EngineControl::refresh_midi_display (std::string focus)
929 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
933 AttachOptions xopt = AttachOptions (FILL|EXPAND);
936 Gtkmm2ext::container_clear (midi_device_table);
938 midi_device_table.set_spacings (6);
940 l = manage (new Label);
941 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
942 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
943 l->set_alignment (0.5, 0.5);
947 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
948 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
949 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
950 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
952 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
953 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
954 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
955 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
958 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
963 bool enabled = (*p)->enabled;
965 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
966 m->set_name ("midi device");
967 m->set_can_focus (Gtk::CAN_FOCUS);
968 m->add_events (Gdk::BUTTON_RELEASE_MASK);
969 m->set_active (enabled);
970 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
971 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
972 if ((*p)->name == focus) {
976 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
977 s = manage (new Gtk::SpinButton (*a));
978 a->set_value ((*p)->input_latency);
979 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
980 s->set_sensitive (_can_set_midi_latencies && enabled);
981 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
983 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
984 s = manage (new Gtk::SpinButton (*a));
985 a->set_value ((*p)->output_latency);
986 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
987 s->set_sensitive (_can_set_midi_latencies && enabled);
988 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
990 b = manage (new Button (_("Calibrate")));
991 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
992 b->set_sensitive (_can_set_midi_latencies && enabled);
993 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1000 EngineControl::backend_changed ()
1002 SignalBlocker blocker (*this, "backend_changed");
1003 string backend_name = backend_combo.get_active_text();
1004 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1006 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1007 /* eh? setting the backend failed... how ? */
1008 /* A: stale config contains a backend that does not exist in current build */
1012 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1014 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1017 setup_midi_tab_for_backend ();
1018 _midi_devices.clear();
1020 if (backend->requires_driver_selection()) {
1021 if (set_driver_popdown_strings ()) {
1025 /* this will change the device text which will cause a call to
1026 * device changed which will set up parameters
1031 update_midi_options ();
1033 connect_disconnect_button.hide();
1035 midi_option_changed();
1037 started_at_least_once = false;
1039 /* changing the backend implies stopping the engine
1040 * ARDOUR::AudioEngine() may or may not emit this signal
1041 * depending on previous engine state
1043 engine_stopped (); // set "active/inactive"
1045 if (!_have_control) {
1046 // set settings from backend that we do have control over
1047 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1050 if (_have_control && !ignore_changes) {
1051 // set driver & devices
1052 State state = get_matching_state (backend_combo.get_active_text());
1054 DEBUG_ECONTROL ("backend-changed(): found prior state for backend");
1055 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1056 set_current_state (state);
1058 DEBUG_ECONTROL ("backend-changed(): no prior state for backend");
1061 DEBUG_ECONTROL (string_compose ("backend-changed(): _have_control=%1 ignore_changes=%2", _have_control, ignore_changes));
1064 if (!ignore_changes) {
1065 maybe_display_saved_state ();
1070 EngineControl::update_midi_options ()
1072 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1073 vector<string> midi_options = backend->enumerate_midi_options();
1075 if (midi_options.size() == 1) {
1076 /* only contains the "none" option */
1077 midi_option_combo.set_sensitive (false);
1079 if (_have_control) {
1080 set_popdown_strings (midi_option_combo, midi_options);
1081 midi_option_combo.set_active_text (midi_options.front());
1082 midi_option_combo.set_sensitive (true);
1084 midi_option_combo.set_sensitive (false);
1090 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1092 if (ARDOUR::Profile->get_mixbus()) {
1096 uint32_t cnt = (uint32_t) sb->get_value();
1098 sb->set_text (_("all available channels"));
1101 snprintf (buf, sizeof (buf), "%d", cnt);
1107 // @return true if there are drivers available
1109 EngineControl::set_driver_popdown_strings ()
1111 DEBUG_ECONTROL ("set_driver_popdown_strings");
1112 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1113 vector<string> drivers = backend->enumerate_drivers();
1115 if (drivers.empty ()) {
1116 // This is an error...?
1120 string current_driver = backend->driver_name ();
1122 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1124 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1127 current_driver = drivers.front ();
1130 set_popdown_strings (driver_combo, drivers);
1132 string_compose ("driver_combo.set_active_text: %1", current_driver));
1133 driver_combo.set_active_text (current_driver);
1138 EngineControl::get_default_device(const string& current_device_name,
1139 const vector<string>& available_devices)
1141 // If the current device is available, use it as default
1142 if (std::find (available_devices.begin (),
1143 available_devices.end (),
1144 current_device_name) != available_devices.end ()) {
1146 return current_device_name;
1149 using namespace ARDOUR;
1151 string default_device_name =
1152 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1154 vector<string>::const_iterator i;
1156 // If there is a "Default" device available, use it
1157 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1158 if (*i == default_device_name) {
1163 string none_device_name =
1164 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1166 // Use the first device that isn't "None"
1167 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1168 if (*i != none_device_name) {
1173 // Use "None" if there are no other available
1174 return available_devices.front();
1177 // @return true if there are devices available
1179 EngineControl::set_device_popdown_strings ()
1181 DEBUG_ECONTROL ("set_device_popdown_strings");
1182 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1183 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1185 /* NOTE: Ardour currently does not display the "available" field of the
1188 * Doing so would require a different GUI widget than the combo
1189 * box/popdown that we currently use, since it has no way to list
1190 * items that are not selectable. Something more like a popup menu,
1191 * which could have unselectable items, would be appropriate.
1194 vector<string> available_devices;
1196 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1197 available_devices.push_back (i->name);
1200 if (available_devices.empty ()) {
1204 set_popdown_strings (device_combo, available_devices);
1206 std::string default_device =
1207 get_default_device(backend->device_name(), available_devices);
1210 string_compose ("set device_combo active text: %1", default_device));
1212 device_combo.set_active_text(default_device);
1216 // @return true if there are input devices available
1218 EngineControl::set_input_device_popdown_strings ()
1220 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1221 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1222 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1224 vector<string> available_devices;
1226 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1227 available_devices.push_back (i->name);
1230 if (available_devices.empty()) {
1234 set_popdown_strings (input_device_combo, available_devices);
1236 std::string default_device =
1237 get_default_device(backend->input_device_name(), available_devices);
1240 string_compose ("set input_device_combo active text: %1", default_device));
1241 input_device_combo.set_active_text(default_device);
1245 // @return true if there are output devices available
1247 EngineControl::set_output_device_popdown_strings ()
1249 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1250 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1251 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1253 vector<string> available_devices;
1255 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1256 available_devices.push_back (i->name);
1259 if (available_devices.empty()) {
1263 set_popdown_strings (output_device_combo, available_devices);
1265 std::string default_device =
1266 get_default_device(backend->output_device_name(), available_devices);
1269 string_compose ("set output_device_combo active text: %1", default_device));
1270 output_device_combo.set_active_text(default_device);
1275 EngineControl::list_devices ()
1277 DEBUG_ECONTROL ("list_devices");
1278 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1281 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1283 bool devices_available = false;
1285 if (backend->use_separate_input_and_output_devices ()) {
1286 bool input_devices_available = set_input_device_popdown_strings ();
1287 bool output_devices_available = set_output_device_popdown_strings ();
1288 devices_available = input_devices_available || output_devices_available;
1290 devices_available = set_device_popdown_strings ();
1293 if (devices_available) {
1296 device_combo.clear();
1297 input_device_combo.clear();
1298 output_device_combo.clear();
1300 update_sensitivity ();
1304 EngineControl::driver_changed ()
1306 SignalBlocker blocker (*this, "driver_changed");
1307 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1310 backend->set_driver (driver_combo.get_active_text());
1313 // TODO load LRU device(s) for backend + driver combo
1315 if (!ignore_changes) {
1316 maybe_display_saved_state ();
1321 EngineControl::get_sample_rates_for_all_devices ()
1323 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1324 ARDOUR::AudioEngine::instance ()->current_backend ();
1325 vector<float> all_rates;
1327 if (backend->use_separate_input_and_output_devices ()) {
1328 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1330 all_rates = backend->available_sample_rates (get_device_name ());
1336 EngineControl::get_default_sample_rates ()
1338 vector<float> rates;
1339 rates.push_back (8000.0f);
1340 rates.push_back (16000.0f);
1341 rates.push_back (32000.0f);
1342 rates.push_back (44100.0f);
1343 rates.push_back (48000.0f);
1344 rates.push_back (88200.0f);
1345 rates.push_back (96000.0f);
1346 rates.push_back (192000.0f);
1347 rates.push_back (384000.0f);
1352 EngineControl::set_samplerate_popdown_strings ()
1354 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1355 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1360 if (_have_control) {
1361 sr = get_sample_rates_for_all_devices ();
1363 sr = get_default_sample_rates ();
1366 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1367 s.push_back (rate_as_string (*x));
1368 if (*x == _desired_sample_rate) {
1373 set_popdown_strings (sample_rate_combo, s);
1376 if (ARDOUR::AudioEngine::instance()->running()) {
1377 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1379 else if (desired.empty ()) {
1380 float new_active_sr = backend->default_sample_rate ();
1382 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1383 new_active_sr = sr.front ();
1386 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1388 sample_rate_combo.set_active_text (desired);
1392 update_sensitivity ();
1396 EngineControl::get_buffer_sizes_for_all_devices ()
1398 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1399 ARDOUR::AudioEngine::instance ()->current_backend ();
1400 vector<uint32_t> all_sizes;
1402 if (backend->use_separate_input_and_output_devices ()) {
1403 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1405 all_sizes = backend->available_buffer_sizes (get_device_name ());
1411 EngineControl::get_default_buffer_sizes ()
1413 vector<uint32_t> sizes;
1414 sizes.push_back (8);
1415 sizes.push_back (16);
1416 sizes.push_back (32);
1417 sizes.push_back (64);
1418 sizes.push_back (128);
1419 sizes.push_back (256);
1420 sizes.push_back (512);
1421 sizes.push_back (1024);
1422 sizes.push_back (2048);
1423 sizes.push_back (4096);
1424 sizes.push_back (8192);
1429 EngineControl::set_buffersize_popdown_strings ()
1431 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1432 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1433 vector<uint32_t> bs;
1436 if (_have_control) {
1437 bs = get_buffer_sizes_for_all_devices ();
1438 } else if (backend->can_change_buffer_size_when_running()) {
1439 bs = get_default_buffer_sizes ();
1442 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1443 s.push_back (bufsize_as_string (*x));
1446 uint32_t previous_size = 0;
1447 if (!buffer_size_combo.get_active_text().empty()) {
1448 previous_size = get_buffer_size ();
1451 set_popdown_strings (buffer_size_combo, s);
1455 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1456 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1459 buffer_size_combo.set_active_text(s.front());
1461 uint32_t period = backend->buffer_size();
1462 if (0 == period && backend->use_separate_input_and_output_devices()) {
1463 period = backend->default_buffer_size(get_input_device_name());
1465 if (0 == period && backend->use_separate_input_and_output_devices()) {
1466 period = backend->default_buffer_size(get_output_device_name());
1468 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1469 period = backend->default_buffer_size(get_device_name());
1472 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1474 show_buffer_duration ();
1476 update_sensitivity ();
1480 EngineControl::set_nperiods_popdown_strings ()
1482 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1483 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1484 vector<uint32_t> np;
1487 if (backend->can_set_period_size()) {
1488 np = backend->available_period_sizes (get_driver());
1491 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1492 s.push_back (to_string (*x));
1495 set_popdown_strings (nperiods_combo, s);
1498 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1501 update_sensitivity ();
1505 EngineControl::device_changed ()
1507 SignalBlocker blocker (*this, "device_changed");
1508 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1511 string device_name_in;
1512 string device_name_out; // only used if backend support separate I/O devices
1514 if (backend->use_separate_input_and_output_devices()) {
1515 device_name_in = get_input_device_name ();
1516 device_name_out = get_output_device_name ();
1518 device_name_in = get_device_name ();
1521 /* we set the backend-device to query various device related intormation.
1522 * This has the side effect that backend->device_name() will match
1523 * the device_name and 'change_device' will never be true.
1524 * so work around this by setting...
1526 if (backend->use_separate_input_and_output_devices()) {
1527 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1528 queue_device_changed = true;
1531 if (device_name_in != backend->device_name()) {
1532 queue_device_changed = true;
1536 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1537 if (backend->use_separate_input_and_output_devices()) {
1538 backend->set_input_device_name (device_name_in);
1539 backend->set_output_device_name (device_name_out);
1541 backend->set_device_name(device_name_in);
1545 /* don't allow programmatic change to combos to cause a
1546 recursive call to this method.
1548 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1550 set_samplerate_popdown_strings ();
1551 set_buffersize_popdown_strings ();
1552 set_nperiods_popdown_strings ();
1554 /* TODO set min + max channel counts here */
1556 manage_control_app_sensitivity ();
1559 /* pick up any saved state for this device */
1561 if (!ignore_changes) {
1562 maybe_display_saved_state ();
1567 EngineControl::input_device_changed ()
1569 DEBUG_ECONTROL ("input_device_changed");
1571 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1572 if (backend && backend->match_input_output_devices_or_none ()) {
1573 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1575 if (get_output_device_name () != dev_none
1576 && get_input_device_name () != dev_none
1577 && get_input_device_name () != get_output_device_name ()) {
1578 block_changed_signals ();
1579 if (contains_value (output_device_combo, get_input_device_name ())) {
1580 output_device_combo.set_active_text (get_input_device_name ());
1582 assert (contains_value (output_device_combo, dev_none));
1583 output_device_combo.set_active_text (dev_none);
1585 unblock_changed_signals ();
1592 EngineControl::output_device_changed ()
1594 DEBUG_ECONTROL ("output_device_changed");
1595 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1596 if (backend && backend->match_input_output_devices_or_none ()) {
1597 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1599 if (get_input_device_name () != dev_none
1600 && get_input_device_name () != dev_none
1601 && get_input_device_name () != get_output_device_name ()) {
1602 block_changed_signals ();
1603 if (contains_value (input_device_combo, get_output_device_name ())) {
1604 input_device_combo.set_active_text (get_output_device_name ());
1606 assert (contains_value (input_device_combo, dev_none));
1607 input_device_combo.set_active_text (dev_none);
1609 unblock_changed_signals ();
1616 EngineControl::bufsize_as_string (uint32_t sz)
1618 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1622 EngineControl::sample_rate_changed ()
1624 DEBUG_ECONTROL ("sample_rate_changed");
1625 /* reset the strings for buffer size to show the correct msec value
1626 (reflecting the new sample rate).
1629 show_buffer_duration ();
1634 EngineControl::buffer_size_changed ()
1636 DEBUG_ECONTROL ("buffer_size_changed");
1637 show_buffer_duration ();
1641 EngineControl::nperiods_changed ()
1643 DEBUG_ECONTROL ("nperiods_changed");
1644 show_buffer_duration ();
1648 EngineControl::show_buffer_duration ()
1650 DEBUG_ECONTROL ("show_buffer_duration");
1651 /* buffer sizes - convert from just samples to samples + msecs for
1652 * the displayed string
1655 string bs_text = buffer_size_combo.get_active_text ();
1656 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1657 uint32_t rate = get_rate();
1659 /* Except for ALSA and Dummy backends, we don't know the number of periods
1660 * per cycle and settings.
1662 * jack1 vs jack2 have different default latencies since jack2 start
1663 * in async-mode unless --sync is given which adds an extra cycle
1664 * of latency. The value is not known if jackd is started externally..
1666 * So just display the period size, that's also what
1667 * ARDOUR_UI::update_sample_rate() does for the status bar.
1668 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1669 * but still, that's the buffer period, not [round-trip] latency)
1672 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1673 buffer_size_duration_label.set_text (buf);
1677 EngineControl::midi_option_changed ()
1679 DEBUG_ECONTROL ("midi_option_changed");
1680 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1683 backend->set_midi_option (get_midi_option());
1685 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1687 //_midi_devices.clear(); // TODO merge with state-saved settings..
1688 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1689 std::vector<MidiDeviceSettings> new_devices;
1691 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1692 MidiDeviceSettings mds = find_midi_device (i->name);
1693 if (i->available && !mds) {
1694 uint32_t input_latency = 0;
1695 uint32_t output_latency = 0;
1696 if (_can_set_midi_latencies) {
1697 input_latency = backend->systemic_midi_input_latency (i->name);
1698 output_latency = backend->systemic_midi_output_latency (i->name);
1700 bool enabled = backend->midi_device_enabled (i->name);
1701 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1702 new_devices.push_back (ptr);
1703 } else if (i->available) {
1704 new_devices.push_back (mds);
1707 _midi_devices = new_devices;
1709 if (_midi_devices.empty()) {
1710 midi_devices_button.hide ();
1712 midi_devices_button.show ();
1717 EngineControl::parameter_changed ()
1721 EngineControl::State
1722 EngineControl::get_matching_state (const string& backend)
1724 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1725 if ((*i)->backend == backend) {
1732 EngineControl::State
1733 EngineControl::get_matching_state (
1734 const string& backend,
1735 const string& driver,
1736 const string& device)
1738 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1739 if ((*i)->backend == backend &&
1740 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1748 EngineControl::State
1749 EngineControl::get_matching_state (
1750 const string& backend,
1751 const string& driver,
1752 const string& input_device,
1753 const string& output_device)
1755 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1756 if ((*i)->backend == backend &&
1757 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1765 EngineControl::State
1766 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1768 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1771 if (backend->use_separate_input_and_output_devices ()) {
1772 return get_matching_state (backend_combo.get_active_text(),
1773 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1774 input_device_combo.get_active_text(),
1775 output_device_combo.get_active_text());
1777 return get_matching_state (backend_combo.get_active_text(),
1778 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1779 device_combo.get_active_text());
1783 return get_matching_state (backend_combo.get_active_text(),
1785 device_combo.get_active_text());
1788 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1789 const EngineControl::State& state2)
1791 if (state1->backend == state2->backend &&
1792 state1->driver == state2->driver &&
1793 state1->device == state2->device &&
1794 state1->input_device == state2->input_device &&
1795 state1->output_device == state2->output_device) {
1801 // sort active first, then most recently used to the beginning of the list
1803 EngineControl::state_sort_cmp (const State &a, const State &b) {
1807 else if (b->active) {
1811 return a->lru > b->lru;
1815 EngineControl::State
1816 EngineControl::save_state ()
1820 if (!_have_control) {
1821 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1823 state->lru = time (NULL) ;
1826 state.reset(new StateStruct);
1827 state->backend = get_backend ();
1829 state.reset(new StateStruct);
1830 store_state (state);
1833 for (StateList::iterator i = states.begin(); i != states.end();) {
1834 if (equivalent_states (*i, state)) {
1835 i = states.erase(i);
1841 states.push_back (state);
1843 states.sort (state_sort_cmp);
1849 EngineControl::store_state (State state)
1851 state->backend = get_backend ();
1852 state->driver = get_driver ();
1853 state->device = get_device_name ();
1854 state->input_device = get_input_device_name ();
1855 state->output_device = get_output_device_name ();
1856 state->sample_rate = get_rate ();
1857 state->buffer_size = get_buffer_size ();
1858 state->n_periods = get_nperiods ();
1859 state->input_latency = get_input_latency ();
1860 state->output_latency = get_output_latency ();
1861 state->input_channels = get_input_channels ();
1862 state->output_channels = get_output_channels ();
1863 state->midi_option = get_midi_option ();
1864 state->midi_devices = _midi_devices;
1865 state->use_buffered_io = get_use_buffered_io ();
1866 state->lru = time (NULL) ;
1870 EngineControl::maybe_display_saved_state ()
1872 if (!_have_control) {
1876 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1879 DEBUG_ECONTROL ("Restoring saved state");
1880 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1882 if (!_desired_sample_rate) {
1883 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1885 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1887 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1888 /* call this explicitly because we're ignoring changes to
1889 the controls at this point.
1891 show_buffer_duration ();
1892 input_latency.set_value (state->input_latency);
1893 output_latency.set_value (state->output_latency);
1895 use_buffered_io_button.set_active (state->use_buffered_io);
1897 if (!state->midi_option.empty()) {
1898 midi_option_combo.set_active_text (state->midi_option);
1899 _midi_devices = state->midi_devices;
1902 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1907 EngineControl::get_state ()
1911 XMLNode* root = new XMLNode ("AudioMIDISetup");
1914 if (!states.empty()) {
1915 XMLNode* state_nodes = new XMLNode ("EngineStates");
1917 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1919 XMLNode* node = new XMLNode ("State");
1921 node->set_property ("backend", (*i)->backend);
1922 node->set_property ("driver", (*i)->driver);
1923 node->set_property ("device", (*i)->device);
1924 node->set_property ("input-device", (*i)->input_device);
1925 node->set_property ("output-device", (*i)->output_device);
1926 node->set_property ("sample-rate", (*i)->sample_rate);
1927 node->set_property ("buffer-size", (*i)->buffer_size);
1928 node->set_property ("n-periods", (*i)->n_periods);
1929 node->set_property ("input-latency", (*i)->input_latency);
1930 node->set_property ("output-latency", (*i)->output_latency);
1931 node->set_property ("input-channels", (*i)->input_channels);
1932 node->set_property ("output-channels", (*i)->output_channels);
1933 node->set_property ("active", (*i)->active);
1934 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1935 node->set_property ("midi-option", (*i)->midi_option);
1936 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1937 node->set_property ("lru", lru_val );
1939 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1940 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1941 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1942 midi_device_stuff->set_property (X_("name"), (*p)->name);
1943 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1944 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1945 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1946 midi_devices->add_child_nocopy (*midi_device_stuff);
1948 node->add_child_nocopy (*midi_devices);
1950 state_nodes->add_child_nocopy (*node);
1953 root->add_child_nocopy (*state_nodes);
1960 EngineControl::set_default_state ()
1962 vector<string> backend_names;
1963 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1965 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1966 backend_names.push_back ((*b)->name);
1968 backend_combo.set_active_text (backend_names.front());
1970 // We could set default backends per platform etc here
1976 EngineControl::set_state (const XMLNode& root)
1978 XMLNodeList clist, cclist;
1979 XMLNodeConstIterator citer, cciter;
1980 XMLNode const * child;
1981 XMLNode const * grandchild;
1983 if (root.name() != "AudioMIDISetup") {
1987 clist = root.children();
1991 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1995 if (child->name() != "EngineStates") {
1999 cclist = child->children();
2001 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2002 State state (new StateStruct);
2004 grandchild = *cciter;
2006 if (grandchild->name() != "State") {
2010 if (!grandchild->get_property ("backend", state->backend)) {
2014 // If any of the required properties are not found in the state node
2015 // then continue/skip to the next engine state
2016 if (!grandchild->get_property ("driver", state->driver) ||
2017 !grandchild->get_property ("device", state->device) ||
2018 !grandchild->get_property ("input-device", state->input_device) ||
2019 !grandchild->get_property ("output-device", state->output_device) ||
2020 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2021 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2022 !grandchild->get_property ("input-latency", state->input_latency) ||
2023 !grandchild->get_property ("output-latency", state->output_latency) ||
2024 !grandchild->get_property ("input-channels", state->input_channels) ||
2025 !grandchild->get_property ("output-channels", state->output_channels) ||
2026 !grandchild->get_property ("active", state->active) ||
2027 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2028 !grandchild->get_property ("midi-option", state->midi_option)) {
2032 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2033 // optional (new value in 4.5)
2034 state->n_periods = 0;
2037 state->midi_devices.clear();
2039 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2040 const XMLNodeList mnc = midinode->children();
2041 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2044 uint32_t input_latency;
2045 uint32_t output_latency;
2047 if (!(*n)->get_property (X_("name"), name) ||
2048 !(*n)->get_property (X_("enabled"), enabled) ||
2049 !(*n)->get_property (X_("input-latency"), input_latency) ||
2050 !(*n)->get_property (X_("output-latency"), output_latency)) {
2054 MidiDeviceSettings ptr (
2055 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2056 state->midi_devices.push_back (ptr);
2061 if (grandchild->get_property ("lru", lru_val)) {
2062 state->lru = lru_val;
2065 states.push_back (state);
2069 /* now see if there was an active state and switch the setup to it */
2071 /* purge states of backend that are not available in this built */
2072 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2073 vector<std::string> backend_names;
2075 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2076 backend_names.push_back((*i)->name);
2078 for (StateList::iterator i = states.begin(); i != states.end();) {
2079 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2080 i = states.erase(i);
2086 states.sort (state_sort_cmp);
2088 /* purge old states referring to the same backend */
2089 const time_t now = time (NULL);
2090 for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2092 for (StateList::iterator i = states.begin(); i != states.end();) {
2093 if ((*i)->backend != *bi) {
2096 // keep at latest one for every audio-system
2101 // also keep states used in the last 90 days.
2102 if ((now - (*i)->lru) < 86400 * 90) {
2105 assert (!(*i)->active);
2106 i = states.erase(i);
2110 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2113 return set_current_state (*i);
2120 EngineControl::set_current_state (const State& state)
2122 DEBUG_ECONTROL ("set_current_state");
2124 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2126 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2127 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2128 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2129 // this shouldn't happen as the invalid backend names should have been
2130 // removed from the list of states.
2134 // now reflect the change in the backend in the GUI so backend_changed will
2135 // do the right thing
2136 backend_combo.set_active_text (state->backend);
2138 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2140 // we don't have control don't restore state
2145 if (!state->driver.empty ()) {
2146 if (!backend->requires_driver_selection ()) {
2147 DEBUG_ECONTROL ("Backend should require driver selection");
2148 // A backend has changed from having driver selection to not having
2149 // it or someone has been manually editing a config file and messed
2154 if (backend->set_driver (state->driver) != 0) {
2155 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2156 // Driver names for a backend have changed and the name in the
2157 // config file is now invalid or support for driver is no longer
2158 // included in the backend
2161 // no need to set the driver_combo as backend_changed will use
2162 // backend->driver_name to set the active driver
2165 if (!state->device.empty ()) {
2166 if (backend->set_device_name (state->device) != 0) {
2168 string_compose ("Unable to set device name %1", state->device));
2169 // device is no longer available on the system
2172 // no need to set active device as it will be picked up in
2173 // via backend_changed ()/set_device_popdown_strings
2176 // backend supports separate input/output devices
2177 if (backend->set_input_device_name (state->input_device) != 0) {
2178 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2179 state->input_device));
2180 // input device is no longer available on the system
2184 if (backend->set_output_device_name (state->output_device) != 0) {
2185 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2186 state->input_device));
2187 // output device is no longer available on the system
2190 // no need to set active devices as it will be picked up in via
2191 // backend_changed ()/set_*_device_popdown_strings
2196 // Now restore the state of the rest of the controls
2198 // We don't use a SignalBlocker as set_current_state is currently only
2199 // called from set_state before any signals are connected. If at some point
2200 // a more general named state mechanism is implemented and
2201 // set_current_state is called while signals are connected then a
2202 // SignalBlocker will need to be instantiated before setting these.
2204 device_combo.set_active_text (state->device);
2205 input_device_combo.set_active_text (state->input_device);
2206 output_device_combo.set_active_text (state->output_device);
2207 if (!_desired_sample_rate) {
2208 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2210 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2211 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2212 input_latency.set_value (state->input_latency);
2213 output_latency.set_value (state->output_latency);
2214 midi_option_combo.set_active_text (state->midi_option);
2215 use_buffered_io_button.set_active (state->use_buffered_io);
2220 EngineControl::push_state_to_backend (bool start)
2222 DEBUG_ECONTROL ("push_state_to_backend");
2223 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2224 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2230 /* figure out what is going to change */
2232 bool restart_required = false;
2233 bool was_running = ARDOUR::AudioEngine::instance()->running();
2234 bool change_driver = false;
2235 bool change_device = false;
2236 bool change_rate = false;
2237 bool change_bufsize = false;
2238 bool change_nperiods = false;
2239 bool change_latency = false;
2240 bool change_channels = false;
2241 bool change_midi = false;
2242 bool change_buffered_io = false;
2244 uint32_t ochan = get_output_channels ();
2245 uint32_t ichan = get_input_channels ();
2247 if (_have_control) {
2249 if (started_at_least_once) {
2251 /* we can control the backend */
2253 if (backend->requires_driver_selection()) {
2254 if (get_driver() != backend->driver_name()) {
2255 change_driver = true;
2259 if (backend->use_separate_input_and_output_devices()) {
2260 if (get_input_device_name() != backend->input_device_name()) {
2261 change_device = true;
2263 if (get_output_device_name() != backend->output_device_name()) {
2264 change_device = true;
2267 if (get_device_name() != backend->device_name()) {
2268 change_device = true;
2272 if (queue_device_changed) {
2273 change_device = true;
2276 if (get_rate() != backend->sample_rate()) {
2280 if (get_buffer_size() != backend->buffer_size()) {
2281 change_bufsize = true;
2284 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2285 && get_nperiods() != backend->period_size()) {
2286 change_nperiods = true;
2289 if (get_midi_option() != backend->midi_option()) {
2293 if (backend->can_use_buffered_io()) {
2294 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2295 change_buffered_io = true;
2299 /* zero-requested channels means "all available" */
2302 ichan = backend->input_channels();
2306 ochan = backend->output_channels();
2309 if (ichan != backend->input_channels()) {
2310 change_channels = true;
2313 if (ochan != backend->output_channels()) {
2314 change_channels = true;
2317 if (get_input_latency() != backend->systemic_input_latency() ||
2318 get_output_latency() != backend->systemic_output_latency()) {
2319 change_latency = true;
2322 /* backend never started, so we have to force a group
2325 change_device = true;
2326 if (backend->requires_driver_selection()) {
2327 change_driver = true;
2330 change_bufsize = true;
2331 change_channels = true;
2332 change_latency = true;
2334 change_buffered_io = backend->can_use_buffered_io();
2335 change_channels = true;
2336 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2341 /* we have no control over the backend, meaning that we can
2342 * only possibly change sample rate and buffer size.
2346 if (get_rate() != backend->sample_rate()) {
2347 change_bufsize = true;
2350 if (get_buffer_size() != backend->buffer_size()) {
2351 change_bufsize = true;
2355 queue_device_changed = false;
2357 if (!_have_control) {
2359 /* We do not have control over the backend, so the best we can
2360 * do is try to change the sample rate and/or bufsize and get
2364 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2368 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2373 backend->set_sample_rate (get_rate());
2376 if (change_bufsize) {
2377 backend->set_buffer_size (get_buffer_size());
2381 if (ARDOUR::AudioEngine::instance()->start ()) {
2382 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2392 /* determine if we need to stop the backend before changing parameters */
2394 if (change_driver || change_device || change_channels || change_nperiods ||
2395 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2396 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2397 change_midi || change_buffered_io ||
2398 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2399 restart_required = true;
2401 restart_required = false;
2406 if (restart_required) {
2407 if (ARDOUR::AudioEngine::instance()->stop()) {
2413 if (change_driver && backend->set_driver (get_driver())) {
2414 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2417 if (backend->use_separate_input_and_output_devices()) {
2418 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2419 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2422 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2423 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2427 if (change_device && backend->set_device_name (get_device_name())) {
2428 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2432 if (change_rate && backend->set_sample_rate (get_rate())) {
2433 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2436 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2437 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2440 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2441 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2445 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2446 if (backend->set_input_channels (get_input_channels())) {
2447 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2450 if (backend->set_output_channels (get_output_channels())) {
2451 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2455 if (change_latency) {
2456 if (backend->set_systemic_input_latency (get_input_latency())) {
2457 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2460 if (backend->set_systemic_output_latency (get_output_latency())) {
2461 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2467 backend->set_midi_option (get_midi_option());
2470 if (change_buffered_io) {
2471 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2475 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2476 if (_measure_midi) {
2477 if (*p == _measure_midi) {
2478 backend->set_midi_device_enabled ((*p)->name, true);
2480 backend->set_midi_device_enabled ((*p)->name, false);
2482 if (backend->can_change_systemic_latency_when_running ()) {
2483 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2484 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2488 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2489 if (backend->can_set_systemic_midi_latencies()) {
2490 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2491 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2496 if (start || (was_running && restart_required)) {
2497 if (ARDOUR::AudioEngine::instance()->start()) {
2508 EngineControl::post_push ()
2510 /* get a pointer to the current state object, creating one if
2514 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2517 state = save_state ();
2523 states.sort (state_sort_cmp);
2527 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2528 (*i)->active = false;
2531 /* mark this one active (to be used next time the dialog is
2535 state->active = true;
2537 if (_have_control) { // XXX
2538 manage_control_app_sensitivity ();
2541 /* schedule a redisplay of MIDI ports */
2542 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2547 EngineControl::get_rate () const
2549 float r = atof (sample_rate_combo.get_active_text ());
2550 /* the string may have been translated with an abbreviation for
2551 * thousands, so use a crude heuristic to fix this.
2561 EngineControl::get_buffer_size () const
2563 string txt = buffer_size_combo.get_active_text ();
2566 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2567 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2568 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2576 EngineControl::get_nperiods () const
2578 string txt = nperiods_combo.get_active_text ();
2579 return atoi (txt.c_str());
2583 EngineControl::get_midi_option () const
2585 return midi_option_combo.get_active_text();
2589 EngineControl::get_use_buffered_io () const
2591 return use_buffered_io_button.get_active();
2595 EngineControl::get_input_channels() const
2597 if (ARDOUR::Profile->get_mixbus()) {
2598 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2599 if (!backend) return 0;
2600 return backend->input_channels();
2602 return (uint32_t) input_channels_adjustment.get_value();
2606 EngineControl::get_output_channels() const
2608 if (ARDOUR::Profile->get_mixbus()) {
2609 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2610 if (!backend) return 0;
2611 return backend->input_channels();
2613 return (uint32_t) output_channels_adjustment.get_value();
2617 EngineControl::get_input_latency() const
2619 return (uint32_t) input_latency_adjustment.get_value();
2623 EngineControl::get_output_latency() const
2625 return (uint32_t) output_latency_adjustment.get_value();
2629 EngineControl::get_backend () const
2631 return backend_combo.get_active_text ();
2635 EngineControl::get_driver () const
2637 if (driver_combo.get_parent()) {
2638 return driver_combo.get_active_text ();
2645 EngineControl::get_device_name () const
2647 return device_combo.get_active_text ();
2651 EngineControl::get_input_device_name () const
2653 return input_device_combo.get_active_text ();
2657 EngineControl::get_output_device_name () const
2659 return output_device_combo.get_active_text ();
2663 EngineControl::control_app_button_clicked ()
2665 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2671 backend->launch_control_app ();
2675 EngineControl::start_stop_button_clicked ()
2677 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2683 if (ARDOUR::AudioEngine::instance()->running()) {
2684 ARDOUR::AudioEngine::instance()->stop ();
2686 if (!ARDOUR_UI::instance()->session_loaded) {
2692 if (!ARDOUR_UI::instance()->session_loaded) {
2693 ArdourDialog::on_response (RESPONSE_OK);
2699 EngineControl::update_devices_button_clicked ()
2701 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2707 if (backend->update_devices()) {
2708 device_list_changed ();
2713 EngineControl::use_buffered_io_button_clicked ()
2715 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2721 bool set_buffered_io = !use_buffered_io_button.get_active();
2722 use_buffered_io_button.set_active (set_buffered_io);
2723 backend->set_use_buffered_io (set_buffered_io);
2727 EngineControl::manage_control_app_sensitivity ()
2729 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2735 string appname = backend->control_app_name();
2737 if (appname.empty()) {
2738 control_app_button.set_sensitive (false);
2740 control_app_button.set_sensitive (true);
2745 EngineControl::set_desired_sample_rate (uint32_t sr)
2747 _desired_sample_rate = sr;
2748 if (ARDOUR::AudioEngine::instance ()->running ()
2749 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2756 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2758 if (page_num == 0) {
2759 _measure_midi.reset();
2760 update_sensitivity ();
2763 if (page_num == midi_tab) {
2765 refresh_midi_display ();
2768 if (page_num == latency_tab) {
2771 if (ARDOUR::AudioEngine::instance()->running()) {
2776 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2778 /* save any existing latency values */
2780 uint32_t il = (uint32_t) input_latency.get_value ();
2781 uint32_t ol = (uint32_t) input_latency.get_value ();
2783 /* reset to zero so that our new test instance
2784 will be clean of any existing latency measures.
2786 NB. this should really be done by the backend
2787 when stated for latency measurement.
2790 input_latency.set_value (0);
2791 output_latency.set_value (0);
2793 push_state_to_backend (false);
2797 input_latency.set_value (il);
2798 output_latency.set_value (ol);
2801 // This should be done in push_state_to_backend()
2802 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2803 disable_latency_tab ();
2806 enable_latency_tab ();
2810 end_latency_detection ();
2811 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2816 /* latency measurement */
2819 EngineControl::check_audio_latency_measurement ()
2821 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2823 if (mtdm->resolve () < 0) {
2824 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2828 if (mtdm->get_peak () > 0.707f) {
2829 // get_peak() resets the peak-hold in the detector.
2830 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2831 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2835 if (mtdm->err () > 0.3) {
2841 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2843 if (sample_rate == 0) {
2844 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2845 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2849 int frames_total = mtdm->del();
2850 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2852 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2853 _("Detected roundtrip latency: "),
2854 frames_total, frames_total * 1000.0f/sample_rate,
2855 _("Systemic latency: "),
2856 extra, extra * 1000.0f/sample_rate);
2860 if (mtdm->err () > 0.2) {
2862 strcat (buf, _("(signal detection error)"));
2868 strcat (buf, _("(inverted - bad wiring)"));
2872 lm_results.set_markup (string_compose (results_markup, buf));
2875 have_lm_results = true;
2876 end_latency_detection ();
2877 lm_use_button.set_sensitive (true);
2885 EngineControl::check_midi_latency_measurement ()
2887 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2889 if (!mididm->have_signal () || mididm->latency () == 0) {
2890 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2895 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2897 if (sample_rate == 0) {
2898 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2899 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2903 ARDOUR::framecnt_t frames_total = mididm->latency();
2904 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2905 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2906 _("Detected roundtrip latency: "),
2907 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2908 _("Systemic latency: "),
2909 extra, extra * 1000.0f / sample_rate);
2913 if (!mididm->ok ()) {
2915 strcat (buf, _("(averaging)"));
2919 if (mididm->deviation () > 50.0) {
2921 strcat (buf, _("(too large jitter)"));
2923 } else if (mididm->deviation () > 10.0) {
2925 strcat (buf, _("(large jitter)"));
2929 have_lm_results = true;
2930 end_latency_detection ();
2931 lm_use_button.set_sensitive (true);
2932 lm_results.set_markup (string_compose (results_markup, buf));
2934 } else if (mididm->processed () > 400) {
2935 have_lm_results = false;
2936 end_latency_detection ();
2937 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2941 lm_results.set_markup (string_compose (results_markup, buf));
2947 EngineControl::start_latency_detection ()
2949 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2950 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2952 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2953 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2954 if (_measure_midi) {
2955 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2957 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2959 lm_measure_label.set_text (_("Cancel"));
2960 have_lm_results = false;
2961 lm_use_button.set_sensitive (false);
2962 lm_input_channel_combo.set_sensitive (false);
2963 lm_output_channel_combo.set_sensitive (false);
2969 EngineControl::end_latency_detection ()
2971 latency_timeout.disconnect ();
2972 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2973 lm_measure_label.set_text (_("Measure"));
2974 if (!have_lm_results) {
2975 lm_use_button.set_sensitive (false);
2977 lm_input_channel_combo.set_sensitive (true);
2978 lm_output_channel_combo.set_sensitive (true);
2983 EngineControl::latency_button_clicked ()
2986 start_latency_detection ();
2988 end_latency_detection ();
2993 EngineControl::latency_back_button_clicked ()
2995 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2996 notebook.set_current_page(0);
3000 EngineControl::use_latency_button_clicked ()
3002 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3003 if (_measure_midi) {
3004 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3008 ARDOUR::framecnt_t frames_total = mididm->latency();
3009 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3010 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3011 _measure_midi->input_latency = one_way;
3012 _measure_midi->output_latency = one_way;
3013 if (backend->can_change_systemic_latency_when_running ()) {
3014 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3015 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3017 notebook.set_current_page (midi_tab);
3019 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3025 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3026 one_way = std::max (0., one_way);
3028 input_latency_adjustment.set_value (one_way);
3029 output_latency_adjustment.set_value (one_way);
3030 if (backend->can_change_systemic_latency_when_running ()) {
3031 backend->set_systemic_input_latency (one_way);
3032 backend->set_systemic_output_latency (one_way);
3035 /* back to settings page */
3036 notebook.set_current_page (0);
3041 EngineControl::on_delete_event (GdkEventAny* ev)
3043 if (notebook.get_current_page() == 2) {
3044 /* currently on latency tab - be sure to clean up */
3045 end_latency_detection ();
3047 return ArdourDialog::on_delete_event (ev);
3051 EngineControl::engine_running ()
3053 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3056 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3057 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3059 if (backend->can_set_period_size ()) {
3060 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3063 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3064 connect_disconnect_button.show();
3066 started_at_least_once = true;
3067 if (_have_control) {
3068 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3070 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3072 update_sensitivity();
3076 EngineControl::engine_stopped ()
3078 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3081 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3082 connect_disconnect_button.show();
3084 if (_have_control) {
3085 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3087 engine_status.set_markup(X_(""));
3090 update_sensitivity();
3094 EngineControl::device_list_changed ()
3096 if (ignore_device_changes) {
3099 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3101 midi_option_changed();
3105 EngineControl::connect_disconnect_click()
3107 if (ARDOUR::AudioEngine::instance()->running()) {
3110 if (!ARDOUR_UI::instance()->session_loaded) {
3116 if (!ARDOUR_UI::instance()->session_loaded) {
3117 ArdourDialog::on_response (RESPONSE_OK);
3123 EngineControl::calibrate_audio_latency ()
3125 _measure_midi.reset ();
3126 have_lm_results = false;
3127 lm_use_button.set_sensitive (false);
3128 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3129 notebook.set_current_page (latency_tab);
3133 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3136 have_lm_results = false;
3137 lm_use_button.set_sensitive (false);
3138 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3139 notebook.set_current_page (latency_tab);
3143 EngineControl::configure_midi_devices ()
3145 notebook.set_current_page (midi_tab);