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_buffersize_popdown_strings ();
1036 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1039 if (_have_control && !ignore_changes) {
1040 // set driver & devices
1041 State state = get_matching_state (backend_combo.get_active_text());
1043 DEBUG_ECONTROL ("backend-changed(): found prior state for backend");
1044 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1045 set_current_state (state);
1047 DEBUG_ECONTROL ("backend-changed(): no prior state for backend");
1050 DEBUG_ECONTROL (string_compose ("backend-changed(): _have_control=%1 ignore_changes=%2", _have_control, ignore_changes));
1053 if (!ignore_changes) {
1054 maybe_display_saved_state ();
1059 EngineControl::update_midi_options ()
1061 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1062 vector<string> midi_options = backend->enumerate_midi_options();
1064 if (midi_options.size() == 1) {
1065 /* only contains the "none" option */
1066 midi_option_combo.set_sensitive (false);
1068 if (_have_control) {
1069 set_popdown_strings (midi_option_combo, midi_options);
1070 midi_option_combo.set_active_text (midi_options.front());
1071 midi_option_combo.set_sensitive (true);
1073 midi_option_combo.set_sensitive (false);
1079 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1081 if (ARDOUR::Profile->get_mixbus()) {
1085 uint32_t cnt = (uint32_t) sb->get_value();
1087 sb->set_text (_("all available channels"));
1090 snprintf (buf, sizeof (buf), "%d", cnt);
1096 // @return true if there are drivers available
1098 EngineControl::set_driver_popdown_strings ()
1100 DEBUG_ECONTROL ("set_driver_popdown_strings");
1101 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1102 vector<string> drivers = backend->enumerate_drivers();
1104 if (drivers.empty ()) {
1105 // This is an error...?
1109 string current_driver = backend->driver_name ();
1111 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1113 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1116 current_driver = drivers.front ();
1119 set_popdown_strings (driver_combo, drivers);
1121 string_compose ("driver_combo.set_active_text: %1", current_driver));
1122 driver_combo.set_active_text (current_driver);
1127 EngineControl::get_default_device(const string& current_device_name,
1128 const vector<string>& available_devices)
1130 // If the current device is available, use it as default
1131 if (std::find (available_devices.begin (),
1132 available_devices.end (),
1133 current_device_name) != available_devices.end ()) {
1135 return current_device_name;
1138 using namespace ARDOUR;
1140 string default_device_name =
1141 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1143 vector<string>::const_iterator i;
1145 // If there is a "Default" device available, use it
1146 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1147 if (*i == default_device_name) {
1152 string none_device_name =
1153 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1155 // Use the first device that isn't "None"
1156 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1157 if (*i != none_device_name) {
1162 // Use "None" if there are no other available
1163 return available_devices.front();
1166 // @return true if there are devices available
1168 EngineControl::set_device_popdown_strings ()
1170 DEBUG_ECONTROL ("set_device_popdown_strings");
1171 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1172 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1174 /* NOTE: Ardour currently does not display the "available" field of the
1177 * Doing so would require a different GUI widget than the combo
1178 * box/popdown that we currently use, since it has no way to list
1179 * items that are not selectable. Something more like a popup menu,
1180 * which could have unselectable items, would be appropriate.
1183 vector<string> available_devices;
1185 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1186 available_devices.push_back (i->name);
1189 if (available_devices.empty ()) {
1193 set_popdown_strings (device_combo, available_devices);
1195 std::string default_device =
1196 get_default_device(backend->device_name(), available_devices);
1199 string_compose ("set device_combo active text: %1", default_device));
1201 device_combo.set_active_text(default_device);
1205 // @return true if there are input devices available
1207 EngineControl::set_input_device_popdown_strings ()
1209 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1210 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1211 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1213 vector<string> available_devices;
1215 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1216 available_devices.push_back (i->name);
1219 if (available_devices.empty()) {
1223 set_popdown_strings (input_device_combo, available_devices);
1225 std::string default_device =
1226 get_default_device(backend->input_device_name(), available_devices);
1229 string_compose ("set input_device_combo active text: %1", default_device));
1230 input_device_combo.set_active_text(default_device);
1234 // @return true if there are output devices available
1236 EngineControl::set_output_device_popdown_strings ()
1238 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1239 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1240 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1242 vector<string> available_devices;
1244 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1245 available_devices.push_back (i->name);
1248 if (available_devices.empty()) {
1252 set_popdown_strings (output_device_combo, available_devices);
1254 std::string default_device =
1255 get_default_device(backend->output_device_name(), available_devices);
1258 string_compose ("set output_device_combo active text: %1", default_device));
1259 output_device_combo.set_active_text(default_device);
1264 EngineControl::list_devices ()
1266 DEBUG_ECONTROL ("list_devices");
1267 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1270 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1272 bool devices_available = false;
1274 if (backend->use_separate_input_and_output_devices ()) {
1275 bool input_devices_available = set_input_device_popdown_strings ();
1276 bool output_devices_available = set_output_device_popdown_strings ();
1277 devices_available = input_devices_available || output_devices_available;
1279 devices_available = set_device_popdown_strings ();
1282 if (devices_available) {
1285 device_combo.clear();
1286 input_device_combo.clear();
1287 output_device_combo.clear();
1289 update_sensitivity ();
1293 EngineControl::driver_changed ()
1295 SignalBlocker blocker (*this, "driver_changed");
1296 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1299 backend->set_driver (driver_combo.get_active_text());
1302 // TODO load LRU device(s) for backend + driver combo
1304 if (!ignore_changes) {
1305 maybe_display_saved_state ();
1310 EngineControl::get_sample_rates_for_all_devices ()
1312 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1313 ARDOUR::AudioEngine::instance ()->current_backend ();
1314 vector<float> all_rates;
1316 if (backend->use_separate_input_and_output_devices ()) {
1317 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1319 all_rates = backend->available_sample_rates (get_device_name ());
1325 EngineControl::get_default_sample_rates ()
1327 vector<float> rates;
1328 rates.push_back (8000.0f);
1329 rates.push_back (16000.0f);
1330 rates.push_back (32000.0f);
1331 rates.push_back (44100.0f);
1332 rates.push_back (48000.0f);
1333 rates.push_back (88200.0f);
1334 rates.push_back (96000.0f);
1335 rates.push_back (192000.0f);
1336 rates.push_back (384000.0f);
1341 EngineControl::set_samplerate_popdown_strings ()
1343 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1344 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1349 if (_have_control) {
1350 sr = get_sample_rates_for_all_devices ();
1352 sr = get_default_sample_rates ();
1355 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1356 s.push_back (rate_as_string (*x));
1357 if (*x == _desired_sample_rate) {
1362 set_popdown_strings (sample_rate_combo, s);
1365 if (ARDOUR::AudioEngine::instance()->running()) {
1366 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1368 else if (desired.empty ()) {
1369 float new_active_sr = backend->default_sample_rate ();
1371 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1372 new_active_sr = sr.front ();
1375 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1377 sample_rate_combo.set_active_text (desired);
1381 update_sensitivity ();
1385 EngineControl::get_buffer_sizes_for_all_devices ()
1387 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1388 ARDOUR::AudioEngine::instance ()->current_backend ();
1389 vector<uint32_t> all_sizes;
1391 if (backend->use_separate_input_and_output_devices ()) {
1392 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1394 all_sizes = backend->available_buffer_sizes (get_device_name ());
1400 EngineControl::get_default_buffer_sizes ()
1402 vector<uint32_t> sizes;
1403 sizes.push_back (8);
1404 sizes.push_back (16);
1405 sizes.push_back (32);
1406 sizes.push_back (64);
1407 sizes.push_back (128);
1408 sizes.push_back (256);
1409 sizes.push_back (512);
1410 sizes.push_back (1024);
1411 sizes.push_back (2048);
1412 sizes.push_back (4096);
1413 sizes.push_back (8192);
1418 EngineControl::set_buffersize_popdown_strings ()
1420 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1421 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1422 vector<uint32_t> bs;
1425 if (_have_control) {
1426 bs = get_buffer_sizes_for_all_devices ();
1427 } else if (backend->can_change_buffer_size_when_running()) {
1428 bs = get_default_buffer_sizes ();
1431 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1432 s.push_back (bufsize_as_string (*x));
1435 uint32_t previous_size = backend->buffer_size ();
1436 if (!buffer_size_combo.get_active_text().empty()) {
1437 previous_size = get_buffer_size ();
1440 set_popdown_strings (buffer_size_combo, s);
1444 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1445 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1448 buffer_size_combo.set_active_text(s.front());
1450 uint32_t period = backend->buffer_size();
1451 if (0 == period && backend->use_separate_input_and_output_devices()) {
1452 period = backend->default_buffer_size(get_input_device_name());
1454 if (0 == period && backend->use_separate_input_and_output_devices()) {
1455 period = backend->default_buffer_size(get_output_device_name());
1457 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1458 period = backend->default_buffer_size(get_device_name());
1461 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1463 show_buffer_duration ();
1465 update_sensitivity ();
1469 EngineControl::set_nperiods_popdown_strings ()
1471 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1472 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1473 vector<uint32_t> np;
1476 if (backend->can_set_period_size()) {
1477 np = backend->available_period_sizes (get_driver());
1480 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1481 s.push_back (to_string (*x));
1484 set_popdown_strings (nperiods_combo, s);
1487 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1490 update_sensitivity ();
1494 EngineControl::device_changed ()
1496 SignalBlocker blocker (*this, "device_changed");
1497 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1500 string device_name_in;
1501 string device_name_out; // only used if backend support separate I/O devices
1503 if (backend->use_separate_input_and_output_devices()) {
1504 device_name_in = get_input_device_name ();
1505 device_name_out = get_output_device_name ();
1507 device_name_in = get_device_name ();
1510 /* we set the backend-device to query various device related intormation.
1511 * This has the side effect that backend->device_name() will match
1512 * the device_name and 'change_device' will never be true.
1513 * so work around this by setting...
1515 if (backend->use_separate_input_and_output_devices()) {
1516 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1517 queue_device_changed = true;
1520 if (device_name_in != backend->device_name()) {
1521 queue_device_changed = true;
1525 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1526 if (backend->use_separate_input_and_output_devices()) {
1527 backend->set_input_device_name (device_name_in);
1528 backend->set_output_device_name (device_name_out);
1530 backend->set_device_name(device_name_in);
1534 /* don't allow programmatic change to combos to cause a
1535 recursive call to this method.
1537 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1539 set_samplerate_popdown_strings ();
1540 set_buffersize_popdown_strings ();
1541 set_nperiods_popdown_strings ();
1543 /* TODO set min + max channel counts here */
1545 manage_control_app_sensitivity ();
1548 /* pick up any saved state for this device */
1550 if (!ignore_changes) {
1551 maybe_display_saved_state ();
1556 EngineControl::input_device_changed ()
1558 DEBUG_ECONTROL ("input_device_changed");
1560 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1561 if (backend && backend->match_input_output_devices_or_none ()) {
1562 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1564 if (get_output_device_name () != dev_none
1565 && get_input_device_name () != dev_none
1566 && get_input_device_name () != get_output_device_name ()) {
1567 block_changed_signals ();
1568 if (contains_value (output_device_combo, get_input_device_name ())) {
1569 output_device_combo.set_active_text (get_input_device_name ());
1571 assert (contains_value (output_device_combo, dev_none));
1572 output_device_combo.set_active_text (dev_none);
1574 unblock_changed_signals ();
1581 EngineControl::output_device_changed ()
1583 DEBUG_ECONTROL ("output_device_changed");
1584 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1585 if (backend && backend->match_input_output_devices_or_none ()) {
1586 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1588 if (get_input_device_name () != dev_none
1589 && get_input_device_name () != dev_none
1590 && get_input_device_name () != get_output_device_name ()) {
1591 block_changed_signals ();
1592 if (contains_value (input_device_combo, get_output_device_name ())) {
1593 input_device_combo.set_active_text (get_output_device_name ());
1595 assert (contains_value (input_device_combo, dev_none));
1596 input_device_combo.set_active_text (dev_none);
1598 unblock_changed_signals ();
1605 EngineControl::bufsize_as_string (uint32_t sz)
1607 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1611 EngineControl::sample_rate_changed ()
1613 DEBUG_ECONTROL ("sample_rate_changed");
1614 /* reset the strings for buffer size to show the correct msec value
1615 (reflecting the new sample rate).
1618 show_buffer_duration ();
1623 EngineControl::buffer_size_changed ()
1625 DEBUG_ECONTROL ("buffer_size_changed");
1626 if (ARDOUR::AudioEngine::instance()->running()) {
1627 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1628 if (backend && backend->can_change_buffer_size_when_running ()) {
1629 backend->set_buffer_size (get_buffer_size());
1632 show_buffer_duration ();
1636 EngineControl::nperiods_changed ()
1638 DEBUG_ECONTROL ("nperiods_changed");
1639 show_buffer_duration ();
1643 EngineControl::show_buffer_duration ()
1645 DEBUG_ECONTROL ("show_buffer_duration");
1646 /* buffer sizes - convert from just samples to samples + msecs for
1647 * the displayed string
1650 string bs_text = buffer_size_combo.get_active_text ();
1651 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1652 uint32_t rate = get_rate();
1654 /* Except for ALSA and Dummy backends, we don't know the number of periods
1655 * per cycle and settings.
1657 * jack1 vs jack2 have different default latencies since jack2 start
1658 * in async-mode unless --sync is given which adds an extra cycle
1659 * of latency. The value is not known if jackd is started externally..
1661 * So just display the period size, that's also what
1662 * ARDOUR_UI::update_sample_rate() does for the status bar.
1663 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1664 * but still, that's the buffer period, not [round-trip] latency)
1667 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1668 buffer_size_duration_label.set_text (buf);
1672 EngineControl::midi_option_changed ()
1674 DEBUG_ECONTROL ("midi_option_changed");
1675 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1678 backend->set_midi_option (get_midi_option());
1680 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1682 //_midi_devices.clear(); // TODO merge with state-saved settings..
1683 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1684 std::vector<MidiDeviceSettings> new_devices;
1686 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1687 MidiDeviceSettings mds = find_midi_device (i->name);
1688 if (i->available && !mds) {
1689 uint32_t input_latency = 0;
1690 uint32_t output_latency = 0;
1691 if (_can_set_midi_latencies) {
1692 input_latency = backend->systemic_midi_input_latency (i->name);
1693 output_latency = backend->systemic_midi_output_latency (i->name);
1695 bool enabled = backend->midi_device_enabled (i->name);
1696 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1697 new_devices.push_back (ptr);
1698 } else if (i->available) {
1699 new_devices.push_back (mds);
1702 _midi_devices = new_devices;
1704 if (_midi_devices.empty()) {
1705 midi_devices_button.hide ();
1707 midi_devices_button.show ();
1712 EngineControl::parameter_changed ()
1716 EngineControl::State
1717 EngineControl::get_matching_state (const string& backend)
1719 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1720 if ((*i)->backend == backend) {
1727 EngineControl::State
1728 EngineControl::get_matching_state (
1729 const string& backend,
1730 const string& driver,
1731 const string& device)
1733 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1734 if ((*i)->backend == backend &&
1735 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1743 EngineControl::State
1744 EngineControl::get_matching_state (
1745 const string& backend,
1746 const string& driver,
1747 const string& input_device,
1748 const string& output_device)
1750 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1751 if ((*i)->backend == backend &&
1752 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1760 EngineControl::State
1761 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1763 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1766 if (backend->use_separate_input_and_output_devices ()) {
1767 return get_matching_state (backend_combo.get_active_text(),
1768 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1769 input_device_combo.get_active_text(),
1770 output_device_combo.get_active_text());
1772 return get_matching_state (backend_combo.get_active_text(),
1773 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1774 device_combo.get_active_text());
1778 return get_matching_state (backend_combo.get_active_text(),
1780 device_combo.get_active_text());
1783 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1784 const EngineControl::State& state2)
1786 if (state1->backend == state2->backend &&
1787 state1->driver == state2->driver &&
1788 state1->device == state2->device &&
1789 state1->input_device == state2->input_device &&
1790 state1->output_device == state2->output_device) {
1796 // sort active first, then most recently used to the beginning of the list
1798 EngineControl::state_sort_cmp (const State &a, const State &b) {
1802 else if (b->active) {
1806 return a->lru > b->lru;
1810 EngineControl::State
1811 EngineControl::save_state ()
1815 if (!_have_control) {
1816 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1818 state->lru = time (NULL) ;
1821 state.reset(new StateStruct);
1822 state->backend = get_backend ();
1824 state.reset(new StateStruct);
1825 store_state (state);
1828 for (StateList::iterator i = states.begin(); i != states.end();) {
1829 if (equivalent_states (*i, state)) {
1830 i = states.erase(i);
1836 states.push_back (state);
1838 states.sort (state_sort_cmp);
1844 EngineControl::store_state (State state)
1846 state->backend = get_backend ();
1847 state->driver = get_driver ();
1848 state->device = get_device_name ();
1849 state->input_device = get_input_device_name ();
1850 state->output_device = get_output_device_name ();
1851 state->sample_rate = get_rate ();
1852 state->buffer_size = get_buffer_size ();
1853 state->n_periods = get_nperiods ();
1854 state->input_latency = get_input_latency ();
1855 state->output_latency = get_output_latency ();
1856 state->input_channels = get_input_channels ();
1857 state->output_channels = get_output_channels ();
1858 state->midi_option = get_midi_option ();
1859 state->midi_devices = _midi_devices;
1860 state->use_buffered_io = get_use_buffered_io ();
1861 state->lru = time (NULL) ;
1865 EngineControl::maybe_display_saved_state ()
1867 if (!_have_control || ARDOUR::AudioEngine::instance()->running ()) {
1871 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1874 DEBUG_ECONTROL ("Restoring saved state");
1875 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1877 if (!_desired_sample_rate) {
1878 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1880 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1882 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1883 /* call this explicitly because we're ignoring changes to
1884 the controls at this point.
1886 show_buffer_duration ();
1887 input_latency.set_value (state->input_latency);
1888 output_latency.set_value (state->output_latency);
1890 use_buffered_io_button.set_active (state->use_buffered_io);
1892 if (!state->midi_option.empty()) {
1893 midi_option_combo.set_active_text (state->midi_option);
1894 _midi_devices = state->midi_devices;
1897 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1902 EngineControl::get_state ()
1906 XMLNode* root = new XMLNode ("AudioMIDISetup");
1909 if (!states.empty()) {
1910 XMLNode* state_nodes = new XMLNode ("EngineStates");
1912 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1914 XMLNode* node = new XMLNode ("State");
1916 node->set_property ("backend", (*i)->backend);
1917 node->set_property ("driver", (*i)->driver);
1918 node->set_property ("device", (*i)->device);
1919 node->set_property ("input-device", (*i)->input_device);
1920 node->set_property ("output-device", (*i)->output_device);
1921 node->set_property ("sample-rate", (*i)->sample_rate);
1922 node->set_property ("buffer-size", (*i)->buffer_size);
1923 node->set_property ("n-periods", (*i)->n_periods);
1924 node->set_property ("input-latency", (*i)->input_latency);
1925 node->set_property ("output-latency", (*i)->output_latency);
1926 node->set_property ("input-channels", (*i)->input_channels);
1927 node->set_property ("output-channels", (*i)->output_channels);
1928 node->set_property ("active", (*i)->active);
1929 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1930 node->set_property ("midi-option", (*i)->midi_option);
1931 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1932 node->set_property ("lru", lru_val );
1934 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1935 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1936 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1937 midi_device_stuff->set_property (X_("name"), (*p)->name);
1938 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1939 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1940 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1941 midi_devices->add_child_nocopy (*midi_device_stuff);
1943 node->add_child_nocopy (*midi_devices);
1945 state_nodes->add_child_nocopy (*node);
1948 root->add_child_nocopy (*state_nodes);
1955 EngineControl::set_default_state ()
1957 vector<string> backend_names;
1958 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1960 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1961 backend_names.push_back ((*b)->name);
1963 backend_combo.set_active_text (backend_names.front());
1965 // We could set default backends per platform etc here
1971 EngineControl::set_state (const XMLNode& root)
1973 XMLNodeList clist, cclist;
1974 XMLNodeConstIterator citer, cciter;
1975 XMLNode const * child;
1976 XMLNode const * grandchild;
1978 if (root.name() != "AudioMIDISetup") {
1982 clist = root.children();
1986 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1990 if (child->name() != "EngineStates") {
1994 cclist = child->children();
1996 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1997 State state (new StateStruct);
1999 grandchild = *cciter;
2001 if (grandchild->name() != "State") {
2005 if (!grandchild->get_property ("backend", state->backend)) {
2009 // If any of the required properties are not found in the state node
2010 // then continue/skip to the next engine state
2011 if (!grandchild->get_property ("driver", state->driver) ||
2012 !grandchild->get_property ("device", state->device) ||
2013 !grandchild->get_property ("input-device", state->input_device) ||
2014 !grandchild->get_property ("output-device", state->output_device) ||
2015 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2016 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2017 !grandchild->get_property ("input-latency", state->input_latency) ||
2018 !grandchild->get_property ("output-latency", state->output_latency) ||
2019 !grandchild->get_property ("input-channels", state->input_channels) ||
2020 !grandchild->get_property ("output-channels", state->output_channels) ||
2021 !grandchild->get_property ("active", state->active) ||
2022 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2023 !grandchild->get_property ("midi-option", state->midi_option)) {
2027 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2028 // optional (new value in 4.5)
2029 state->n_periods = 0;
2032 state->midi_devices.clear();
2034 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2035 const XMLNodeList mnc = midinode->children();
2036 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2039 uint32_t input_latency;
2040 uint32_t output_latency;
2042 if (!(*n)->get_property (X_("name"), name) ||
2043 !(*n)->get_property (X_("enabled"), enabled) ||
2044 !(*n)->get_property (X_("input-latency"), input_latency) ||
2045 !(*n)->get_property (X_("output-latency"), output_latency)) {
2049 MidiDeviceSettings ptr (
2050 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2051 state->midi_devices.push_back (ptr);
2056 if (grandchild->get_property ("lru", lru_val)) {
2057 state->lru = lru_val;
2060 states.push_back (state);
2064 /* now see if there was an active state and switch the setup to it */
2066 /* purge states of backend that are not available in this built */
2067 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2068 vector<std::string> backend_names;
2070 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2071 backend_names.push_back((*i)->name);
2073 for (StateList::iterator i = states.begin(); i != states.end();) {
2074 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2075 i = states.erase(i);
2081 states.sort (state_sort_cmp);
2083 /* purge old states referring to the same backend */
2084 const time_t now = time (NULL);
2085 for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2087 for (StateList::iterator i = states.begin(); i != states.end();) {
2088 if ((*i)->backend != *bi) {
2091 // keep at latest one for every audio-system
2096 // also keep states used in the last 90 days.
2097 if ((now - (*i)->lru) < 86400 * 90) {
2100 assert (!(*i)->active);
2101 i = states.erase(i);
2105 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2108 return set_current_state (*i);
2115 EngineControl::set_current_state (const State& state)
2117 DEBUG_ECONTROL ("set_current_state");
2119 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2121 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2122 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2123 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2124 // this shouldn't happen as the invalid backend names should have been
2125 // removed from the list of states.
2129 // now reflect the change in the backend in the GUI so backend_changed will
2130 // do the right thing
2131 backend_combo.set_active_text (state->backend);
2133 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2135 // we don't have control don't restore state
2140 if (!state->driver.empty ()) {
2141 if (!backend->requires_driver_selection ()) {
2142 DEBUG_ECONTROL ("Backend should require driver selection");
2143 // A backend has changed from having driver selection to not having
2144 // it or someone has been manually editing a config file and messed
2149 if (backend->set_driver (state->driver) != 0) {
2150 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2151 // Driver names for a backend have changed and the name in the
2152 // config file is now invalid or support for driver is no longer
2153 // included in the backend
2156 // no need to set the driver_combo as backend_changed will use
2157 // backend->driver_name to set the active driver
2160 if (!state->device.empty ()) {
2161 if (backend->set_device_name (state->device) != 0) {
2163 string_compose ("Unable to set device name %1", state->device));
2164 // device is no longer available on the system
2167 // no need to set active device as it will be picked up in
2168 // via backend_changed ()/set_device_popdown_strings
2171 // backend supports separate input/output devices
2172 if (backend->set_input_device_name (state->input_device) != 0) {
2173 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2174 state->input_device));
2175 // input device is no longer available on the system
2179 if (backend->set_output_device_name (state->output_device) != 0) {
2180 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2181 state->input_device));
2182 // output device is no longer available on the system
2185 // no need to set active devices as it will be picked up in via
2186 // backend_changed ()/set_*_device_popdown_strings
2191 // Now restore the state of the rest of the controls
2193 // We don't use a SignalBlocker as set_current_state is currently only
2194 // called from set_state before any signals are connected. If at some point
2195 // a more general named state mechanism is implemented and
2196 // set_current_state is called while signals are connected then a
2197 // SignalBlocker will need to be instantiated before setting these.
2199 device_combo.set_active_text (state->device);
2200 input_device_combo.set_active_text (state->input_device);
2201 output_device_combo.set_active_text (state->output_device);
2202 if (!_desired_sample_rate) {
2203 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2205 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2206 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2207 input_latency.set_value (state->input_latency);
2208 output_latency.set_value (state->output_latency);
2209 midi_option_combo.set_active_text (state->midi_option);
2210 use_buffered_io_button.set_active (state->use_buffered_io);
2215 EngineControl::push_state_to_backend (bool start)
2217 DEBUG_ECONTROL ("push_state_to_backend");
2218 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2219 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2225 /* figure out what is going to change */
2227 bool restart_required = false;
2228 bool was_running = ARDOUR::AudioEngine::instance()->running();
2229 bool change_driver = false;
2230 bool change_device = false;
2231 bool change_rate = false;
2232 bool change_bufsize = false;
2233 bool change_nperiods = false;
2234 bool change_latency = false;
2235 bool change_channels = false;
2236 bool change_midi = false;
2237 bool change_buffered_io = false;
2239 uint32_t ochan = get_output_channels ();
2240 uint32_t ichan = get_input_channels ();
2242 if (_have_control) {
2244 if (started_at_least_once) {
2246 /* we can control the backend */
2248 if (backend->requires_driver_selection()) {
2249 if (get_driver() != backend->driver_name()) {
2250 change_driver = true;
2254 if (backend->use_separate_input_and_output_devices()) {
2255 if (get_input_device_name() != backend->input_device_name()) {
2256 change_device = true;
2258 if (get_output_device_name() != backend->output_device_name()) {
2259 change_device = true;
2262 if (get_device_name() != backend->device_name()) {
2263 change_device = true;
2267 if (queue_device_changed) {
2268 change_device = true;
2271 if (get_rate() != backend->sample_rate()) {
2275 if (get_buffer_size() != backend->buffer_size()) {
2276 change_bufsize = true;
2279 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2280 && get_nperiods() != backend->period_size()) {
2281 change_nperiods = true;
2284 if (get_midi_option() != backend->midi_option()) {
2288 if (backend->can_use_buffered_io()) {
2289 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2290 change_buffered_io = true;
2294 /* zero-requested channels means "all available" */
2297 ichan = backend->input_channels();
2301 ochan = backend->output_channels();
2304 if (ichan != backend->input_channels()) {
2305 change_channels = true;
2308 if (ochan != backend->output_channels()) {
2309 change_channels = true;
2312 if (get_input_latency() != backend->systemic_input_latency() ||
2313 get_output_latency() != backend->systemic_output_latency()) {
2314 change_latency = true;
2317 /* backend never started, so we have to force a group
2320 change_device = true;
2321 if (backend->requires_driver_selection()) {
2322 change_driver = true;
2325 change_bufsize = true;
2326 change_channels = true;
2327 change_latency = true;
2329 change_buffered_io = backend->can_use_buffered_io();
2330 change_channels = true;
2331 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2336 /* we have no control over the backend, meaning that we can
2337 * only possibly change sample rate and buffer size.
2341 if (get_rate() != backend->sample_rate()) {
2342 change_bufsize = true;
2345 if (get_buffer_size() != backend->buffer_size()) {
2346 change_bufsize = true;
2350 queue_device_changed = false;
2352 if (!_have_control) {
2354 /* We do not have control over the backend, so the best we can
2355 * do is try to change the sample rate and/or bufsize and get
2359 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2363 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2368 backend->set_sample_rate (get_rate());
2371 if (change_bufsize) {
2372 backend->set_buffer_size (get_buffer_size());
2376 if (ARDOUR::AudioEngine::instance()->start ()) {
2377 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2387 /* determine if we need to stop the backend before changing parameters */
2389 if (change_driver || change_device || change_channels || change_nperiods ||
2390 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2391 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2392 change_midi || change_buffered_io ||
2393 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2394 restart_required = true;
2396 restart_required = false;
2401 if (restart_required) {
2402 if (ARDOUR::AudioEngine::instance()->stop()) {
2408 if (change_driver && backend->set_driver (get_driver())) {
2409 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2412 if (backend->use_separate_input_and_output_devices()) {
2413 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2414 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2417 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2418 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2422 if (change_device && backend->set_device_name (get_device_name())) {
2423 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2427 if (change_rate && backend->set_sample_rate (get_rate())) {
2428 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2431 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2432 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2435 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2436 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2440 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2441 if (backend->set_input_channels (get_input_channels())) {
2442 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2445 if (backend->set_output_channels (get_output_channels())) {
2446 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2450 if (change_latency) {
2451 if (backend->set_systemic_input_latency (get_input_latency())) {
2452 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2455 if (backend->set_systemic_output_latency (get_output_latency())) {
2456 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2462 backend->set_midi_option (get_midi_option());
2465 if (change_buffered_io) {
2466 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2470 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2471 if (_measure_midi) {
2472 if (*p == _measure_midi) {
2473 backend->set_midi_device_enabled ((*p)->name, true);
2475 backend->set_midi_device_enabled ((*p)->name, false);
2477 if (backend->can_change_systemic_latency_when_running ()) {
2478 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2479 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2483 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2484 if (backend->can_set_systemic_midi_latencies()) {
2485 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2486 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2491 if (start || (was_running && restart_required)) {
2492 if (ARDOUR::AudioEngine::instance()->start()) {
2503 EngineControl::post_push ()
2505 /* get a pointer to the current state object, creating one if
2509 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2512 state = save_state ();
2518 states.sort (state_sort_cmp);
2522 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2523 (*i)->active = false;
2526 /* mark this one active (to be used next time the dialog is
2530 state->active = true;
2532 if (_have_control) { // XXX
2533 manage_control_app_sensitivity ();
2536 /* schedule a redisplay of MIDI ports */
2537 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2542 EngineControl::get_rate () const
2544 float r = atof (sample_rate_combo.get_active_text ());
2545 /* the string may have been translated with an abbreviation for
2546 * thousands, so use a crude heuristic to fix this.
2556 EngineControl::get_buffer_size () const
2558 string txt = buffer_size_combo.get_active_text ();
2561 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2562 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2563 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2571 EngineControl::get_nperiods () const
2573 string txt = nperiods_combo.get_active_text ();
2574 return atoi (txt.c_str());
2578 EngineControl::get_midi_option () const
2580 return midi_option_combo.get_active_text();
2584 EngineControl::get_use_buffered_io () const
2586 return use_buffered_io_button.get_active();
2590 EngineControl::get_input_channels() const
2592 if (ARDOUR::Profile->get_mixbus()) {
2593 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2594 if (!backend) return 0;
2595 return backend->input_channels();
2597 return (uint32_t) input_channels_adjustment.get_value();
2601 EngineControl::get_output_channels() const
2603 if (ARDOUR::Profile->get_mixbus()) {
2604 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2605 if (!backend) return 0;
2606 return backend->input_channels();
2608 return (uint32_t) output_channels_adjustment.get_value();
2612 EngineControl::get_input_latency() const
2614 return (uint32_t) input_latency_adjustment.get_value();
2618 EngineControl::get_output_latency() const
2620 return (uint32_t) output_latency_adjustment.get_value();
2624 EngineControl::get_backend () const
2626 return backend_combo.get_active_text ();
2630 EngineControl::get_driver () const
2632 if (driver_combo.get_parent()) {
2633 return driver_combo.get_active_text ();
2640 EngineControl::get_device_name () const
2642 return device_combo.get_active_text ();
2646 EngineControl::get_input_device_name () const
2648 return input_device_combo.get_active_text ();
2652 EngineControl::get_output_device_name () const
2654 return output_device_combo.get_active_text ();
2658 EngineControl::control_app_button_clicked ()
2660 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2666 backend->launch_control_app ();
2670 EngineControl::start_stop_button_clicked ()
2672 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2678 if (ARDOUR::AudioEngine::instance()->running()) {
2679 ARDOUR::AudioEngine::instance()->stop ();
2681 if (!ARDOUR_UI::instance()->session_loaded) {
2687 if (!ARDOUR_UI::instance()->session_loaded) {
2688 ArdourDialog::on_response (RESPONSE_OK);
2694 EngineControl::update_devices_button_clicked ()
2696 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2702 if (backend->update_devices()) {
2703 device_list_changed ();
2708 EngineControl::use_buffered_io_button_clicked ()
2710 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2716 bool set_buffered_io = !use_buffered_io_button.get_active();
2717 use_buffered_io_button.set_active (set_buffered_io);
2718 backend->set_use_buffered_io (set_buffered_io);
2722 EngineControl::manage_control_app_sensitivity ()
2724 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2730 string appname = backend->control_app_name();
2732 if (appname.empty()) {
2733 control_app_button.set_sensitive (false);
2735 control_app_button.set_sensitive (true);
2740 EngineControl::set_desired_sample_rate (uint32_t sr)
2742 _desired_sample_rate = sr;
2743 if (ARDOUR::AudioEngine::instance ()->running ()
2744 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2751 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2753 if (page_num == 0) {
2754 _measure_midi.reset();
2755 update_sensitivity ();
2758 if (page_num == midi_tab) {
2760 refresh_midi_display ();
2763 if (page_num == latency_tab) {
2766 if (ARDOUR::AudioEngine::instance()->running()) {
2771 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2773 /* save any existing latency values */
2775 uint32_t il = (uint32_t) input_latency.get_value ();
2776 uint32_t ol = (uint32_t) input_latency.get_value ();
2778 /* reset to zero so that our new test instance
2779 will be clean of any existing latency measures.
2781 NB. this should really be done by the backend
2782 when stated for latency measurement.
2785 input_latency.set_value (0);
2786 output_latency.set_value (0);
2788 push_state_to_backend (false);
2792 input_latency.set_value (il);
2793 output_latency.set_value (ol);
2796 // This should be done in push_state_to_backend()
2797 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2798 disable_latency_tab ();
2801 enable_latency_tab ();
2805 end_latency_detection ();
2806 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2811 /* latency measurement */
2814 EngineControl::check_audio_latency_measurement ()
2816 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2818 if (mtdm->resolve () < 0) {
2819 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2823 if (mtdm->get_peak () > 0.707f) {
2824 // get_peak() resets the peak-hold in the detector.
2825 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2826 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2830 if (mtdm->err () > 0.3) {
2836 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2838 if (sample_rate == 0) {
2839 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2840 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2844 int frames_total = mtdm->del();
2845 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2847 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2848 _("Detected roundtrip latency: "),
2849 frames_total, frames_total * 1000.0f/sample_rate,
2850 _("Systemic latency: "),
2851 extra, extra * 1000.0f/sample_rate);
2855 if (mtdm->err () > 0.2) {
2857 strcat (buf, _("(signal detection error)"));
2863 strcat (buf, _("(inverted - bad wiring)"));
2867 lm_results.set_markup (string_compose (results_markup, buf));
2870 have_lm_results = true;
2871 end_latency_detection ();
2872 lm_use_button.set_sensitive (true);
2880 EngineControl::check_midi_latency_measurement ()
2882 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2884 if (!mididm->have_signal () || mididm->latency () == 0) {
2885 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2890 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2892 if (sample_rate == 0) {
2893 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2894 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2898 ARDOUR::framecnt_t frames_total = mididm->latency();
2899 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2900 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2901 _("Detected roundtrip latency: "),
2902 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2903 _("Systemic latency: "),
2904 extra, extra * 1000.0f / sample_rate);
2908 if (!mididm->ok ()) {
2910 strcat (buf, _("(averaging)"));
2914 if (mididm->deviation () > 50.0) {
2916 strcat (buf, _("(too large jitter)"));
2918 } else if (mididm->deviation () > 10.0) {
2920 strcat (buf, _("(large jitter)"));
2924 have_lm_results = true;
2925 end_latency_detection ();
2926 lm_use_button.set_sensitive (true);
2927 lm_results.set_markup (string_compose (results_markup, buf));
2929 } else if (mididm->processed () > 400) {
2930 have_lm_results = false;
2931 end_latency_detection ();
2932 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2936 lm_results.set_markup (string_compose (results_markup, buf));
2942 EngineControl::start_latency_detection ()
2944 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2945 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2947 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2948 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2949 if (_measure_midi) {
2950 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2952 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2954 lm_measure_label.set_text (_("Cancel"));
2955 have_lm_results = false;
2956 lm_use_button.set_sensitive (false);
2957 lm_input_channel_combo.set_sensitive (false);
2958 lm_output_channel_combo.set_sensitive (false);
2964 EngineControl::end_latency_detection ()
2966 latency_timeout.disconnect ();
2967 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2968 lm_measure_label.set_text (_("Measure"));
2969 if (!have_lm_results) {
2970 lm_use_button.set_sensitive (false);
2972 lm_input_channel_combo.set_sensitive (true);
2973 lm_output_channel_combo.set_sensitive (true);
2978 EngineControl::latency_button_clicked ()
2981 start_latency_detection ();
2983 end_latency_detection ();
2988 EngineControl::latency_back_button_clicked ()
2990 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2991 notebook.set_current_page(0);
2995 EngineControl::use_latency_button_clicked ()
2997 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2998 if (_measure_midi) {
2999 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3003 ARDOUR::framecnt_t frames_total = mididm->latency();
3004 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3005 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3006 _measure_midi->input_latency = one_way;
3007 _measure_midi->output_latency = one_way;
3008 if (backend->can_change_systemic_latency_when_running ()) {
3009 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3010 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3012 notebook.set_current_page (midi_tab);
3014 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3020 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3021 one_way = std::max (0., one_way);
3023 input_latency_adjustment.set_value (one_way);
3024 output_latency_adjustment.set_value (one_way);
3025 if (backend->can_change_systemic_latency_when_running ()) {
3026 backend->set_systemic_input_latency (one_way);
3027 backend->set_systemic_output_latency (one_way);
3030 /* back to settings page */
3031 notebook.set_current_page (0);
3036 EngineControl::on_delete_event (GdkEventAny* ev)
3038 if (notebook.get_current_page() == 2) {
3039 /* currently on latency tab - be sure to clean up */
3040 end_latency_detection ();
3042 return ArdourDialog::on_delete_event (ev);
3046 EngineControl::engine_running ()
3048 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3051 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3052 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3054 if (backend->can_set_period_size ()) {
3055 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3058 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3059 connect_disconnect_button.show();
3061 started_at_least_once = true;
3062 if (_have_control) {
3063 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3065 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3067 update_sensitivity();
3071 EngineControl::engine_stopped ()
3073 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3076 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3077 connect_disconnect_button.show();
3079 if (_have_control) {
3080 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3082 engine_status.set_markup(X_(""));
3085 update_sensitivity();
3089 EngineControl::device_list_changed ()
3091 if (ignore_device_changes) {
3094 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3096 midi_option_changed();
3100 EngineControl::connect_disconnect_click()
3102 if (ARDOUR::AudioEngine::instance()->running()) {
3105 if (!ARDOUR_UI::instance()->session_loaded) {
3111 if (!ARDOUR_UI::instance()->session_loaded) {
3112 ArdourDialog::on_response (RESPONSE_OK);
3118 EngineControl::calibrate_audio_latency ()
3120 _measure_midi.reset ();
3121 have_lm_results = false;
3122 lm_use_button.set_sensitive (false);
3123 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3124 notebook.set_current_page (latency_tab);
3128 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3131 have_lm_results = false;
3132 lm_use_button.set_sensitive (false);
3133 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3134 notebook.set_current_page (latency_tab);
3138 EngineControl::configure_midi_devices ()
3140 notebook.set_current_page (midi_tab);