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()->the_session () && !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()->the_session ()) {
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()));
1367 } else if (ARDOUR_UI::instance()->the_session ()) {
1368 float active_sr = ARDOUR_UI::instance()->the_session()->nominal_sample_rate ();
1370 if (std::find (sr.begin (), sr.end (), active_sr) == sr.end ()) {
1371 active_sr = sr.front ();
1374 sample_rate_combo.set_active_text (rate_as_string (active_sr));
1375 } else if (desired.empty ()) {
1376 float new_active_sr = backend->default_sample_rate ();
1378 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1379 new_active_sr = sr.front ();
1382 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1384 sample_rate_combo.set_active_text (desired);
1387 update_sensitivity ();
1391 EngineControl::get_buffer_sizes_for_all_devices ()
1393 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1394 ARDOUR::AudioEngine::instance ()->current_backend ();
1395 vector<uint32_t> all_sizes;
1397 if (backend->use_separate_input_and_output_devices ()) {
1398 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1400 all_sizes = backend->available_buffer_sizes (get_device_name ());
1406 EngineControl::get_default_buffer_sizes ()
1408 vector<uint32_t> sizes;
1409 sizes.push_back (8);
1410 sizes.push_back (16);
1411 sizes.push_back (32);
1412 sizes.push_back (64);
1413 sizes.push_back (128);
1414 sizes.push_back (256);
1415 sizes.push_back (512);
1416 sizes.push_back (1024);
1417 sizes.push_back (2048);
1418 sizes.push_back (4096);
1419 sizes.push_back (8192);
1424 EngineControl::set_buffersize_popdown_strings ()
1426 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1427 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1428 vector<uint32_t> bs;
1431 if (_have_control) {
1432 bs = get_buffer_sizes_for_all_devices ();
1433 } else if (backend->can_change_buffer_size_when_running()) {
1434 bs = get_default_buffer_sizes ();
1437 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1438 s.push_back (bufsize_as_string (*x));
1441 uint32_t previous_size = backend->buffer_size ();
1442 if (!buffer_size_combo.get_active_text().empty()) {
1443 previous_size = get_buffer_size ();
1446 set_popdown_strings (buffer_size_combo, s);
1450 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1451 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1454 buffer_size_combo.set_active_text(s.front());
1456 uint32_t period = backend->buffer_size();
1457 if (0 == period && backend->use_separate_input_and_output_devices()) {
1458 period = backend->default_buffer_size(get_input_device_name());
1460 if (0 == period && backend->use_separate_input_and_output_devices()) {
1461 period = backend->default_buffer_size(get_output_device_name());
1463 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1464 period = backend->default_buffer_size(get_device_name());
1467 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1469 show_buffer_duration ();
1471 update_sensitivity ();
1475 EngineControl::set_nperiods_popdown_strings ()
1477 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1478 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1479 vector<uint32_t> np;
1482 if (backend->can_set_period_size()) {
1483 np = backend->available_period_sizes (get_driver());
1486 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1487 s.push_back (to_string (*x));
1490 set_popdown_strings (nperiods_combo, s);
1493 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1496 update_sensitivity ();
1500 EngineControl::device_changed ()
1502 SignalBlocker blocker (*this, "device_changed");
1503 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1506 string device_name_in;
1507 string device_name_out; // only used if backend support separate I/O devices
1509 if (backend->use_separate_input_and_output_devices()) {
1510 device_name_in = get_input_device_name ();
1511 device_name_out = get_output_device_name ();
1513 device_name_in = get_device_name ();
1516 /* we set the backend-device to query various device related intormation.
1517 * This has the side effect that backend->device_name() will match
1518 * the device_name and 'change_device' will never be true.
1519 * so work around this by setting...
1521 if (backend->use_separate_input_and_output_devices()) {
1522 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1523 queue_device_changed = true;
1526 if (device_name_in != backend->device_name()) {
1527 queue_device_changed = true;
1531 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1532 if (backend->use_separate_input_and_output_devices()) {
1533 backend->set_input_device_name (device_name_in);
1534 backend->set_output_device_name (device_name_out);
1536 backend->set_device_name(device_name_in);
1540 /* don't allow programmatic change to combos to cause a
1541 recursive call to this method.
1543 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1545 set_samplerate_popdown_strings ();
1546 set_buffersize_popdown_strings ();
1547 set_nperiods_popdown_strings ();
1549 /* TODO set min + max channel counts here */
1551 manage_control_app_sensitivity ();
1554 /* pick up any saved state for this device */
1556 if (!ignore_changes) {
1557 maybe_display_saved_state ();
1562 EngineControl::input_device_changed ()
1564 DEBUG_ECONTROL ("input_device_changed");
1566 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1567 if (backend && backend->match_input_output_devices_or_none ()) {
1568 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1570 if (get_output_device_name () != dev_none
1571 && get_input_device_name () != dev_none
1572 && get_input_device_name () != get_output_device_name ()) {
1573 block_changed_signals ();
1574 if (contains_value (output_device_combo, get_input_device_name ())) {
1575 output_device_combo.set_active_text (get_input_device_name ());
1577 assert (contains_value (output_device_combo, dev_none));
1578 output_device_combo.set_active_text (dev_none);
1580 unblock_changed_signals ();
1587 EngineControl::output_device_changed ()
1589 DEBUG_ECONTROL ("output_device_changed");
1590 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1591 if (backend && backend->match_input_output_devices_or_none ()) {
1592 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1594 if (get_input_device_name () != dev_none
1595 && get_input_device_name () != dev_none
1596 && get_input_device_name () != get_output_device_name ()) {
1597 block_changed_signals ();
1598 if (contains_value (input_device_combo, get_output_device_name ())) {
1599 input_device_combo.set_active_text (get_output_device_name ());
1601 assert (contains_value (input_device_combo, dev_none));
1602 input_device_combo.set_active_text (dev_none);
1604 unblock_changed_signals ();
1611 EngineControl::bufsize_as_string (uint32_t sz)
1613 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1617 EngineControl::sample_rate_changed ()
1619 DEBUG_ECONTROL ("sample_rate_changed");
1620 /* reset the strings for buffer size to show the correct msec value
1621 (reflecting the new sample rate).
1624 show_buffer_duration ();
1629 EngineControl::buffer_size_changed ()
1631 DEBUG_ECONTROL ("buffer_size_changed");
1632 if (ARDOUR::AudioEngine::instance()->running()) {
1633 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1634 if (backend && backend->can_change_buffer_size_when_running ()) {
1635 backend->set_buffer_size (get_buffer_size());
1638 show_buffer_duration ();
1642 EngineControl::nperiods_changed ()
1644 DEBUG_ECONTROL ("nperiods_changed");
1645 show_buffer_duration ();
1649 EngineControl::show_buffer_duration ()
1651 DEBUG_ECONTROL ("show_buffer_duration");
1652 /* buffer sizes - convert from just samples to samples + msecs for
1653 * the displayed string
1656 string bs_text = buffer_size_combo.get_active_text ();
1657 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1658 uint32_t rate = get_rate();
1660 /* Except for ALSA and Dummy backends, we don't know the number of periods
1661 * per cycle and settings.
1663 * jack1 vs jack2 have different default latencies since jack2 start
1664 * in async-mode unless --sync is given which adds an extra cycle
1665 * of latency. The value is not known if jackd is started externally..
1667 * So just display the period size, that's also what
1668 * ARDOUR_UI::update_sample_rate() does for the status bar.
1669 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1670 * but still, that's the buffer period, not [round-trip] latency)
1673 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1674 buffer_size_duration_label.set_text (buf);
1678 EngineControl::midi_option_changed ()
1680 DEBUG_ECONTROL ("midi_option_changed");
1681 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1684 backend->set_midi_option (get_midi_option());
1686 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1688 //_midi_devices.clear(); // TODO merge with state-saved settings..
1689 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1690 std::vector<MidiDeviceSettings> new_devices;
1692 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1693 MidiDeviceSettings mds = find_midi_device (i->name);
1694 if (i->available && !mds) {
1695 uint32_t input_latency = 0;
1696 uint32_t output_latency = 0;
1697 if (_can_set_midi_latencies) {
1698 input_latency = backend->systemic_midi_input_latency (i->name);
1699 output_latency = backend->systemic_midi_output_latency (i->name);
1701 bool enabled = backend->midi_device_enabled (i->name);
1702 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1703 new_devices.push_back (ptr);
1704 } else if (i->available) {
1705 new_devices.push_back (mds);
1708 _midi_devices = new_devices;
1710 if (_midi_devices.empty()) {
1711 midi_devices_button.hide ();
1713 midi_devices_button.show ();
1718 EngineControl::parameter_changed ()
1722 EngineControl::State
1723 EngineControl::get_matching_state (const string& backend)
1725 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1726 if ((*i)->backend == backend) {
1733 EngineControl::State
1734 EngineControl::get_matching_state (
1735 const string& backend,
1736 const string& driver,
1737 const string& device)
1739 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1740 if ((*i)->backend == backend &&
1741 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1749 EngineControl::State
1750 EngineControl::get_matching_state (
1751 const string& backend,
1752 const string& driver,
1753 const string& input_device,
1754 const string& output_device)
1756 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1757 if ((*i)->backend == backend &&
1758 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1766 EngineControl::State
1767 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1769 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1772 if (backend->use_separate_input_and_output_devices ()) {
1773 return get_matching_state (backend_combo.get_active_text(),
1774 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1775 input_device_combo.get_active_text(),
1776 output_device_combo.get_active_text());
1778 return get_matching_state (backend_combo.get_active_text(),
1779 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1780 device_combo.get_active_text());
1784 return get_matching_state (backend_combo.get_active_text(),
1786 device_combo.get_active_text());
1789 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1790 const EngineControl::State& state2)
1792 if (state1->backend == state2->backend &&
1793 state1->driver == state2->driver &&
1794 state1->device == state2->device &&
1795 state1->input_device == state2->input_device &&
1796 state1->output_device == state2->output_device) {
1802 // sort active first, then most recently used to the beginning of the list
1804 EngineControl::state_sort_cmp (const State &a, const State &b) {
1808 else if (b->active) {
1812 return a->lru > b->lru;
1816 EngineControl::State
1817 EngineControl::save_state ()
1821 if (!_have_control) {
1822 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1824 state->lru = time (NULL) ;
1827 state.reset(new StateStruct);
1828 state->backend = get_backend ();
1830 state.reset(new StateStruct);
1831 store_state (state);
1834 for (StateList::iterator i = states.begin(); i != states.end();) {
1835 if (equivalent_states (*i, state)) {
1836 i = states.erase(i);
1842 states.push_back (state);
1844 states.sort (state_sort_cmp);
1850 EngineControl::store_state (State state)
1852 state->backend = get_backend ();
1853 state->driver = get_driver ();
1854 state->device = get_device_name ();
1855 state->input_device = get_input_device_name ();
1856 state->output_device = get_output_device_name ();
1857 state->sample_rate = get_rate ();
1858 state->buffer_size = get_buffer_size ();
1859 state->n_periods = get_nperiods ();
1860 state->input_latency = get_input_latency ();
1861 state->output_latency = get_output_latency ();
1862 state->input_channels = get_input_channels ();
1863 state->output_channels = get_output_channels ();
1864 state->midi_option = get_midi_option ();
1865 state->midi_devices = _midi_devices;
1866 state->use_buffered_io = get_use_buffered_io ();
1867 state->lru = time (NULL) ;
1871 EngineControl::maybe_display_saved_state ()
1873 if (!_have_control || ARDOUR::AudioEngine::instance()->running ()) {
1877 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1880 DEBUG_ECONTROL ("Restoring saved state");
1881 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1883 if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
1884 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1886 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1888 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1889 /* call this explicitly because we're ignoring changes to
1890 the controls at this point.
1892 show_buffer_duration ();
1893 input_latency.set_value (state->input_latency);
1894 output_latency.set_value (state->output_latency);
1896 use_buffered_io_button.set_active (state->use_buffered_io);
1898 if (!state->midi_option.empty()) {
1899 midi_option_combo.set_active_text (state->midi_option);
1900 _midi_devices = state->midi_devices;
1903 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1908 EngineControl::get_state ()
1912 XMLNode* root = new XMLNode ("AudioMIDISetup");
1915 if (!states.empty()) {
1916 XMLNode* state_nodes = new XMLNode ("EngineStates");
1918 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1920 XMLNode* node = new XMLNode ("State");
1922 node->set_property ("backend", (*i)->backend);
1923 node->set_property ("driver", (*i)->driver);
1924 node->set_property ("device", (*i)->device);
1925 node->set_property ("input-device", (*i)->input_device);
1926 node->set_property ("output-device", (*i)->output_device);
1927 node->set_property ("sample-rate", (*i)->sample_rate);
1928 node->set_property ("buffer-size", (*i)->buffer_size);
1929 node->set_property ("n-periods", (*i)->n_periods);
1930 node->set_property ("input-latency", (*i)->input_latency);
1931 node->set_property ("output-latency", (*i)->output_latency);
1932 node->set_property ("input-channels", (*i)->input_channels);
1933 node->set_property ("output-channels", (*i)->output_channels);
1934 node->set_property ("active", (*i)->active);
1935 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1936 node->set_property ("midi-option", (*i)->midi_option);
1937 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1938 node->set_property ("lru", lru_val );
1940 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1941 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1942 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1943 midi_device_stuff->set_property (X_("name"), (*p)->name);
1944 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1945 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1946 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1947 midi_devices->add_child_nocopy (*midi_device_stuff);
1949 node->add_child_nocopy (*midi_devices);
1951 state_nodes->add_child_nocopy (*node);
1954 root->add_child_nocopy (*state_nodes);
1961 EngineControl::set_default_state ()
1963 vector<string> backend_names;
1964 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1966 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1967 backend_names.push_back ((*b)->name);
1969 backend_combo.set_active_text (backend_names.front());
1971 // We could set default backends per platform etc here
1977 EngineControl::set_state (const XMLNode& root)
1979 XMLNodeList clist, cclist;
1980 XMLNodeConstIterator citer, cciter;
1981 XMLNode const * child;
1982 XMLNode const * grandchild;
1984 if (root.name() != "AudioMIDISetup") {
1988 clist = root.children();
1992 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1996 if (child->name() != "EngineStates") {
2000 cclist = child->children();
2002 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2003 State state (new StateStruct);
2005 grandchild = *cciter;
2007 if (grandchild->name() != "State") {
2011 if (!grandchild->get_property ("backend", state->backend)) {
2015 // If any of the required properties are not found in the state node
2016 // then continue/skip to the next engine state
2017 if (!grandchild->get_property ("driver", state->driver) ||
2018 !grandchild->get_property ("device", state->device) ||
2019 !grandchild->get_property ("input-device", state->input_device) ||
2020 !grandchild->get_property ("output-device", state->output_device) ||
2021 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2022 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2023 !grandchild->get_property ("input-latency", state->input_latency) ||
2024 !grandchild->get_property ("output-latency", state->output_latency) ||
2025 !grandchild->get_property ("input-channels", state->input_channels) ||
2026 !grandchild->get_property ("output-channels", state->output_channels) ||
2027 !grandchild->get_property ("active", state->active) ||
2028 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2029 !grandchild->get_property ("midi-option", state->midi_option)) {
2033 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2034 // optional (new value in 4.5)
2035 state->n_periods = 0;
2038 state->midi_devices.clear();
2040 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2041 const XMLNodeList mnc = midinode->children();
2042 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2045 uint32_t input_latency;
2046 uint32_t output_latency;
2048 if (!(*n)->get_property (X_("name"), name) ||
2049 !(*n)->get_property (X_("enabled"), enabled) ||
2050 !(*n)->get_property (X_("input-latency"), input_latency) ||
2051 !(*n)->get_property (X_("output-latency"), output_latency)) {
2055 MidiDeviceSettings ptr (
2056 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2057 state->midi_devices.push_back (ptr);
2062 if (grandchild->get_property ("lru", lru_val)) {
2063 state->lru = lru_val;
2066 states.push_back (state);
2070 /* now see if there was an active state and switch the setup to it */
2072 /* purge states of backend that are not available in this built */
2073 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2074 vector<std::string> backend_names;
2076 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2077 backend_names.push_back((*i)->name);
2079 for (StateList::iterator i = states.begin(); i != states.end();) {
2080 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2081 i = states.erase(i);
2087 states.sort (state_sort_cmp);
2089 /* purge old states referring to the same backend */
2090 const time_t now = time (NULL);
2091 for (vector<std::string>::const_iterator bi = backend_names.begin(); bi != backend_names.end(); ++bi) {
2093 for (StateList::iterator i = states.begin(); i != states.end();) {
2094 if ((*i)->backend != *bi) {
2097 // keep at latest one for every audio-system
2102 // also keep states used in the last 90 days.
2103 if ((now - (*i)->lru) < 86400 * 90) {
2106 assert (!(*i)->active);
2107 i = states.erase(i);
2111 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2114 return set_current_state (*i);
2121 EngineControl::set_current_state (const State& state)
2123 DEBUG_ECONTROL ("set_current_state");
2125 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2127 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2128 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2129 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2130 // this shouldn't happen as the invalid backend names should have been
2131 // removed from the list of states.
2135 // now reflect the change in the backend in the GUI so backend_changed will
2136 // do the right thing
2137 backend_combo.set_active_text (state->backend);
2139 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2141 // we don't have control don't restore state
2146 if (!state->driver.empty ()) {
2147 if (!backend->requires_driver_selection ()) {
2148 DEBUG_ECONTROL ("Backend should require driver selection");
2149 // A backend has changed from having driver selection to not having
2150 // it or someone has been manually editing a config file and messed
2155 if (backend->set_driver (state->driver) != 0) {
2156 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2157 // Driver names for a backend have changed and the name in the
2158 // config file is now invalid or support for driver is no longer
2159 // included in the backend
2162 // no need to set the driver_combo as backend_changed will use
2163 // backend->driver_name to set the active driver
2166 if (!state->device.empty ()) {
2167 if (backend->set_device_name (state->device) != 0) {
2169 string_compose ("Unable to set device name %1", state->device));
2170 // device is no longer available on the system
2173 // no need to set active device as it will be picked up in
2174 // via backend_changed ()/set_device_popdown_strings
2177 // backend supports separate input/output devices
2178 if (backend->set_input_device_name (state->input_device) != 0) {
2179 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2180 state->input_device));
2181 // input device is no longer available on the system
2185 if (backend->set_output_device_name (state->output_device) != 0) {
2186 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2187 state->input_device));
2188 // output device is no longer available on the system
2191 // no need to set active devices as it will be picked up in via
2192 // backend_changed ()/set_*_device_popdown_strings
2197 // Now restore the state of the rest of the controls
2199 // We don't use a SignalBlocker as set_current_state is currently only
2200 // called from set_state before any signals are connected. If at some point
2201 // a more general named state mechanism is implemented and
2202 // set_current_state is called while signals are connected then a
2203 // SignalBlocker will need to be instantiated before setting these.
2205 device_combo.set_active_text (state->device);
2206 input_device_combo.set_active_text (state->input_device);
2207 output_device_combo.set_active_text (state->output_device);
2208 if (0 == _desired_sample_rate && sample_rate_combo.get_sensitive ()) {
2209 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2211 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2212 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2213 input_latency.set_value (state->input_latency);
2214 output_latency.set_value (state->output_latency);
2215 midi_option_combo.set_active_text (state->midi_option);
2216 use_buffered_io_button.set_active (state->use_buffered_io);
2221 EngineControl::push_state_to_backend (bool start)
2223 DEBUG_ECONTROL ("push_state_to_backend");
2224 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2225 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2231 /* figure out what is going to change */
2233 bool restart_required = false;
2234 bool was_running = ARDOUR::AudioEngine::instance()->running();
2235 bool change_driver = false;
2236 bool change_device = false;
2237 bool change_rate = false;
2238 bool change_bufsize = false;
2239 bool change_nperiods = false;
2240 bool change_latency = false;
2241 bool change_channels = false;
2242 bool change_midi = false;
2243 bool change_buffered_io = false;
2245 uint32_t ochan = get_output_channels ();
2246 uint32_t ichan = get_input_channels ();
2248 if (_have_control) {
2250 if (started_at_least_once) {
2252 /* we can control the backend */
2254 if (backend->requires_driver_selection()) {
2255 if (get_driver() != backend->driver_name()) {
2256 change_driver = true;
2260 if (backend->use_separate_input_and_output_devices()) {
2261 if (get_input_device_name() != backend->input_device_name()) {
2262 change_device = true;
2264 if (get_output_device_name() != backend->output_device_name()) {
2265 change_device = true;
2268 if (get_device_name() != backend->device_name()) {
2269 change_device = true;
2273 if (queue_device_changed) {
2274 change_device = true;
2277 if (get_rate() != backend->sample_rate()) {
2281 if (get_buffer_size() != backend->buffer_size()) {
2282 change_bufsize = true;
2285 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2286 && get_nperiods() != backend->period_size()) {
2287 change_nperiods = true;
2290 if (get_midi_option() != backend->midi_option()) {
2294 if (backend->can_use_buffered_io()) {
2295 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2296 change_buffered_io = true;
2300 /* zero-requested channels means "all available" */
2303 ichan = backend->input_channels();
2307 ochan = backend->output_channels();
2310 if (ichan != backend->input_channels()) {
2311 change_channels = true;
2314 if (ochan != backend->output_channels()) {
2315 change_channels = true;
2318 if (get_input_latency() != backend->systemic_input_latency() ||
2319 get_output_latency() != backend->systemic_output_latency()) {
2320 change_latency = true;
2323 /* backend never started, so we have to force a group
2326 change_device = true;
2327 if (backend->requires_driver_selection()) {
2328 change_driver = true;
2331 change_bufsize = true;
2332 change_channels = true;
2333 change_latency = true;
2335 change_buffered_io = backend->can_use_buffered_io();
2336 change_channels = true;
2337 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2342 /* we have no control over the backend, meaning that we can
2343 * only possibly change sample rate and buffer size.
2347 if (get_rate() != backend->sample_rate()) {
2348 change_bufsize = true;
2351 if (get_buffer_size() != backend->buffer_size()) {
2352 change_bufsize = true;
2356 queue_device_changed = false;
2358 if (!_have_control) {
2360 /* We do not have control over the backend, so the best we can
2361 * do is try to change the sample rate and/or bufsize and get
2365 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2369 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2374 backend->set_sample_rate (get_rate());
2377 if (change_bufsize) {
2378 backend->set_buffer_size (get_buffer_size());
2382 if (ARDOUR::AudioEngine::instance()->start ()) {
2383 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2393 /* determine if we need to stop the backend before changing parameters */
2395 if (change_driver || change_device || change_channels || change_nperiods ||
2396 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2397 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2398 change_midi || change_buffered_io ||
2399 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2400 restart_required = true;
2402 restart_required = false;
2407 if (restart_required) {
2408 if (ARDOUR::AudioEngine::instance()->stop()) {
2414 if (change_driver && backend->set_driver (get_driver())) {
2415 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2418 if (backend->use_separate_input_and_output_devices()) {
2419 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2420 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2423 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2424 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2428 if (change_device && backend->set_device_name (get_device_name())) {
2429 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2433 if (change_rate && backend->set_sample_rate (get_rate())) {
2434 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2437 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2438 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2441 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2442 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2446 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2447 if (backend->set_input_channels (get_input_channels())) {
2448 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2451 if (backend->set_output_channels (get_output_channels())) {
2452 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2456 if (change_latency) {
2457 if (backend->set_systemic_input_latency (get_input_latency())) {
2458 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2461 if (backend->set_systemic_output_latency (get_output_latency())) {
2462 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2468 backend->set_midi_option (get_midi_option());
2471 if (change_buffered_io) {
2472 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2476 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2477 if (_measure_midi) {
2478 if (*p == _measure_midi) {
2479 backend->set_midi_device_enabled ((*p)->name, true);
2481 backend->set_midi_device_enabled ((*p)->name, false);
2483 if (backend->can_change_systemic_latency_when_running ()) {
2484 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2485 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2489 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2490 if (backend->can_set_systemic_midi_latencies()) {
2491 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2492 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2497 if (start || (was_running && restart_required)) {
2498 if (ARDOUR::AudioEngine::instance()->start()) {
2509 EngineControl::post_push ()
2511 /* get a pointer to the current state object, creating one if
2515 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2518 state = save_state ();
2524 states.sort (state_sort_cmp);
2528 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2529 (*i)->active = false;
2532 /* mark this one active (to be used next time the dialog is
2536 state->active = true;
2538 if (_have_control) { // XXX
2539 manage_control_app_sensitivity ();
2542 /* schedule a redisplay of MIDI ports */
2543 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2548 EngineControl::get_rate () const
2550 float r = atof (sample_rate_combo.get_active_text ());
2551 /* the string may have been translated with an abbreviation for
2552 * thousands, so use a crude heuristic to fix this.
2562 EngineControl::get_buffer_size () const
2564 string txt = buffer_size_combo.get_active_text ();
2567 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2568 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2569 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2577 EngineControl::get_nperiods () const
2579 string txt = nperiods_combo.get_active_text ();
2580 return atoi (txt.c_str());
2584 EngineControl::get_midi_option () const
2586 return midi_option_combo.get_active_text();
2590 EngineControl::get_use_buffered_io () const
2592 return use_buffered_io_button.get_active();
2596 EngineControl::get_input_channels() const
2598 if (ARDOUR::Profile->get_mixbus()) {
2599 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2600 if (!backend) return 0;
2601 return backend->input_channels();
2603 return (uint32_t) input_channels_adjustment.get_value();
2607 EngineControl::get_output_channels() const
2609 if (ARDOUR::Profile->get_mixbus()) {
2610 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2611 if (!backend) return 0;
2612 return backend->input_channels();
2614 return (uint32_t) output_channels_adjustment.get_value();
2618 EngineControl::get_input_latency() const
2620 return (uint32_t) input_latency_adjustment.get_value();
2624 EngineControl::get_output_latency() const
2626 return (uint32_t) output_latency_adjustment.get_value();
2630 EngineControl::get_backend () const
2632 return backend_combo.get_active_text ();
2636 EngineControl::get_driver () const
2638 if (driver_combo.get_parent()) {
2639 return driver_combo.get_active_text ();
2646 EngineControl::get_device_name () const
2648 return device_combo.get_active_text ();
2652 EngineControl::get_input_device_name () const
2654 return input_device_combo.get_active_text ();
2658 EngineControl::get_output_device_name () const
2660 return output_device_combo.get_active_text ();
2664 EngineControl::control_app_button_clicked ()
2666 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2672 backend->launch_control_app ();
2676 EngineControl::start_stop_button_clicked ()
2678 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2684 if (ARDOUR::AudioEngine::instance()->running()) {
2685 ARDOUR::AudioEngine::instance()->stop ();
2687 if (!ARDOUR_UI::instance()->the_session ()) {
2693 if (!ARDOUR_UI::instance()->the_session ()) {
2694 ArdourDialog::on_response (RESPONSE_OK);
2700 EngineControl::update_devices_button_clicked ()
2702 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2708 if (backend->update_devices()) {
2709 device_list_changed ();
2714 EngineControl::use_buffered_io_button_clicked ()
2716 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2722 bool set_buffered_io = !use_buffered_io_button.get_active();
2723 use_buffered_io_button.set_active (set_buffered_io);
2724 backend->set_use_buffered_io (set_buffered_io);
2728 EngineControl::manage_control_app_sensitivity ()
2730 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2736 string appname = backend->control_app_name();
2738 if (appname.empty()) {
2739 control_app_button.set_sensitive (false);
2741 control_app_button.set_sensitive (true);
2746 EngineControl::set_desired_sample_rate (uint32_t sr)
2748 _desired_sample_rate = sr;
2749 if (ARDOUR::AudioEngine::instance ()->running ()
2750 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2757 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2759 if (page_num == 0) {
2760 _measure_midi.reset();
2761 update_sensitivity ();
2764 if (page_num == midi_tab) {
2766 refresh_midi_display ();
2769 if (page_num == latency_tab) {
2772 if (ARDOUR::AudioEngine::instance()->running()) {
2777 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2779 /* save any existing latency values */
2781 uint32_t il = (uint32_t) input_latency.get_value ();
2782 uint32_t ol = (uint32_t) input_latency.get_value ();
2784 /* reset to zero so that our new test instance
2785 will be clean of any existing latency measures.
2787 NB. this should really be done by the backend
2788 when stated for latency measurement.
2791 input_latency.set_value (0);
2792 output_latency.set_value (0);
2794 push_state_to_backend (false);
2798 input_latency.set_value (il);
2799 output_latency.set_value (ol);
2802 // This should be done in push_state_to_backend()
2803 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2804 disable_latency_tab ();
2807 enable_latency_tab ();
2811 end_latency_detection ();
2812 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2817 /* latency measurement */
2820 EngineControl::check_audio_latency_measurement ()
2822 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2824 if (mtdm->resolve () < 0) {
2825 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2829 if (mtdm->get_peak () > 0.707f) {
2830 // get_peak() resets the peak-hold in the detector.
2831 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2832 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2836 if (mtdm->err () > 0.3) {
2842 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2844 if (sample_rate == 0) {
2845 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2846 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2850 int samples_total = mtdm->del();
2851 int extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2853 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2854 _("Detected roundtrip latency: "),
2855 samples_total, samples_total * 1000.0f/sample_rate,
2856 _("Systemic latency: "),
2857 extra, extra * 1000.0f/sample_rate);
2861 if (mtdm->err () > 0.2) {
2863 strcat (buf, _("(signal detection error)"));
2869 strcat (buf, _("(inverted - bad wiring)"));
2873 lm_results.set_markup (string_compose (results_markup, buf));
2876 have_lm_results = true;
2877 end_latency_detection ();
2878 lm_use_button.set_sensitive (true);
2886 EngineControl::check_midi_latency_measurement ()
2888 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2890 if (!mididm->have_signal () || mididm->latency () == 0) {
2891 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2896 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2898 if (sample_rate == 0) {
2899 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2900 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2904 ARDOUR::samplecnt_t samples_total = mididm->latency();
2905 ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2906 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2907 _("Detected roundtrip latency: "),
2908 samples_total, samples_total * 1000.0f / sample_rate, mididm->deviation (),
2909 _("Systemic latency: "),
2910 extra, extra * 1000.0f / sample_rate);
2914 if (!mididm->ok ()) {
2916 strcat (buf, _("(averaging)"));
2920 if (mididm->deviation () > 50.0) {
2922 strcat (buf, _("(too large jitter)"));
2924 } else if (mididm->deviation () > 10.0) {
2926 strcat (buf, _("(large jitter)"));
2930 have_lm_results = true;
2931 end_latency_detection ();
2932 lm_use_button.set_sensitive (true);
2933 lm_results.set_markup (string_compose (results_markup, buf));
2935 } else if (mididm->processed () > 400) {
2936 have_lm_results = false;
2937 end_latency_detection ();
2938 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2942 lm_results.set_markup (string_compose (results_markup, buf));
2948 EngineControl::start_latency_detection ()
2950 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2951 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2953 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2954 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2955 if (_measure_midi) {
2956 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2958 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2960 lm_measure_label.set_text (_("Cancel"));
2961 have_lm_results = false;
2962 lm_use_button.set_sensitive (false);
2963 lm_input_channel_combo.set_sensitive (false);
2964 lm_output_channel_combo.set_sensitive (false);
2970 EngineControl::end_latency_detection ()
2972 latency_timeout.disconnect ();
2973 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2974 lm_measure_label.set_text (_("Measure"));
2975 if (!have_lm_results) {
2976 lm_use_button.set_sensitive (false);
2978 lm_input_channel_combo.set_sensitive (true);
2979 lm_output_channel_combo.set_sensitive (true);
2984 EngineControl::latency_button_clicked ()
2987 start_latency_detection ();
2989 end_latency_detection ();
2994 EngineControl::latency_back_button_clicked ()
2996 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2997 notebook.set_current_page(0);
3001 EngineControl::use_latency_button_clicked ()
3003 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3004 if (_measure_midi) {
3005 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3009 ARDOUR::samplecnt_t samples_total = mididm->latency();
3010 ARDOUR::samplecnt_t extra = samples_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3011 uint32_t one_way = max ((ARDOUR::samplecnt_t) 0, extra / 2);
3012 _measure_midi->input_latency = one_way;
3013 _measure_midi->output_latency = one_way;
3014 if (backend->can_change_systemic_latency_when_running ()) {
3015 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3016 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3018 notebook.set_current_page (midi_tab);
3020 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3026 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3027 one_way = std::max (0., one_way);
3029 input_latency_adjustment.set_value (one_way);
3030 output_latency_adjustment.set_value (one_way);
3031 if (backend->can_change_systemic_latency_when_running ()) {
3032 backend->set_systemic_input_latency (one_way);
3033 backend->set_systemic_output_latency (one_way);
3036 /* back to settings page */
3037 notebook.set_current_page (0);
3042 EngineControl::on_delete_event (GdkEventAny* ev)
3044 if (notebook.get_current_page() == 2) {
3045 /* currently on latency tab - be sure to clean up */
3046 end_latency_detection ();
3048 return ArdourDialog::on_delete_event (ev);
3052 EngineControl::engine_running ()
3054 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3057 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3058 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3060 if (backend->can_set_period_size ()) {
3061 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3064 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3065 connect_disconnect_button.show();
3067 started_at_least_once = true;
3068 if (_have_control) {
3069 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3071 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3073 update_sensitivity();
3077 EngineControl::engine_stopped ()
3079 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3082 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3083 connect_disconnect_button.show();
3085 if (_have_control) {
3086 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3088 engine_status.set_markup(X_(""));
3091 update_sensitivity();
3095 EngineControl::device_list_changed ()
3097 if (ignore_device_changes) {
3100 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3102 midi_option_changed();
3106 EngineControl::connect_disconnect_click()
3108 if (ARDOUR::AudioEngine::instance()->running()) {
3111 if (!ARDOUR_UI::instance()->the_session ()) {
3117 if (!ARDOUR_UI::instance()->the_session ()) {
3118 ArdourDialog::on_response (RESPONSE_OK);
3124 EngineControl::calibrate_audio_latency ()
3126 _measure_midi.reset ();
3127 have_lm_results = false;
3128 lm_use_button.set_sensitive (false);
3129 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3130 notebook.set_current_page (latency_tab);
3134 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3137 have_lm_results = false;
3138 lm_use_button.set_sensitive (false);
3139 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3140 notebook.set_current_page (latency_tab);
3144 EngineControl::configure_midi_devices ()
3146 notebook.set_current_page (midi_tab);