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_buffer_size_when_running ()) {
807 buffer_size_combo.set_sensitive (valid || !_have_control);
809 buffer_size_combo.set_sensitive (false);
812 buffer_size_combo.set_sensitive (false);
816 if (get_popdown_string_count (sample_rate_combo) > 0) {
817 bool allow_to_set_rate = false;
818 if (!engine_running) {
819 if (!ARDOUR_UI::instance()->session_loaded) {
820 // engine is not running, no session loaded -> anything goes.
821 allow_to_set_rate = true;
822 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
823 // only allow to change if the current setting is not the native session rate.
824 allow_to_set_rate = true;
827 sample_rate_combo.set_sensitive (allow_to_set_rate);
829 sample_rate_combo.set_sensitive (false);
833 if (get_popdown_string_count (nperiods_combo) > 0) {
834 if (!engine_running) {
835 nperiods_combo.set_sensitive (true);
837 nperiods_combo.set_sensitive (false);
840 nperiods_combo.set_sensitive (false);
844 start_stop_button.set_sensitive(true);
845 start_stop_button.show();
846 if (engine_running) {
847 start_stop_button.set_text("Stop");
848 update_devices_button.set_sensitive(false);
849 use_buffered_io_button.set_sensitive(false);
851 if (backend->can_request_update_devices()) {
852 update_devices_button.show();
854 update_devices_button.hide();
856 if (backend->can_use_buffered_io()) {
857 use_buffered_io_button.show();
859 use_buffered_io_button.hide();
861 start_stop_button.set_text("Start");
862 update_devices_button.set_sensitive(true);
863 use_buffered_io_button.set_sensitive(true);
866 update_devices_button.set_sensitive(false);
867 update_devices_button.hide();
868 use_buffered_io_button.set_sensitive(false);
869 use_buffered_io_button.hide();
870 start_stop_button.set_sensitive(false);
871 start_stop_button.hide();
874 if (engine_running && _have_control) {
875 input_device_combo.set_sensitive (false);
876 output_device_combo.set_sensitive (false);
877 device_combo.set_sensitive (false);
878 driver_combo.set_sensitive (false);
880 input_device_combo.set_sensitive (true);
881 output_device_combo.set_sensitive (true);
882 device_combo.set_sensitive (true);
883 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
884 driver_combo.set_sensitive (true);
886 driver_combo.set_sensitive (false);
890 midi_option_combo.set_sensitive (!engine_running);
894 EngineControl::setup_midi_tab_for_jack ()
899 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
901 device->input_latency = a->get_value();
903 device->output_latency = a->get_value();
908 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
909 b->set_active (!b->get_active());
910 device->enabled = b->get_active();
911 refresh_midi_display(device->name);
915 EngineControl::refresh_midi_display (std::string focus)
917 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
921 AttachOptions xopt = AttachOptions (FILL|EXPAND);
924 Gtkmm2ext::container_clear (midi_device_table);
926 midi_device_table.set_spacings (6);
928 l = manage (new Label);
929 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
930 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
931 l->set_alignment (0.5, 0.5);
935 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
936 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
937 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
938 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
940 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
941 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
942 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
943 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
946 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
951 bool enabled = (*p)->enabled;
953 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
954 m->set_name ("midi device");
955 m->set_can_focus (Gtk::CAN_FOCUS);
956 m->add_events (Gdk::BUTTON_RELEASE_MASK);
957 m->set_active (enabled);
958 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
959 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
960 if ((*p)->name == focus) {
964 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
965 s = manage (new Gtk::SpinButton (*a));
966 a->set_value ((*p)->input_latency);
967 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
968 s->set_sensitive (_can_set_midi_latencies && enabled);
969 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
971 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
972 s = manage (new Gtk::SpinButton (*a));
973 a->set_value ((*p)->output_latency);
974 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
975 s->set_sensitive (_can_set_midi_latencies && enabled);
976 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
978 b = manage (new Button (_("Calibrate")));
979 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
980 b->set_sensitive (_can_set_midi_latencies && enabled);
981 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
988 EngineControl::backend_changed ()
990 SignalBlocker blocker (*this, "backend_changed");
991 string backend_name = backend_combo.get_active_text();
992 boost::shared_ptr<ARDOUR::AudioBackend> backend;
994 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
995 /* eh? setting the backend failed... how ? */
996 /* A: stale config contains a backend that does not exist in current build */
1000 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1002 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1005 setup_midi_tab_for_backend ();
1006 _midi_devices.clear();
1008 if (backend->requires_driver_selection()) {
1009 if (set_driver_popdown_strings ()) {
1013 /* this will change the device text which will cause a call to
1014 * device changed which will set up parameters
1019 update_midi_options ();
1021 connect_disconnect_button.hide();
1023 midi_option_changed();
1025 started_at_least_once = false;
1027 /* changing the backend implies stopping the engine
1028 * ARDOUR::AudioEngine() may or may not emit this signal
1029 * depending on previous engine state
1031 engine_stopped (); // set "active/inactive"
1033 if (!_have_control) {
1034 // set settings from backend that we do have control over
1035 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1038 if (_have_control && !ignore_changes) {
1039 // set driver & devices
1040 State state = get_matching_state (backend_combo.get_active_text());
1042 DEBUG_ECONTROL ("backend-changed(): found prior state for backend");
1043 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1044 set_current_state (state);
1046 DEBUG_ECONTROL ("backend-changed(): no prior state for backend");
1049 DEBUG_ECONTROL (string_compose ("backend-changed(): _have_control=%1 ignore_changes=%2", _have_control, ignore_changes));
1052 if (!ignore_changes) {
1053 maybe_display_saved_state ();
1058 EngineControl::update_midi_options ()
1060 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1061 vector<string> midi_options = backend->enumerate_midi_options();
1063 if (midi_options.size() == 1) {
1064 /* only contains the "none" option */
1065 midi_option_combo.set_sensitive (false);
1067 if (_have_control) {
1068 set_popdown_strings (midi_option_combo, midi_options);
1069 midi_option_combo.set_active_text (midi_options.front());
1070 midi_option_combo.set_sensitive (true);
1072 midi_option_combo.set_sensitive (false);
1078 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1080 if (ARDOUR::Profile->get_mixbus()) {
1084 uint32_t cnt = (uint32_t) sb->get_value();
1086 sb->set_text (_("all available channels"));
1089 snprintf (buf, sizeof (buf), "%d", cnt);
1095 // @return true if there are drivers available
1097 EngineControl::set_driver_popdown_strings ()
1099 DEBUG_ECONTROL ("set_driver_popdown_strings");
1100 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1101 vector<string> drivers = backend->enumerate_drivers();
1103 if (drivers.empty ()) {
1104 // This is an error...?
1108 string current_driver = backend->driver_name ();
1110 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1112 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1115 current_driver = drivers.front ();
1118 set_popdown_strings (driver_combo, drivers);
1120 string_compose ("driver_combo.set_active_text: %1", current_driver));
1121 driver_combo.set_active_text (current_driver);
1126 EngineControl::get_default_device(const string& current_device_name,
1127 const vector<string>& available_devices)
1129 // If the current device is available, use it as default
1130 if (std::find (available_devices.begin (),
1131 available_devices.end (),
1132 current_device_name) != available_devices.end ()) {
1134 return current_device_name;
1137 using namespace ARDOUR;
1139 string default_device_name =
1140 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1142 vector<string>::const_iterator i;
1144 // If there is a "Default" device available, use it
1145 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1146 if (*i == default_device_name) {
1151 string none_device_name =
1152 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1154 // Use the first device that isn't "None"
1155 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1156 if (*i != none_device_name) {
1161 // Use "None" if there are no other available
1162 return available_devices.front();
1165 // @return true if there are devices available
1167 EngineControl::set_device_popdown_strings ()
1169 DEBUG_ECONTROL ("set_device_popdown_strings");
1170 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1171 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1173 /* NOTE: Ardour currently does not display the "available" field of the
1176 * Doing so would require a different GUI widget than the combo
1177 * box/popdown that we currently use, since it has no way to list
1178 * items that are not selectable. Something more like a popup menu,
1179 * which could have unselectable items, would be appropriate.
1182 vector<string> available_devices;
1184 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1185 available_devices.push_back (i->name);
1188 if (available_devices.empty ()) {
1192 set_popdown_strings (device_combo, available_devices);
1194 std::string default_device =
1195 get_default_device(backend->device_name(), available_devices);
1198 string_compose ("set device_combo active text: %1", default_device));
1200 device_combo.set_active_text(default_device);
1204 // @return true if there are input devices available
1206 EngineControl::set_input_device_popdown_strings ()
1208 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1209 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1210 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1212 vector<string> available_devices;
1214 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1215 available_devices.push_back (i->name);
1218 if (available_devices.empty()) {
1222 set_popdown_strings (input_device_combo, available_devices);
1224 std::string default_device =
1225 get_default_device(backend->input_device_name(), available_devices);
1228 string_compose ("set input_device_combo active text: %1", default_device));
1229 input_device_combo.set_active_text(default_device);
1233 // @return true if there are output devices available
1235 EngineControl::set_output_device_popdown_strings ()
1237 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1238 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1239 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1241 vector<string> available_devices;
1243 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1244 available_devices.push_back (i->name);
1247 if (available_devices.empty()) {
1251 set_popdown_strings (output_device_combo, available_devices);
1253 std::string default_device =
1254 get_default_device(backend->output_device_name(), available_devices);
1257 string_compose ("set output_device_combo active text: %1", default_device));
1258 output_device_combo.set_active_text(default_device);
1263 EngineControl::list_devices ()
1265 DEBUG_ECONTROL ("list_devices");
1266 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1269 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1271 bool devices_available = false;
1273 if (backend->use_separate_input_and_output_devices ()) {
1274 bool input_devices_available = set_input_device_popdown_strings ();
1275 bool output_devices_available = set_output_device_popdown_strings ();
1276 devices_available = input_devices_available || output_devices_available;
1278 devices_available = set_device_popdown_strings ();
1281 if (devices_available) {
1284 device_combo.clear();
1285 input_device_combo.clear();
1286 output_device_combo.clear();
1288 update_sensitivity ();
1292 EngineControl::driver_changed ()
1294 SignalBlocker blocker (*this, "driver_changed");
1295 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1298 backend->set_driver (driver_combo.get_active_text());
1301 // TODO load LRU device(s) for backend + driver combo
1303 if (!ignore_changes) {
1304 maybe_display_saved_state ();
1309 EngineControl::get_sample_rates_for_all_devices ()
1311 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1312 ARDOUR::AudioEngine::instance ()->current_backend ();
1313 vector<float> all_rates;
1315 if (backend->use_separate_input_and_output_devices ()) {
1316 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1318 all_rates = backend->available_sample_rates (get_device_name ());
1324 EngineControl::get_default_sample_rates ()
1326 vector<float> rates;
1327 rates.push_back (8000.0f);
1328 rates.push_back (16000.0f);
1329 rates.push_back (32000.0f);
1330 rates.push_back (44100.0f);
1331 rates.push_back (48000.0f);
1332 rates.push_back (88200.0f);
1333 rates.push_back (96000.0f);
1334 rates.push_back (192000.0f);
1335 rates.push_back (384000.0f);
1340 EngineControl::set_samplerate_popdown_strings ()
1342 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1343 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1348 if (_have_control) {
1349 sr = get_sample_rates_for_all_devices ();
1351 sr = get_default_sample_rates ();
1354 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1355 s.push_back (rate_as_string (*x));
1356 if (*x == _desired_sample_rate) {
1361 set_popdown_strings (sample_rate_combo, s);
1364 if (ARDOUR::AudioEngine::instance()->running()) {
1365 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1367 else if (desired.empty ()) {
1368 float new_active_sr = backend->default_sample_rate ();
1370 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1371 new_active_sr = sr.front ();
1374 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1376 sample_rate_combo.set_active_text (desired);
1380 update_sensitivity ();
1384 EngineControl::get_buffer_sizes_for_all_devices ()
1386 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1387 ARDOUR::AudioEngine::instance ()->current_backend ();
1388 vector<uint32_t> all_sizes;
1390 if (backend->use_separate_input_and_output_devices ()) {
1391 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1393 all_sizes = backend->available_buffer_sizes (get_device_name ());
1399 EngineControl::get_default_buffer_sizes ()
1401 vector<uint32_t> sizes;
1402 sizes.push_back (8);
1403 sizes.push_back (16);
1404 sizes.push_back (32);
1405 sizes.push_back (64);
1406 sizes.push_back (128);
1407 sizes.push_back (256);
1408 sizes.push_back (512);
1409 sizes.push_back (1024);
1410 sizes.push_back (2048);
1411 sizes.push_back (4096);
1412 sizes.push_back (8192);
1417 EngineControl::set_buffersize_popdown_strings ()
1419 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1420 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1421 vector<uint32_t> bs;
1424 if (_have_control) {
1425 bs = get_buffer_sizes_for_all_devices ();
1426 } else if (backend->can_change_buffer_size_when_running()) {
1427 bs = get_default_buffer_sizes ();
1430 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1431 s.push_back (bufsize_as_string (*x));
1434 uint32_t previous_size = backend->buffer_size ();
1435 if (!buffer_size_combo.get_active_text().empty()) {
1436 previous_size = get_buffer_size ();
1439 set_popdown_strings (buffer_size_combo, s);
1443 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1444 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1447 buffer_size_combo.set_active_text(s.front());
1449 uint32_t period = backend->buffer_size();
1450 if (0 == period && backend->use_separate_input_and_output_devices()) {
1451 period = backend->default_buffer_size(get_input_device_name());
1453 if (0 == period && backend->use_separate_input_and_output_devices()) {
1454 period = backend->default_buffer_size(get_output_device_name());
1456 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1457 period = backend->default_buffer_size(get_device_name());
1460 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1462 show_buffer_duration ();
1464 update_sensitivity ();
1468 EngineControl::set_nperiods_popdown_strings ()
1470 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1471 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1472 vector<uint32_t> np;
1475 if (backend->can_set_period_size()) {
1476 np = backend->available_period_sizes (get_driver());
1479 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1480 s.push_back (to_string (*x));
1483 set_popdown_strings (nperiods_combo, s);
1486 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1489 update_sensitivity ();
1493 EngineControl::device_changed ()
1495 SignalBlocker blocker (*this, "device_changed");
1496 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1499 string device_name_in;
1500 string device_name_out; // only used if backend support separate I/O devices
1502 if (backend->use_separate_input_and_output_devices()) {
1503 device_name_in = get_input_device_name ();
1504 device_name_out = get_output_device_name ();
1506 device_name_in = get_device_name ();
1509 /* we set the backend-device to query various device related intormation.
1510 * This has the side effect that backend->device_name() will match
1511 * the device_name and 'change_device' will never be true.
1512 * so work around this by setting...
1514 if (backend->use_separate_input_and_output_devices()) {
1515 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1516 queue_device_changed = true;
1519 if (device_name_in != backend->device_name()) {
1520 queue_device_changed = true;
1524 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1525 if (backend->use_separate_input_and_output_devices()) {
1526 backend->set_input_device_name (device_name_in);
1527 backend->set_output_device_name (device_name_out);
1529 backend->set_device_name(device_name_in);
1533 /* don't allow programmatic change to combos to cause a
1534 recursive call to this method.
1536 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1538 set_samplerate_popdown_strings ();
1539 set_buffersize_popdown_strings ();
1540 set_nperiods_popdown_strings ();
1542 /* TODO set min + max channel counts here */
1544 manage_control_app_sensitivity ();
1547 /* pick up any saved state for this device */
1549 if (!ignore_changes) {
1550 maybe_display_saved_state ();
1555 EngineControl::input_device_changed ()
1557 DEBUG_ECONTROL ("input_device_changed");
1559 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1560 if (backend && backend->match_input_output_devices_or_none ()) {
1561 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1563 if (get_output_device_name () != dev_none
1564 && get_input_device_name () != dev_none
1565 && get_input_device_name () != get_output_device_name ()) {
1566 block_changed_signals ();
1567 if (contains_value (output_device_combo, get_input_device_name ())) {
1568 output_device_combo.set_active_text (get_input_device_name ());
1570 assert (contains_value (output_device_combo, dev_none));
1571 output_device_combo.set_active_text (dev_none);
1573 unblock_changed_signals ();
1580 EngineControl::output_device_changed ()
1582 DEBUG_ECONTROL ("output_device_changed");
1583 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1584 if (backend && backend->match_input_output_devices_or_none ()) {
1585 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1587 if (get_input_device_name () != dev_none
1588 && get_input_device_name () != dev_none
1589 && get_input_device_name () != get_output_device_name ()) {
1590 block_changed_signals ();
1591 if (contains_value (input_device_combo, get_output_device_name ())) {
1592 input_device_combo.set_active_text (get_output_device_name ());
1594 assert (contains_value (input_device_combo, dev_none));
1595 input_device_combo.set_active_text (dev_none);
1597 unblock_changed_signals ();
1604 EngineControl::bufsize_as_string (uint32_t sz)
1606 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1610 EngineControl::sample_rate_changed ()
1612 DEBUG_ECONTROL ("sample_rate_changed");
1613 /* reset the strings for buffer size to show the correct msec value
1614 (reflecting the new sample rate).
1617 show_buffer_duration ();
1622 EngineControl::buffer_size_changed ()
1624 DEBUG_ECONTROL ("buffer_size_changed");
1625 if (ARDOUR::AudioEngine::instance()->running()) {
1626 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1627 if (backend && backend->can_change_buffer_size_when_running ()) {
1628 backend->set_buffer_size (get_buffer_size());
1631 show_buffer_duration ();
1635 EngineControl::nperiods_changed ()
1637 DEBUG_ECONTROL ("nperiods_changed");
1638 show_buffer_duration ();
1642 EngineControl::show_buffer_duration ()
1644 DEBUG_ECONTROL ("show_buffer_duration");
1645 /* buffer sizes - convert from just samples to samples + msecs for
1646 * the displayed string
1649 string bs_text = buffer_size_combo.get_active_text ();
1650 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1651 uint32_t rate = get_rate();
1653 /* Except for ALSA and Dummy backends, we don't know the number of periods
1654 * per cycle and settings.
1656 * jack1 vs jack2 have different default latencies since jack2 start
1657 * in async-mode unless --sync is given which adds an extra cycle
1658 * of latency. The value is not known if jackd is started externally..
1660 * So just display the period size, that's also what
1661 * ARDOUR_UI::update_sample_rate() does for the status bar.
1662 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1663 * but still, that's the buffer period, not [round-trip] latency)
1666 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1667 buffer_size_duration_label.set_text (buf);
1671 EngineControl::midi_option_changed ()
1673 DEBUG_ECONTROL ("midi_option_changed");
1674 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1677 backend->set_midi_option (get_midi_option());
1679 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1681 //_midi_devices.clear(); // TODO merge with state-saved settings..
1682 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1683 std::vector<MidiDeviceSettings> new_devices;
1685 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1686 MidiDeviceSettings mds = find_midi_device (i->name);
1687 if (i->available && !mds) {
1688 uint32_t input_latency = 0;
1689 uint32_t output_latency = 0;
1690 if (_can_set_midi_latencies) {
1691 input_latency = backend->systemic_midi_input_latency (i->name);
1692 output_latency = backend->systemic_midi_output_latency (i->name);
1694 bool enabled = backend->midi_device_enabled (i->name);
1695 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1696 new_devices.push_back (ptr);
1697 } else if (i->available) {
1698 new_devices.push_back (mds);
1701 _midi_devices = new_devices;
1703 if (_midi_devices.empty()) {
1704 midi_devices_button.hide ();
1706 midi_devices_button.show ();
1711 EngineControl::parameter_changed ()
1715 EngineControl::State
1716 EngineControl::get_matching_state (const string& backend)
1718 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1719 if ((*i)->backend == backend) {
1726 EngineControl::State
1727 EngineControl::get_matching_state (
1728 const string& backend,
1729 const string& driver,
1730 const string& device)
1732 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1733 if ((*i)->backend == backend &&
1734 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1742 EngineControl::State
1743 EngineControl::get_matching_state (
1744 const string& backend,
1745 const string& driver,
1746 const string& input_device,
1747 const string& output_device)
1749 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1750 if ((*i)->backend == backend &&
1751 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1759 EngineControl::State
1760 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1762 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1765 if (backend->use_separate_input_and_output_devices ()) {
1766 return get_matching_state (backend_combo.get_active_text(),
1767 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1768 input_device_combo.get_active_text(),
1769 output_device_combo.get_active_text());
1771 return get_matching_state (backend_combo.get_active_text(),
1772 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1773 device_combo.get_active_text());
1777 return get_matching_state (backend_combo.get_active_text(),
1779 device_combo.get_active_text());
1782 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1783 const EngineControl::State& state2)
1785 if (state1->backend == state2->backend &&
1786 state1->driver == state2->driver &&
1787 state1->device == state2->device &&
1788 state1->input_device == state2->input_device &&
1789 state1->output_device == state2->output_device) {
1795 // sort active first, then most recently used to the beginning of the list
1797 EngineControl::state_sort_cmp (const State &a, const State &b) {
1801 else if (b->active) {
1805 return a->lru > b->lru;
1809 EngineControl::State
1810 EngineControl::save_state ()
1814 if (!_have_control) {
1815 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1817 state->lru = time (NULL) ;
1820 state.reset(new StateStruct);
1821 state->backend = get_backend ();
1823 state.reset(new StateStruct);
1824 store_state (state);
1827 for (StateList::iterator i = states.begin(); i != states.end();) {
1828 if (equivalent_states (*i, state)) {
1829 i = states.erase(i);
1835 states.push_back (state);
1837 states.sort (state_sort_cmp);
1843 EngineControl::store_state (State state)
1845 state->backend = get_backend ();
1846 state->driver = get_driver ();
1847 state->device = get_device_name ();
1848 state->input_device = get_input_device_name ();
1849 state->output_device = get_output_device_name ();
1850 state->sample_rate = get_rate ();
1851 state->buffer_size = get_buffer_size ();
1852 state->n_periods = get_nperiods ();
1853 state->input_latency = get_input_latency ();
1854 state->output_latency = get_output_latency ();
1855 state->input_channels = get_input_channels ();
1856 state->output_channels = get_output_channels ();
1857 state->midi_option = get_midi_option ();
1858 state->midi_devices = _midi_devices;
1859 state->use_buffered_io = get_use_buffered_io ();
1860 state->lru = time (NULL) ;
1864 EngineControl::maybe_display_saved_state ()
1866 if (!_have_control || ARDOUR::AudioEngine::instance()->running ()) {
1870 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1873 DEBUG_ECONTROL ("Restoring saved state");
1874 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1876 if (!_desired_sample_rate) {
1877 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1879 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1881 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1882 /* call this explicitly because we're ignoring changes to
1883 the controls at this point.
1885 show_buffer_duration ();
1886 input_latency.set_value (state->input_latency);
1887 output_latency.set_value (state->output_latency);
1889 use_buffered_io_button.set_active (state->use_buffered_io);
1891 if (!state->midi_option.empty()) {
1892 midi_option_combo.set_active_text (state->midi_option);
1893 _midi_devices = state->midi_devices;
1896 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1901 EngineControl::get_state ()
1905 XMLNode* root = new XMLNode ("AudioMIDISetup");
1908 if (!states.empty()) {
1909 XMLNode* state_nodes = new XMLNode ("EngineStates");
1911 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1913 XMLNode* node = new XMLNode ("State");
1915 node->set_property ("backend", (*i)->backend);
1916 node->set_property ("driver", (*i)->driver);
1917 node->set_property ("device", (*i)->device);
1918 node->set_property ("input-device", (*i)->input_device);
1919 node->set_property ("output-device", (*i)->output_device);
1920 node->set_property ("sample-rate", (*i)->sample_rate);
1921 node->set_property ("buffer-size", (*i)->buffer_size);
1922 node->set_property ("n-periods", (*i)->n_periods);
1923 node->set_property ("input-latency", (*i)->input_latency);
1924 node->set_property ("output-latency", (*i)->output_latency);
1925 node->set_property ("input-channels", (*i)->input_channels);
1926 node->set_property ("output-channels", (*i)->output_channels);
1927 node->set_property ("active", (*i)->active);
1928 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1929 node->set_property ("midi-option", (*i)->midi_option);
1930 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1931 node->set_property ("lru", lru_val );
1933 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1934 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1935 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1936 midi_device_stuff->set_property (X_("name"), (*p)->name);
1937 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1938 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1939 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1940 midi_devices->add_child_nocopy (*midi_device_stuff);
1942 node->add_child_nocopy (*midi_devices);
1944 state_nodes->add_child_nocopy (*node);
1947 root->add_child_nocopy (*state_nodes);
1954 EngineControl::set_default_state ()
1956 vector<string> backend_names;
1957 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1959 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1960 backend_names.push_back ((*b)->name);
1962 backend_combo.set_active_text (backend_names.front());
1964 // We could set default backends per platform etc here
1970 EngineControl::set_state (const XMLNode& root)
1972 XMLNodeList clist, cclist;
1973 XMLNodeConstIterator citer, cciter;
1974 XMLNode const * child;
1975 XMLNode const * grandchild;
1977 if (root.name() != "AudioMIDISetup") {
1981 clist = root.children();
1985 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1989 if (child->name() != "EngineStates") {
1993 cclist = child->children();
1995 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1996 State state (new StateStruct);
1998 grandchild = *cciter;
2000 if (grandchild->name() != "State") {
2004 if (!grandchild->get_property ("backend", state->backend)) {
2008 // If any of the required properties are not found in the state node
2009 // then continue/skip to the next engine state
2010 if (!grandchild->get_property ("driver", state->driver) ||
2011 !grandchild->get_property ("device", state->device) ||
2012 !grandchild->get_property ("input-device", state->input_device) ||
2013 !grandchild->get_property ("output-device", state->output_device) ||
2014 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2015 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2016 !grandchild->get_property ("input-latency", state->input_latency) ||
2017 !grandchild->get_property ("output-latency", state->output_latency) ||
2018 !grandchild->get_property ("input-channels", state->input_channels) ||
2019 !grandchild->get_property ("output-channels", state->output_channels) ||
2020 !grandchild->get_property ("active", state->active) ||
2021 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2022 !grandchild->get_property ("midi-option", state->midi_option)) {
2026 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2027 // optional (new value in 4.5)
2028 state->n_periods = 0;
2031 state->midi_devices.clear();
2033 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2034 const XMLNodeList mnc = midinode->children();
2035 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2038 uint32_t input_latency;
2039 uint32_t output_latency;
2041 if (!(*n)->get_property (X_("name"), name) ||
2042 !(*n)->get_property (X_("enabled"), enabled) ||
2043 !(*n)->get_property (X_("input-latency"), input_latency) ||
2044 !(*n)->get_property (X_("output-latency"), output_latency)) {
2048 MidiDeviceSettings ptr (
2049 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2050 state->midi_devices.push_back (ptr);
2055 if (grandchild->get_property ("lru", lru_val)) {
2056 state->lru = lru_val;
2059 states.push_back (state);
2063 /* now see if there was an active state and switch the setup to it */
2065 /* purge states of backend that are not available in this built */
2066 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2067 vector<std::string> backend_names;
2069 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2070 backend_names.push_back((*i)->name);
2072 for (StateList::iterator i = states.begin(); i != states.end();) {
2073 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2074 i = states.erase(i);
2080 states.sort (state_sort_cmp);
2082 /* purge old states referring to the same backend */
2083 const time_t now = time (NULL);
2084 for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2086 for (StateList::iterator i = states.begin(); i != states.end();) {
2087 if ((*i)->backend != *bi) {
2090 // keep at latest one for every audio-system
2095 // also keep states used in the last 90 days.
2096 if ((now - (*i)->lru) < 86400 * 90) {
2099 assert (!(*i)->active);
2100 i = states.erase(i);
2104 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2107 return set_current_state (*i);
2114 EngineControl::set_current_state (const State& state)
2116 DEBUG_ECONTROL ("set_current_state");
2118 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2120 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2121 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2122 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2123 // this shouldn't happen as the invalid backend names should have been
2124 // removed from the list of states.
2128 // now reflect the change in the backend in the GUI so backend_changed will
2129 // do the right thing
2130 backend_combo.set_active_text (state->backend);
2132 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2134 // we don't have control don't restore state
2139 if (!state->driver.empty ()) {
2140 if (!backend->requires_driver_selection ()) {
2141 DEBUG_ECONTROL ("Backend should require driver selection");
2142 // A backend has changed from having driver selection to not having
2143 // it or someone has been manually editing a config file and messed
2148 if (backend->set_driver (state->driver) != 0) {
2149 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2150 // Driver names for a backend have changed and the name in the
2151 // config file is now invalid or support for driver is no longer
2152 // included in the backend
2155 // no need to set the driver_combo as backend_changed will use
2156 // backend->driver_name to set the active driver
2159 if (!state->device.empty ()) {
2160 if (backend->set_device_name (state->device) != 0) {
2162 string_compose ("Unable to set device name %1", state->device));
2163 // device is no longer available on the system
2166 // no need to set active device as it will be picked up in
2167 // via backend_changed ()/set_device_popdown_strings
2170 // backend supports separate input/output devices
2171 if (backend->set_input_device_name (state->input_device) != 0) {
2172 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2173 state->input_device));
2174 // input device is no longer available on the system
2178 if (backend->set_output_device_name (state->output_device) != 0) {
2179 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2180 state->input_device));
2181 // output device is no longer available on the system
2184 // no need to set active devices as it will be picked up in via
2185 // backend_changed ()/set_*_device_popdown_strings
2190 // Now restore the state of the rest of the controls
2192 // We don't use a SignalBlocker as set_current_state is currently only
2193 // called from set_state before any signals are connected. If at some point
2194 // a more general named state mechanism is implemented and
2195 // set_current_state is called while signals are connected then a
2196 // SignalBlocker will need to be instantiated before setting these.
2198 device_combo.set_active_text (state->device);
2199 input_device_combo.set_active_text (state->input_device);
2200 output_device_combo.set_active_text (state->output_device);
2201 if (!_desired_sample_rate) {
2202 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2204 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2205 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2206 input_latency.set_value (state->input_latency);
2207 output_latency.set_value (state->output_latency);
2208 midi_option_combo.set_active_text (state->midi_option);
2209 use_buffered_io_button.set_active (state->use_buffered_io);
2214 EngineControl::push_state_to_backend (bool start)
2216 DEBUG_ECONTROL ("push_state_to_backend");
2217 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2218 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2224 /* figure out what is going to change */
2226 bool restart_required = false;
2227 bool was_running = ARDOUR::AudioEngine::instance()->running();
2228 bool change_driver = false;
2229 bool change_device = false;
2230 bool change_rate = false;
2231 bool change_bufsize = false;
2232 bool change_nperiods = false;
2233 bool change_latency = false;
2234 bool change_channels = false;
2235 bool change_midi = false;
2236 bool change_buffered_io = false;
2238 uint32_t ochan = get_output_channels ();
2239 uint32_t ichan = get_input_channels ();
2241 if (_have_control) {
2243 if (started_at_least_once) {
2245 /* we can control the backend */
2247 if (backend->requires_driver_selection()) {
2248 if (get_driver() != backend->driver_name()) {
2249 change_driver = true;
2253 if (backend->use_separate_input_and_output_devices()) {
2254 if (get_input_device_name() != backend->input_device_name()) {
2255 change_device = true;
2257 if (get_output_device_name() != backend->output_device_name()) {
2258 change_device = true;
2261 if (get_device_name() != backend->device_name()) {
2262 change_device = true;
2266 if (queue_device_changed) {
2267 change_device = true;
2270 if (get_rate() != backend->sample_rate()) {
2274 if (get_buffer_size() != backend->buffer_size()) {
2275 change_bufsize = true;
2278 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2279 && get_nperiods() != backend->period_size()) {
2280 change_nperiods = true;
2283 if (get_midi_option() != backend->midi_option()) {
2287 if (backend->can_use_buffered_io()) {
2288 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2289 change_buffered_io = true;
2293 /* zero-requested channels means "all available" */
2296 ichan = backend->input_channels();
2300 ochan = backend->output_channels();
2303 if (ichan != backend->input_channels()) {
2304 change_channels = true;
2307 if (ochan != backend->output_channels()) {
2308 change_channels = true;
2311 if (get_input_latency() != backend->systemic_input_latency() ||
2312 get_output_latency() != backend->systemic_output_latency()) {
2313 change_latency = true;
2316 /* backend never started, so we have to force a group
2319 change_device = true;
2320 if (backend->requires_driver_selection()) {
2321 change_driver = true;
2324 change_bufsize = true;
2325 change_channels = true;
2326 change_latency = true;
2328 change_buffered_io = backend->can_use_buffered_io();
2329 change_channels = true;
2330 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2335 /* we have no control over the backend, meaning that we can
2336 * only possibly change sample rate and buffer size.
2340 if (get_rate() != backend->sample_rate()) {
2341 change_bufsize = true;
2344 if (get_buffer_size() != backend->buffer_size()) {
2345 change_bufsize = true;
2349 queue_device_changed = false;
2351 if (!_have_control) {
2353 /* We do not have control over the backend, so the best we can
2354 * do is try to change the sample rate and/or bufsize and get
2358 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2362 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2367 backend->set_sample_rate (get_rate());
2370 if (change_bufsize) {
2371 backend->set_buffer_size (get_buffer_size());
2375 if (ARDOUR::AudioEngine::instance()->start ()) {
2376 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2386 /* determine if we need to stop the backend before changing parameters */
2388 if (change_driver || change_device || change_channels || change_nperiods ||
2389 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2390 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2391 change_midi || change_buffered_io ||
2392 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2393 restart_required = true;
2395 restart_required = false;
2400 if (restart_required) {
2401 if (ARDOUR::AudioEngine::instance()->stop()) {
2407 if (change_driver && backend->set_driver (get_driver())) {
2408 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2411 if (backend->use_separate_input_and_output_devices()) {
2412 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2413 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2416 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2417 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2421 if (change_device && backend->set_device_name (get_device_name())) {
2422 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2426 if (change_rate && backend->set_sample_rate (get_rate())) {
2427 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2430 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2431 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2434 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2435 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2439 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2440 if (backend->set_input_channels (get_input_channels())) {
2441 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2444 if (backend->set_output_channels (get_output_channels())) {
2445 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2449 if (change_latency) {
2450 if (backend->set_systemic_input_latency (get_input_latency())) {
2451 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2454 if (backend->set_systemic_output_latency (get_output_latency())) {
2455 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2461 backend->set_midi_option (get_midi_option());
2464 if (change_buffered_io) {
2465 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2469 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2470 if (_measure_midi) {
2471 if (*p == _measure_midi) {
2472 backend->set_midi_device_enabled ((*p)->name, true);
2474 backend->set_midi_device_enabled ((*p)->name, false);
2476 if (backend->can_change_systemic_latency_when_running ()) {
2477 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2478 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2482 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2483 if (backend->can_set_systemic_midi_latencies()) {
2484 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2485 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2490 if (start || (was_running && restart_required)) {
2491 if (ARDOUR::AudioEngine::instance()->start()) {
2502 EngineControl::post_push ()
2504 /* get a pointer to the current state object, creating one if
2508 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2511 state = save_state ();
2517 states.sort (state_sort_cmp);
2521 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2522 (*i)->active = false;
2525 /* mark this one active (to be used next time the dialog is
2529 state->active = true;
2531 if (_have_control) { // XXX
2532 manage_control_app_sensitivity ();
2535 /* schedule a redisplay of MIDI ports */
2536 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2541 EngineControl::get_rate () const
2543 float r = atof (sample_rate_combo.get_active_text ());
2544 /* the string may have been translated with an abbreviation for
2545 * thousands, so use a crude heuristic to fix this.
2555 EngineControl::get_buffer_size () const
2557 string txt = buffer_size_combo.get_active_text ();
2560 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2561 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2562 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2570 EngineControl::get_nperiods () const
2572 string txt = nperiods_combo.get_active_text ();
2573 return atoi (txt.c_str());
2577 EngineControl::get_midi_option () const
2579 return midi_option_combo.get_active_text();
2583 EngineControl::get_use_buffered_io () const
2585 return use_buffered_io_button.get_active();
2589 EngineControl::get_input_channels() const
2591 if (ARDOUR::Profile->get_mixbus()) {
2592 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2593 if (!backend) return 0;
2594 return backend->input_channels();
2596 return (uint32_t) input_channels_adjustment.get_value();
2600 EngineControl::get_output_channels() const
2602 if (ARDOUR::Profile->get_mixbus()) {
2603 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2604 if (!backend) return 0;
2605 return backend->input_channels();
2607 return (uint32_t) output_channels_adjustment.get_value();
2611 EngineControl::get_input_latency() const
2613 return (uint32_t) input_latency_adjustment.get_value();
2617 EngineControl::get_output_latency() const
2619 return (uint32_t) output_latency_adjustment.get_value();
2623 EngineControl::get_backend () const
2625 return backend_combo.get_active_text ();
2629 EngineControl::get_driver () const
2631 if (driver_combo.get_parent()) {
2632 return driver_combo.get_active_text ();
2639 EngineControl::get_device_name () const
2641 return device_combo.get_active_text ();
2645 EngineControl::get_input_device_name () const
2647 return input_device_combo.get_active_text ();
2651 EngineControl::get_output_device_name () const
2653 return output_device_combo.get_active_text ();
2657 EngineControl::control_app_button_clicked ()
2659 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2665 backend->launch_control_app ();
2669 EngineControl::start_stop_button_clicked ()
2671 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2677 if (ARDOUR::AudioEngine::instance()->running()) {
2678 ARDOUR::AudioEngine::instance()->stop ();
2680 if (!ARDOUR_UI::instance()->session_loaded) {
2686 if (!ARDOUR_UI::instance()->session_loaded) {
2687 ArdourDialog::on_response (RESPONSE_OK);
2693 EngineControl::update_devices_button_clicked ()
2695 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2701 if (backend->update_devices()) {
2702 device_list_changed ();
2707 EngineControl::use_buffered_io_button_clicked ()
2709 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2715 bool set_buffered_io = !use_buffered_io_button.get_active();
2716 use_buffered_io_button.set_active (set_buffered_io);
2717 backend->set_use_buffered_io (set_buffered_io);
2721 EngineControl::manage_control_app_sensitivity ()
2723 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2729 string appname = backend->control_app_name();
2731 if (appname.empty()) {
2732 control_app_button.set_sensitive (false);
2734 control_app_button.set_sensitive (true);
2739 EngineControl::set_desired_sample_rate (uint32_t sr)
2741 _desired_sample_rate = sr;
2742 if (ARDOUR::AudioEngine::instance ()->running ()
2743 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2750 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2752 if (page_num == 0) {
2753 _measure_midi.reset();
2754 update_sensitivity ();
2757 if (page_num == midi_tab) {
2759 refresh_midi_display ();
2762 if (page_num == latency_tab) {
2765 if (ARDOUR::AudioEngine::instance()->running()) {
2770 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2772 /* save any existing latency values */
2774 uint32_t il = (uint32_t) input_latency.get_value ();
2775 uint32_t ol = (uint32_t) input_latency.get_value ();
2777 /* reset to zero so that our new test instance
2778 will be clean of any existing latency measures.
2780 NB. this should really be done by the backend
2781 when stated for latency measurement.
2784 input_latency.set_value (0);
2785 output_latency.set_value (0);
2787 push_state_to_backend (false);
2791 input_latency.set_value (il);
2792 output_latency.set_value (ol);
2795 // This should be done in push_state_to_backend()
2796 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2797 disable_latency_tab ();
2800 enable_latency_tab ();
2804 end_latency_detection ();
2805 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2810 /* latency measurement */
2813 EngineControl::check_audio_latency_measurement ()
2815 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2817 if (mtdm->resolve () < 0) {
2818 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2822 if (mtdm->get_peak () > 0.707f) {
2823 // get_peak() resets the peak-hold in the detector.
2824 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2825 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2829 if (mtdm->err () > 0.3) {
2835 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2837 if (sample_rate == 0) {
2838 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2839 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2843 int frames_total = mtdm->del();
2844 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2846 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2847 _("Detected roundtrip latency: "),
2848 frames_total, frames_total * 1000.0f/sample_rate,
2849 _("Systemic latency: "),
2850 extra, extra * 1000.0f/sample_rate);
2854 if (mtdm->err () > 0.2) {
2856 strcat (buf, _("(signal detection error)"));
2862 strcat (buf, _("(inverted - bad wiring)"));
2866 lm_results.set_markup (string_compose (results_markup, buf));
2869 have_lm_results = true;
2870 end_latency_detection ();
2871 lm_use_button.set_sensitive (true);
2879 EngineControl::check_midi_latency_measurement ()
2881 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2883 if (!mididm->have_signal () || mididm->latency () == 0) {
2884 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2889 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2891 if (sample_rate == 0) {
2892 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2893 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2897 ARDOUR::framecnt_t frames_total = mididm->latency();
2898 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2899 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2900 _("Detected roundtrip latency: "),
2901 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2902 _("Systemic latency: "),
2903 extra, extra * 1000.0f / sample_rate);
2907 if (!mididm->ok ()) {
2909 strcat (buf, _("(averaging)"));
2913 if (mididm->deviation () > 50.0) {
2915 strcat (buf, _("(too large jitter)"));
2917 } else if (mididm->deviation () > 10.0) {
2919 strcat (buf, _("(large jitter)"));
2923 have_lm_results = true;
2924 end_latency_detection ();
2925 lm_use_button.set_sensitive (true);
2926 lm_results.set_markup (string_compose (results_markup, buf));
2928 } else if (mididm->processed () > 400) {
2929 have_lm_results = false;
2930 end_latency_detection ();
2931 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2935 lm_results.set_markup (string_compose (results_markup, buf));
2941 EngineControl::start_latency_detection ()
2943 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2944 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2946 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2947 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2948 if (_measure_midi) {
2949 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2951 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2953 lm_measure_label.set_text (_("Cancel"));
2954 have_lm_results = false;
2955 lm_use_button.set_sensitive (false);
2956 lm_input_channel_combo.set_sensitive (false);
2957 lm_output_channel_combo.set_sensitive (false);
2963 EngineControl::end_latency_detection ()
2965 latency_timeout.disconnect ();
2966 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2967 lm_measure_label.set_text (_("Measure"));
2968 if (!have_lm_results) {
2969 lm_use_button.set_sensitive (false);
2971 lm_input_channel_combo.set_sensitive (true);
2972 lm_output_channel_combo.set_sensitive (true);
2977 EngineControl::latency_button_clicked ()
2980 start_latency_detection ();
2982 end_latency_detection ();
2987 EngineControl::latency_back_button_clicked ()
2989 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2990 notebook.set_current_page(0);
2994 EngineControl::use_latency_button_clicked ()
2996 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2997 if (_measure_midi) {
2998 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3002 ARDOUR::framecnt_t frames_total = mididm->latency();
3003 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3004 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3005 _measure_midi->input_latency = one_way;
3006 _measure_midi->output_latency = one_way;
3007 if (backend->can_change_systemic_latency_when_running ()) {
3008 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3009 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3011 notebook.set_current_page (midi_tab);
3013 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3019 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3020 one_way = std::max (0., one_way);
3022 input_latency_adjustment.set_value (one_way);
3023 output_latency_adjustment.set_value (one_way);
3024 if (backend->can_change_systemic_latency_when_running ()) {
3025 backend->set_systemic_input_latency (one_way);
3026 backend->set_systemic_output_latency (one_way);
3029 /* back to settings page */
3030 notebook.set_current_page (0);
3035 EngineControl::on_delete_event (GdkEventAny* ev)
3037 if (notebook.get_current_page() == 2) {
3038 /* currently on latency tab - be sure to clean up */
3039 end_latency_detection ();
3041 return ArdourDialog::on_delete_event (ev);
3045 EngineControl::engine_running ()
3047 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3050 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3051 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3053 if (backend->can_set_period_size ()) {
3054 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3057 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3058 connect_disconnect_button.show();
3060 started_at_least_once = true;
3061 if (_have_control) {
3062 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3064 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3066 update_sensitivity();
3070 EngineControl::engine_stopped ()
3072 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3075 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3076 connect_disconnect_button.show();
3078 if (_have_control) {
3079 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3081 engine_status.set_markup(X_(""));
3084 update_sensitivity();
3088 EngineControl::device_list_changed ()
3090 if (ignore_device_changes) {
3093 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3095 midi_option_changed();
3099 EngineControl::connect_disconnect_click()
3101 if (ARDOUR::AudioEngine::instance()->running()) {
3104 if (!ARDOUR_UI::instance()->session_loaded) {
3110 if (!ARDOUR_UI::instance()->session_loaded) {
3111 ArdourDialog::on_response (RESPONSE_OK);
3117 EngineControl::calibrate_audio_latency ()
3119 _measure_midi.reset ();
3120 have_lm_results = false;
3121 lm_use_button.set_sensitive (false);
3122 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3123 notebook.set_current_page (latency_tab);
3127 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3130 have_lm_results = false;
3131 lm_use_button.set_sensitive (false);
3132 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3133 notebook.set_current_page (latency_tab);
3137 EngineControl::configure_midi_devices ()
3139 notebook.set_current_page (midi_tab);