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/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
91 , lm_measure_label (_("Measure"))
92 , lm_use_button (_("Use results"))
93 , lm_back_button (_("Back to settings ... (ignore results)"))
94 , lm_button_audio (_("Calibrate Audio"))
96 , have_lm_results (false)
98 , midi_back_button (_("Back to settings"))
100 , ignore_device_changes (0)
101 , _desired_sample_rate (0)
102 , started_at_least_once (false)
103 , queue_device_changed (false)
104 , _have_control (true)
107 using namespace Notebook_Helpers;
108 vector<string> backend_names;
110 AttachOptions xopt = AttachOptions (FILL|EXPAND);
113 set_name (X_("AudioMIDISetup"));
115 /* the backend combo is the one thing that is ALWAYS visible */
117 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
119 if (backends.empty()) {
120 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));
122 throw failed_constructor ();
125 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
126 backend_names.push_back ((*b)->name);
129 set_popdown_strings (backend_combo, backend_names);
131 /* setup basic packing characteristics for the table used on the main
132 * tab of the notebook
135 basic_packer.set_spacings (6);
136 basic_packer.set_border_width (12);
137 basic_packer.set_homogeneous (false);
141 basic_hbox.pack_start (basic_packer, false, false);
143 /* latency measurement tab */
145 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
148 lm_table.set_row_spacings (12);
149 lm_table.set_col_spacings (6);
150 lm_table.set_homogeneous (false);
152 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
155 lm_preamble.set_width_chars (60);
156 lm_preamble.set_line_wrap (true);
157 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
159 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162 Gtk::Label* preamble;
163 preamble = manage (new Label);
164 preamble->set_width_chars (60);
165 preamble->set_line_wrap (true);
166 preamble->set_markup (_("Select two channels below and connect them using a cable."));
168 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
171 label = manage (new Label (_("Output channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_output_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
179 label = manage (new Label (_("Input channel")));
180 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
182 misc_align = manage (new Alignment (0.0, 0.5));
183 misc_align->add (lm_input_channel_combo);
184 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
187 lm_measure_label.set_padding (10, 10);
188 lm_measure_button.add (lm_measure_label);
189 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
190 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
191 lm_back_button_signal = lm_back_button.signal_clicked().connect(
192 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
194 lm_use_button.set_sensitive (false);
196 /* Increase the default spacing around the labels of these three
202 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
203 l->set_padding (10, 10);
206 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
207 l->set_padding (10, 10);
210 preamble = manage (new Label);
211 preamble->set_width_chars (60);
212 preamble->set_line_wrap (true);
213 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
214 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 preamble = manage (new Label);
218 preamble->set_width_chars (60);
219 preamble->set_line_wrap (true);
220 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
221 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 ++row; // skip a row in the table
224 ++row; // skip a row in the table
226 lm_table.attach (lm_results, 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_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
237 lm_vbox.set_border_width (12);
238 lm_vbox.pack_start (lm_table, false, false);
240 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
242 midi_vbox.set_border_width (12);
243 midi_vbox.set_spacing (6);
244 midi_vbox.pack_start (midi_input_view);
245 midi_vbox.pack_start (midi_output_view);
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);
285 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
286 update_devices_button.set_sensitive (false);
287 update_devices_button.set_name ("generic button");
288 update_devices_button.set_can_focus(true);
290 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
291 use_buffered_io_button.set_sensitive (false);
292 use_buffered_io_button.set_name ("generic button");
293 use_buffered_io_button.set_can_focus(true);
295 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
296 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
298 /* Pick up any existing audio setup configuration, if appropriate */
300 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
302 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
303 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
304 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
305 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
308 if (!set_state (*audio_setup)) {
309 set_default_state ();
312 set_default_state ();
315 update_sensitivity ();
316 connect_changed_signals ();
318 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
320 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
322 connect_disconnect_button.set_no_show_all();
323 use_buffered_io_button.set_no_show_all();
324 update_devices_button.set_no_show_all();
325 start_stop_button.set_no_show_all();
326 midi_devices_button.set_no_show_all();
330 EngineControl::connect_changed_signals ()
332 backend_combo_connection = backend_combo.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::backend_changed));
334 driver_combo_connection = driver_combo.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::driver_changed));
336 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
338 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
340 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
342 device_combo_connection = device_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::device_changed));
344 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
347 input_device_combo_connection = input_device_combo.signal_changed ().connect (
348 sigc::mem_fun (*this, &EngineControl::input_device_changed));
349 output_device_combo_connection = output_device_combo.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::output_device_changed));
352 input_latency_connection = input_latency.signal_changed ().connect (
353 sigc::mem_fun (*this, &EngineControl::parameter_changed));
354 output_latency_connection = output_latency.signal_changed ().connect (
355 sigc::mem_fun (*this, &EngineControl::parameter_changed));
356 input_channels_connection = input_channels.signal_changed ().connect (
357 sigc::mem_fun (*this, &EngineControl::parameter_changed));
358 output_channels_connection = output_channels.signal_changed ().connect (
359 sigc::mem_fun (*this, &EngineControl::parameter_changed));
363 EngineControl::block_changed_signals ()
365 if (block_signals++ == 0) {
366 DEBUG_ECONTROL ("Blocking changed signals");
367 backend_combo_connection.block ();
368 driver_combo_connection.block ();
369 sample_rate_combo_connection.block ();
370 buffer_size_combo_connection.block ();
371 nperiods_combo_connection.block ();
372 device_combo_connection.block ();
373 input_device_combo_connection.block ();
374 output_device_combo_connection.block ();
375 midi_option_combo_connection.block ();
376 input_latency_connection.block ();
377 output_latency_connection.block ();
378 input_channels_connection.block ();
379 output_channels_connection.block ();
384 EngineControl::unblock_changed_signals ()
386 if (--block_signals == 0) {
387 DEBUG_ECONTROL ("Unblocking changed signals");
388 backend_combo_connection.unblock ();
389 driver_combo_connection.unblock ();
390 sample_rate_combo_connection.unblock ();
391 buffer_size_combo_connection.unblock ();
392 nperiods_combo_connection.unblock ();
393 device_combo_connection.unblock ();
394 input_device_combo_connection.unblock ();
395 output_device_combo_connection.unblock ();
396 midi_option_combo_connection.unblock ();
397 input_latency_connection.unblock ();
398 output_latency_connection.unblock ();
399 input_channels_connection.unblock ();
400 output_channels_connection.unblock ();
404 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
405 const std::string& reason)
406 : ec (engine_control)
409 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
410 ec.block_changed_signals ();
413 EngineControl::SignalBlocker::~SignalBlocker ()
415 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
416 ec.unblock_changed_signals ();
420 EngineControl::on_show ()
422 ArdourDialog::on_show ();
423 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
424 // re-check _have_control (jackd running) see #6041
428 ok_button->grab_focus();
432 EngineControl::try_autostart ()
434 if (!start_stop_button.get_sensitive()) {
437 if (ARDOUR::AudioEngine::instance()->running()) {
440 return start_engine ();
444 EngineControl::start_engine ()
446 if (push_state_to_backend(true) != 0) {
447 MessageDialog msg(*this,
448 ARDOUR::AudioEngine::instance()->get_last_backend_error());
456 EngineControl::stop_engine (bool for_latency)
458 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
459 MessageDialog msg(*this,
460 ARDOUR::AudioEngine::instance()->get_last_backend_error());
468 EngineControl::on_response (int response_id)
470 ArdourDialog::on_response (response_id);
472 switch (response_id) {
474 if (!start_engine()) {
479 #ifdef PLATFORM_WINDOWS
481 // But if there's no session open, this can produce
482 // a long gap when nothing appears to be happening.
483 // Let's show the splash image while we're waiting.
484 if (!ARDOUR_COMMAND_LINE::no_splash) {
485 if (ARDOUR_UI::instance()) {
486 if (!ARDOUR_UI::instance()->session_loaded) {
487 ARDOUR_UI::instance()->show_splash();
493 case RESPONSE_DELETE_EVENT: {
495 ev.type = GDK_BUTTON_PRESS;
497 on_delete_event((GdkEventAny*)&ev);
500 case RESPONSE_CANCEL:
501 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
502 ARDOUR_UI::instance()->check_audioengine(*this);
511 EngineControl::build_notebook ()
514 AttachOptions xopt = AttachOptions (FILL|EXPAND);
516 /* clear the table */
518 Gtkmm2ext::container_clear (basic_vbox);
519 Gtkmm2ext::container_clear (basic_packer);
521 if (control_app_button.get_parent()) {
522 control_app_button.get_parent()->remove (control_app_button);
525 label = manage (left_aligned_label (_("Audio System:")));
526 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
527 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
529 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
530 engine_status.show();
532 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
533 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
534 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
536 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
537 lm_button_audio.set_name ("generic button");
538 lm_button_audio.set_can_focus(true);
541 build_full_control_notebook ();
543 build_no_control_notebook ();
546 basic_vbox.pack_start (basic_hbox, false, false);
549 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
550 basic_vbox.show_all ();
555 EngineControl::build_full_control_notebook ()
557 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
560 using namespace Notebook_Helpers;
562 vector<string> strings;
563 AttachOptions xopt = AttachOptions (FILL|EXPAND);
564 int row = 1; // row zero == backend combo
566 /* start packing it up */
568 if (backend->requires_driver_selection()) {
569 label = manage (left_aligned_label (_("Driver:")));
570 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
571 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
575 if (backend->use_separate_input_and_output_devices()) {
576 label = manage (left_aligned_label (_("Input Device:")));
577 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
578 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
580 label = manage (left_aligned_label (_("Output Device:")));
581 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
582 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
584 // reset so it isn't used in state comparisons
585 device_combo.set_active_text ("");
587 label = manage (left_aligned_label (_("Device:")));
588 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
589 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
591 // reset these so they don't get used in state comparisons
592 input_device_combo.set_active_text ("");
593 output_device_combo.set_active_text ("");
596 label = manage (left_aligned_label (_("Sample rate:")));
597 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
598 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
602 label = manage (left_aligned_label (_("Buffer size:")));
603 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
604 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
605 buffer_size_duration_label.set_alignment (0.0); /* left-align */
606 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
608 int ctrl_btn_span = 1;
609 if (backend->can_set_period_size ()) {
611 label = manage (left_aligned_label (_("Periods:")));
612 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
613 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
617 /* button spans 2 or 3 rows */
619 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
622 input_channels.set_name ("InputChannels");
623 input_channels.set_flags (Gtk::CAN_FOCUS);
624 input_channels.set_digits (0);
625 input_channels.set_wrap (false);
626 output_channels.set_editable (true);
628 if (!ARDOUR::Profile->get_mixbus()) {
629 label = manage (left_aligned_label (_("Input Channels:")));
630 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
631 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
635 output_channels.set_name ("OutputChannels");
636 output_channels.set_flags (Gtk::CAN_FOCUS);
637 output_channels.set_digits (0);
638 output_channels.set_wrap (false);
639 output_channels.set_editable (true);
641 if (!ARDOUR::Profile->get_mixbus()) {
642 label = manage (left_aligned_label (_("Output Channels:")));
643 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
644 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
648 input_latency.set_name ("InputLatency");
649 input_latency.set_flags (Gtk::CAN_FOCUS);
650 input_latency.set_digits (0);
651 input_latency.set_wrap (false);
652 input_latency.set_editable (true);
654 label = manage (left_aligned_label (_("Hardware input latency:")));
655 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
656 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
657 label = manage (left_aligned_label (_("samples")));
658 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
661 output_latency.set_name ("OutputLatency");
662 output_latency.set_flags (Gtk::CAN_FOCUS);
663 output_latency.set_digits (0);
664 output_latency.set_wrap (false);
665 output_latency.set_editable (true);
667 label = manage (left_aligned_label (_("Hardware output latency:")));
668 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
669 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
670 label = manage (left_aligned_label (_("samples")));
671 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
673 /* button spans 2 rows */
675 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
678 label = manage (left_aligned_label (_("MIDI System:")));
679 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
680 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
681 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
686 EngineControl::build_no_control_notebook ()
688 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
691 using namespace Notebook_Helpers;
693 vector<string> strings;
694 AttachOptions xopt = AttachOptions (FILL|EXPAND);
695 int row = 1; // row zero == backend combo
696 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
698 label = manage (new Label);
699 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
700 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
703 if (backend->can_change_sample_rate_when_running()) {
704 label = manage (left_aligned_label (_("Sample rate:")));
705 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
706 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
710 if (backend->can_change_buffer_size_when_running()) {
711 label = manage (left_aligned_label (_("Buffer size:")));
712 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
713 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
714 buffer_size_duration_label.set_alignment (0.0); /* left-align */
715 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
719 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
723 EngineControl::~EngineControl ()
725 ignore_changes = true;
729 EngineControl::disable_latency_tab ()
731 vector<string> empty;
732 set_popdown_strings (lm_output_channel_combo, empty);
733 set_popdown_strings (lm_input_channel_combo, empty);
734 lm_measure_button.set_sensitive (false);
735 lm_use_button.set_sensitive (false);
739 EngineControl::enable_latency_tab ()
741 vector<string> outputs;
742 vector<string> inputs;
744 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
745 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
746 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
748 if (!ARDOUR::AudioEngine::instance()->running()) {
749 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
750 notebook.set_current_page (0);
754 else if (inputs.empty() || outputs.empty()) {
755 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
756 notebook.set_current_page (0);
761 lm_back_button_signal.disconnect();
763 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
766 lm_back_button_signal = lm_back_button.signal_clicked().connect(
767 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
771 set_popdown_strings (lm_output_channel_combo, outputs);
772 lm_output_channel_combo.set_active_text (outputs.front());
773 lm_output_channel_combo.set_sensitive (true);
775 set_popdown_strings (lm_input_channel_combo, inputs);
776 lm_input_channel_combo.set_active_text (inputs.front());
777 lm_input_channel_combo.set_sensitive (true);
779 lm_measure_button.set_sensitive (true);
783 EngineControl::setup_midi_tab_for_backend ()
788 EngineControl::refill_midi_ports (bool for_input)
790 using namespace ARDOUR;
792 std::vector<string> ports;
794 AudioEngine::instance()->get_ports (string(), DataType::MIDI, for_input ? IsInput : IsOutput, ports);
796 Glib::RefPtr<ListStore> model = Gtk::ListStore::create (midi_port_columns);
798 for (vector<string>::const_iterator s = ports.begin(); s != ports.end(); ++s) {
800 if (AudioEngine::instance()->port_is_mine (*s)) {
804 TreeModel::Row row = *(model->append());
806 string pretty = AudioEngine::instance()->get_pretty_name_by_name (*s);
807 cerr << "pretty for " << *s << " = " << pretty << endl;
808 row[midi_port_columns.name] = *s;
809 row[midi_port_columns.pretty_name] = (pretty.empty() ? *s : pretty);
810 row[midi_port_columns.in_use] = true;
811 row[midi_port_columns.music_data] = true;
812 row[midi_port_columns.control_data] = true;
815 Gtk::TreeView& view (for_input ? midi_input_view : midi_output_view);
816 int pretty_name_column;
817 view.set_model (model);
818 view.append_column (_("Name"), midi_port_columns.name);
819 pretty_name_column = view.append_column (_("Pretty Name"), midi_port_columns.pretty_name) - 1;
820 view.append_column (_("Use"), midi_port_columns.in_use);
821 view.append_column (_("Music Data"), midi_port_columns.music_data);
822 view.append_column (_("Control Data"), midi_port_columns.control_data);
824 CellRendererText* pretty_name_cell = dynamic_cast<CellRendererText*> (view.get_column_cell_renderer (pretty_name_column));
825 pretty_name_cell->property_editable() = true;
826 pretty_name_cell->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::pretty_name_edit), &view));
830 EngineControl::pretty_name_edit (std::string const & path, string const & new_text, Gtk::TreeView* view)
832 TreeIter iter = view->get_model()->get_iter (path);
838 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
840 ARDOUR::PortEngine::PortHandle ph = backend->get_port_by_name ((*iter)[midi_port_columns.name]);
842 backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", new_text, "");
843 (*iter)[midi_port_columns.pretty_name] = new_text;
849 EngineControl::update_sensitivity ()
851 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
853 ok_button->set_sensitive (false);
854 start_stop_button.set_sensitive (false);
859 size_t devices_available = 0;
861 if (backend->use_separate_input_and_output_devices ()) {
862 devices_available += get_popdown_string_count (input_device_combo);
863 devices_available += get_popdown_string_count (output_device_combo);
865 devices_available += get_popdown_string_count (device_combo);
868 if (devices_available == 0) {
870 input_latency.set_sensitive (false);
871 output_latency.set_sensitive (false);
872 input_channels.set_sensitive (false);
873 output_channels.set_sensitive (false);
875 input_latency.set_sensitive (true);
876 output_latency.set_sensitive (true);
877 input_channels.set_sensitive (true);
878 output_channels.set_sensitive (true);
881 if (get_popdown_string_count (buffer_size_combo) > 0) {
882 if (!ARDOUR::AudioEngine::instance()->running()) {
883 buffer_size_combo.set_sensitive (valid);
884 } else if (backend->can_change_sample_rate_when_running()) {
885 buffer_size_combo.set_sensitive (valid || !_have_control);
889 * Currently there is no way to manually stop the
890 * engine in order to re-configure it.
891 * This needs to remain sensitive for now.
893 * (it's also handy to implicily
894 * re-start the engine)
896 buffer_size_combo.set_sensitive (true);
898 buffer_size_combo.set_sensitive (false);
902 buffer_size_combo.set_sensitive (false);
906 if (get_popdown_string_count (sample_rate_combo) > 0) {
907 bool allow_to_set_rate = false;
908 if (!ARDOUR::AudioEngine::instance()->running()) {
909 if (!ARDOUR_UI::instance()->session_loaded) {
910 // engine is not running, no session loaded -> anything goes.
911 allow_to_set_rate = true;
912 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
913 // only allow to change if the current setting is not the native session rate.
914 allow_to_set_rate = true;
917 sample_rate_combo.set_sensitive (allow_to_set_rate);
919 sample_rate_combo.set_sensitive (false);
923 if (get_popdown_string_count (nperiods_combo) > 0) {
924 if (!ARDOUR::AudioEngine::instance()->running()) {
925 nperiods_combo.set_sensitive (true);
927 nperiods_combo.set_sensitive (false);
930 nperiods_combo.set_sensitive (false);
934 start_stop_button.set_sensitive(true);
935 start_stop_button.show();
936 if (ARDOUR::AudioEngine::instance()->running()) {
937 start_stop_button.set_text("Stop");
938 update_devices_button.set_sensitive(false);
939 use_buffered_io_button.set_sensitive(false);
941 if (backend->can_request_update_devices()) {
942 update_devices_button.show();
944 update_devices_button.hide();
946 if (backend->can_use_buffered_io()) {
947 use_buffered_io_button.show();
949 use_buffered_io_button.hide();
951 start_stop_button.set_text("Start");
952 update_devices_button.set_sensitive(true);
953 use_buffered_io_button.set_sensitive(true);
956 update_devices_button.set_sensitive(false);
957 update_devices_button.hide();
958 use_buffered_io_button.set_sensitive(false);
959 use_buffered_io_button.hide();
960 start_stop_button.set_sensitive(false);
961 start_stop_button.hide();
964 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
965 input_device_combo.set_sensitive (false);
966 output_device_combo.set_sensitive (false);
967 device_combo.set_sensitive (false);
968 driver_combo.set_sensitive (false);
970 input_device_combo.set_sensitive (true);
971 output_device_combo.set_sensitive (true);
972 device_combo.set_sensitive (true);
973 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
974 driver_combo.set_sensitive (true);
976 driver_combo.set_sensitive (false);
980 if (valid || !_have_control) {
981 ok_button->set_sensitive (true);
983 ok_button->set_sensitive (false);
988 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
990 device->input_latency = a->get_value();
992 device->output_latency = a->get_value();
997 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
998 b->set_active (!b->get_active());
999 device->enabled = b->get_active();
1000 refresh_midi_display(device->name);
1004 EngineControl::refresh_midi_display (std::string focus)
1006 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1010 AttachOptions xopt = AttachOptions (FILL|EXPAND);
1013 Gtkmm2ext::container_clear (midi_device_table);
1015 midi_device_table.set_spacings (6);
1017 l = manage (new Label);
1018 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
1019 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
1020 l->set_alignment (0.5, 0.5);
1024 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
1025 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
1026 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
1027 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
1029 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
1030 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
1031 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
1032 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
1035 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1040 bool enabled = (*p)->enabled;
1042 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
1043 m->set_name ("midi device");
1044 m->set_can_focus (Gtk::CAN_FOCUS);
1045 m->add_events (Gdk::BUTTON_RELEASE_MASK);
1046 m->set_active (enabled);
1047 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
1048 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
1049 if ((*p)->name == focus) {
1053 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1054 s = manage (new Gtk::SpinButton (*a));
1055 a->set_value ((*p)->input_latency);
1056 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1057 s->set_sensitive (_can_set_midi_latencies && enabled);
1058 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1060 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1061 s = manage (new Gtk::SpinButton (*a));
1062 a->set_value ((*p)->output_latency);
1063 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1064 s->set_sensitive (_can_set_midi_latencies && enabled);
1065 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1067 b = manage (new Button (_("Calibrate")));
1068 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1069 b->set_sensitive (_can_set_midi_latencies && enabled);
1070 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1077 EngineControl::backend_changed ()
1080 SignalBlocker blocker (*this, "backend_changed");
1081 string backend_name = backend_combo.get_active_text();
1082 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1084 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1085 /* eh? setting the backend failed... how ? */
1086 /* A: stale config contains a backend that does not exist in current build */
1090 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1092 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1096 setup_midi_tab_for_backend ();
1097 _midi_devices.clear();
1099 if (backend->requires_driver_selection()) {
1100 if (set_driver_popdown_strings ()) {
1104 /* this will change the device text which will cause a call to
1105 * device changed which will set up parameters
1110 update_midi_options ();
1112 connect_disconnect_button.hide();
1114 midi_option_changed();
1116 started_at_least_once = false;
1118 /* changing the backend implies stopping the engine
1119 * ARDOUR::AudioEngine() may or may not emit this signal
1120 * depending on previous engine state
1122 engine_stopped (); // set "active/inactive"
1124 if (!_have_control) {
1125 // set settings from backend that we do have control over
1126 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1129 if (_have_control && !ignore_changes) {
1130 // set driver & devices
1131 State state = get_matching_state (backend_combo.get_active_text());
1133 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1134 set_current_state (state);
1138 if (!ignore_changes) {
1139 maybe_display_saved_state ();
1144 EngineControl::update_midi_options ()
1146 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1147 vector<string> midi_options = backend->enumerate_midi_options();
1149 if (midi_options.size() == 1) {
1150 /* only contains the "none" option */
1151 midi_option_combo.set_sensitive (false);
1153 if (_have_control) {
1154 set_popdown_strings (midi_option_combo, midi_options);
1155 midi_option_combo.set_active_text (midi_options.front());
1156 midi_option_combo.set_sensitive (true);
1158 midi_option_combo.set_sensitive (false);
1164 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1166 if (ARDOUR::Profile->get_mixbus()) {
1170 uint32_t cnt = (uint32_t) sb->get_value();
1172 sb->set_text (_("all available channels"));
1175 snprintf (buf, sizeof (buf), "%d", cnt);
1181 // @return true if there are drivers available
1183 EngineControl::set_driver_popdown_strings ()
1185 DEBUG_ECONTROL ("set_driver_popdown_strings");
1186 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1187 vector<string> drivers = backend->enumerate_drivers();
1189 if (drivers.empty ()) {
1190 // This is an error...?
1194 string current_driver = backend->driver_name ();
1196 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1198 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1201 current_driver = drivers.front ();
1204 set_popdown_strings (driver_combo, drivers);
1206 string_compose ("driver_combo.set_active_text: %1", current_driver));
1207 driver_combo.set_active_text (current_driver);
1212 EngineControl::get_default_device(const string& current_device_name,
1213 const vector<string>& available_devices)
1215 // If the current device is available, use it as default
1216 if (std::find (available_devices.begin (),
1217 available_devices.end (),
1218 current_device_name) != available_devices.end ()) {
1220 return current_device_name;
1223 using namespace ARDOUR;
1225 string default_device_name =
1226 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1228 vector<string>::const_iterator i;
1230 // If there is a "Default" device available, use it
1231 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1232 if (*i == default_device_name) {
1237 string none_device_name =
1238 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1240 // Use the first device that isn't "None"
1241 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1242 if (*i != none_device_name) {
1247 // Use "None" if there are no other available
1248 return available_devices.front();
1251 // @return true if there are devices available
1253 EngineControl::set_device_popdown_strings ()
1255 DEBUG_ECONTROL ("set_device_popdown_strings");
1256 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1257 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1259 /* NOTE: Ardour currently does not display the "available" field of the
1262 * Doing so would require a different GUI widget than the combo
1263 * box/popdown that we currently use, since it has no way to list
1264 * items that are not selectable. Something more like a popup menu,
1265 * which could have unselectable items, would be appropriate.
1268 vector<string> available_devices;
1270 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1271 available_devices.push_back (i->name);
1274 if (available_devices.empty ()) {
1278 set_popdown_strings (device_combo, available_devices);
1280 std::string default_device =
1281 get_default_device(backend->device_name(), available_devices);
1284 string_compose ("set device_combo active text: %1", default_device));
1286 device_combo.set_active_text(default_device);
1290 // @return true if there are input devices available
1292 EngineControl::set_input_device_popdown_strings ()
1294 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1295 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1296 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1298 vector<string> available_devices;
1300 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1301 available_devices.push_back (i->name);
1304 if (available_devices.empty()) {
1308 set_popdown_strings (input_device_combo, available_devices);
1310 std::string default_device =
1311 get_default_device(backend->input_device_name(), available_devices);
1314 string_compose ("set input_device_combo active text: %1", default_device));
1315 input_device_combo.set_active_text(default_device);
1319 // @return true if there are output devices available
1321 EngineControl::set_output_device_popdown_strings ()
1323 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1324 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1325 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1327 vector<string> available_devices;
1329 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1330 available_devices.push_back (i->name);
1333 if (available_devices.empty()) {
1337 set_popdown_strings (output_device_combo, available_devices);
1339 std::string default_device =
1340 get_default_device(backend->output_device_name(), available_devices);
1343 string_compose ("set output_device_combo active text: %1", default_device));
1344 output_device_combo.set_active_text(default_device);
1349 EngineControl::list_devices ()
1351 DEBUG_ECONTROL ("list_devices");
1352 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1355 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1357 bool devices_available = false;
1359 if (backend->use_separate_input_and_output_devices ()) {
1360 bool input_devices_available = set_input_device_popdown_strings ();
1361 bool output_devices_available = set_output_device_popdown_strings ();
1362 devices_available = input_devices_available || output_devices_available;
1364 devices_available = set_device_popdown_strings ();
1367 if (devices_available) {
1370 device_combo.clear();
1371 input_device_combo.clear();
1372 output_device_combo.clear();
1374 update_sensitivity ();
1378 EngineControl::driver_changed ()
1380 SignalBlocker blocker (*this, "driver_changed");
1381 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1384 backend->set_driver (driver_combo.get_active_text());
1387 // TODO load LRU device(s) for backend + driver combo
1389 if (!ignore_changes) {
1390 maybe_display_saved_state ();
1395 EngineControl::get_sample_rates_for_all_devices ()
1397 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1398 ARDOUR::AudioEngine::instance ()->current_backend ();
1399 vector<float> all_rates;
1401 if (backend->use_separate_input_and_output_devices ()) {
1402 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1404 all_rates = backend->available_sample_rates (get_device_name ());
1410 EngineControl::get_default_sample_rates ()
1412 vector<float> rates;
1413 rates.push_back (8000.0f);
1414 rates.push_back (16000.0f);
1415 rates.push_back (32000.0f);
1416 rates.push_back (44100.0f);
1417 rates.push_back (48000.0f);
1418 rates.push_back (88200.0f);
1419 rates.push_back (96000.0f);
1420 rates.push_back (192000.0f);
1421 rates.push_back (384000.0f);
1426 EngineControl::set_samplerate_popdown_strings ()
1428 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1429 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1434 if (_have_control) {
1435 sr = get_sample_rates_for_all_devices ();
1437 sr = get_default_sample_rates ();
1440 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1441 s.push_back (rate_as_string (*x));
1442 if (*x == _desired_sample_rate) {
1447 set_popdown_strings (sample_rate_combo, s);
1450 if (ARDOUR::AudioEngine::instance()->running()) {
1451 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1453 else if (desired.empty ()) {
1454 float new_active_sr = backend->default_sample_rate ();
1456 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1457 new_active_sr = sr.front ();
1460 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1462 sample_rate_combo.set_active_text (desired);
1466 update_sensitivity ();
1470 EngineControl::get_buffer_sizes_for_all_devices ()
1472 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1473 ARDOUR::AudioEngine::instance ()->current_backend ();
1474 vector<uint32_t> all_sizes;
1476 if (backend->use_separate_input_and_output_devices ()) {
1477 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1479 all_sizes = backend->available_buffer_sizes (get_device_name ());
1485 EngineControl::get_default_buffer_sizes ()
1487 vector<uint32_t> sizes;
1488 sizes.push_back (8);
1489 sizes.push_back (16);
1490 sizes.push_back (32);
1491 sizes.push_back (64);
1492 sizes.push_back (128);
1493 sizes.push_back (256);
1494 sizes.push_back (512);
1495 sizes.push_back (1024);
1496 sizes.push_back (2048);
1497 sizes.push_back (4096);
1498 sizes.push_back (8192);
1503 EngineControl::set_buffersize_popdown_strings ()
1505 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1506 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1507 vector<uint32_t> bs;
1510 if (_have_control) {
1511 bs = get_buffer_sizes_for_all_devices ();
1512 } else if (backend->can_change_buffer_size_when_running()) {
1513 bs = get_default_buffer_sizes ();
1516 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1517 s.push_back (bufsize_as_string (*x));
1520 uint32_t previous_size = 0;
1521 if (!buffer_size_combo.get_active_text().empty()) {
1522 previous_size = get_buffer_size ();
1525 set_popdown_strings (buffer_size_combo, s);
1529 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1530 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1533 buffer_size_combo.set_active_text(s.front());
1535 uint32_t period = backend->buffer_size();
1536 if (0 == period && backend->use_separate_input_and_output_devices()) {
1537 period = backend->default_buffer_size(get_input_device_name());
1539 if (0 == period && backend->use_separate_input_and_output_devices()) {
1540 period = backend->default_buffer_size(get_output_device_name());
1542 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1543 period = backend->default_buffer_size(get_device_name());
1546 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1548 show_buffer_duration ();
1550 update_sensitivity ();
1554 EngineControl::set_nperiods_popdown_strings ()
1556 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1557 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1558 vector<uint32_t> np;
1561 if (backend->can_set_period_size()) {
1562 np = backend->available_period_sizes (get_driver());
1565 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1566 s.push_back (nperiods_as_string (*x));
1569 set_popdown_strings (nperiods_combo, s);
1572 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1575 update_sensitivity ();
1579 EngineControl::device_changed ()
1581 SignalBlocker blocker (*this, "device_changed");
1582 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1585 string device_name_in;
1586 string device_name_out; // only used if backend support separate I/O devices
1588 if (backend->use_separate_input_and_output_devices()) {
1589 device_name_in = get_input_device_name ();
1590 device_name_out = get_output_device_name ();
1592 device_name_in = get_device_name ();
1595 /* we set the backend-device to query various device related intormation.
1596 * This has the side effect that backend->device_name() will match
1597 * the device_name and 'change_device' will never be true.
1598 * so work around this by setting...
1600 if (backend->use_separate_input_and_output_devices()) {
1601 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1602 queue_device_changed = true;
1605 if (device_name_in != backend->device_name()) {
1606 queue_device_changed = true;
1610 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1611 if (backend->use_separate_input_and_output_devices()) {
1612 backend->set_input_device_name (device_name_in);
1613 backend->set_output_device_name (device_name_out);
1615 backend->set_device_name(device_name_in);
1619 /* don't allow programmatic change to combos to cause a
1620 recursive call to this method.
1622 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1624 set_samplerate_popdown_strings ();
1625 set_buffersize_popdown_strings ();
1626 set_nperiods_popdown_strings ();
1628 /* TODO set min + max channel counts here */
1630 manage_control_app_sensitivity ();
1633 /* pick up any saved state for this device */
1635 if (!ignore_changes) {
1636 maybe_display_saved_state ();
1641 EngineControl::input_device_changed ()
1643 DEBUG_ECONTROL ("input_device_changed");
1648 EngineControl::output_device_changed ()
1650 DEBUG_ECONTROL ("output_device_changed");
1655 EngineControl::bufsize_as_string (uint32_t sz)
1657 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1661 EngineControl::nperiods_as_string (uint32_t np)
1664 snprintf (buf, sizeof (buf), "%u", np);
1670 EngineControl::sample_rate_changed ()
1672 DEBUG_ECONTROL ("sample_rate_changed");
1673 /* reset the strings for buffer size to show the correct msec value
1674 (reflecting the new sample rate).
1677 show_buffer_duration ();
1682 EngineControl::buffer_size_changed ()
1684 DEBUG_ECONTROL ("buffer_size_changed");
1685 show_buffer_duration ();
1689 EngineControl::nperiods_changed ()
1691 DEBUG_ECONTROL ("nperiods_changed");
1692 show_buffer_duration ();
1696 EngineControl::show_buffer_duration ()
1698 DEBUG_ECONTROL ("show_buffer_duration");
1699 /* buffer sizes - convert from just samples to samples + msecs for
1700 * the displayed string
1703 string bs_text = buffer_size_combo.get_active_text ();
1704 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1705 uint32_t rate = get_rate();
1707 /* Except for ALSA and Dummy backends, we don't know the number of periods
1708 * per cycle and settings.
1710 * jack1 vs jack2 have different default latencies since jack2 start
1711 * in async-mode unless --sync is given which adds an extra cycle
1712 * of latency. The value is not known if jackd is started externally..
1714 * So just display the period size, that's also what
1715 * ARDOUR_UI::update_sample_rate() does for the status bar.
1716 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1717 * but still, that's the buffer period, not [round-trip] latency)
1720 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1721 buffer_size_duration_label.set_text (buf);
1725 EngineControl::midi_option_changed ()
1727 DEBUG_ECONTROL ("midi_option_changed");
1728 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1731 backend->set_midi_option (get_midi_option());
1733 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1735 //_midi_devices.clear(); // TODO merge with state-saved settings..
1736 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1737 std::vector<MidiDeviceSettings> new_devices;
1739 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1740 MidiDeviceSettings mds = find_midi_device (i->name);
1741 if (i->available && !mds) {
1742 uint32_t input_latency = 0;
1743 uint32_t output_latency = 0;
1744 if (_can_set_midi_latencies) {
1745 input_latency = backend->systemic_midi_input_latency (i->name);
1746 output_latency = backend->systemic_midi_output_latency (i->name);
1748 bool enabled = backend->midi_device_enabled (i->name);
1749 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1750 new_devices.push_back (ptr);
1751 } else if (i->available) {
1752 new_devices.push_back (mds);
1755 _midi_devices = new_devices;
1757 if (_midi_devices.empty()) {
1758 midi_devices_button.hide ();
1760 midi_devices_button.show ();
1765 EngineControl::parameter_changed ()
1769 EngineControl::State
1770 EngineControl::get_matching_state (const string& backend)
1772 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1773 if ((*i)->backend == backend) {
1780 EngineControl::State
1781 EngineControl::get_matching_state (
1782 const string& backend,
1783 const string& driver,
1784 const string& device)
1786 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1787 if ((*i)->backend == backend &&
1788 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1796 EngineControl::State
1797 EngineControl::get_matching_state (
1798 const string& backend,
1799 const string& driver,
1800 const string& input_device,
1801 const string& output_device)
1803 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1804 if ((*i)->backend == backend &&
1805 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1813 EngineControl::State
1814 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1816 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1819 if (backend->use_separate_input_and_output_devices ()) {
1820 return get_matching_state (backend_combo.get_active_text(),
1821 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1822 input_device_combo.get_active_text(),
1823 output_device_combo.get_active_text());
1825 return get_matching_state (backend_combo.get_active_text(),
1826 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1827 device_combo.get_active_text());
1831 return get_matching_state (backend_combo.get_active_text(),
1833 device_combo.get_active_text());
1836 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1837 const EngineControl::State& state2)
1839 if (state1->backend == state2->backend &&
1840 state1->driver == state2->driver &&
1841 state1->device == state2->device &&
1842 state1->input_device == state2->input_device &&
1843 state1->output_device == state2->output_device) {
1850 EngineControl::state_sort_cmp (const State &a, const State &b) {
1854 else if (b->active) {
1858 return a->lru < b->lru;
1862 EngineControl::State
1863 EngineControl::save_state ()
1867 if (!_have_control) {
1868 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1870 state->lru = time (NULL) ;
1873 state.reset(new StateStruct);
1874 state->backend = get_backend ();
1876 state.reset(new StateStruct);
1877 store_state (state);
1880 for (StateList::iterator i = states.begin(); i != states.end();) {
1881 if (equivalent_states (*i, state)) {
1882 i = states.erase(i);
1888 states.push_back (state);
1890 states.sort (state_sort_cmp);
1896 EngineControl::store_state (State state)
1898 state->backend = get_backend ();
1899 state->driver = get_driver ();
1900 state->device = get_device_name ();
1901 state->input_device = get_input_device_name ();
1902 state->output_device = get_output_device_name ();
1903 state->sample_rate = get_rate ();
1904 state->buffer_size = get_buffer_size ();
1905 state->n_periods = get_nperiods ();
1906 state->input_latency = get_input_latency ();
1907 state->output_latency = get_output_latency ();
1908 state->input_channels = get_input_channels ();
1909 state->output_channels = get_output_channels ();
1910 state->midi_option = get_midi_option ();
1911 state->midi_devices = _midi_devices;
1912 state->use_buffered_io = get_use_buffered_io ();
1913 state->lru = time (NULL) ;
1917 EngineControl::maybe_display_saved_state ()
1919 if (!_have_control) {
1923 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1926 DEBUG_ECONTROL ("Restoring saved state");
1927 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1929 if (!_desired_sample_rate) {
1930 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1932 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1934 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1935 /* call this explicitly because we're ignoring changes to
1936 the controls at this point.
1938 show_buffer_duration ();
1939 input_latency.set_value (state->input_latency);
1940 output_latency.set_value (state->output_latency);
1942 use_buffered_io_button.set_active (state->use_buffered_io);
1944 if (!state->midi_option.empty()) {
1945 midi_option_combo.set_active_text (state->midi_option);
1946 _midi_devices = state->midi_devices;
1949 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1954 EngineControl::get_state ()
1958 XMLNode* root = new XMLNode ("AudioMIDISetup");
1961 if (!states.empty()) {
1962 XMLNode* state_nodes = new XMLNode ("EngineStates");
1964 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1966 XMLNode* node = new XMLNode ("State");
1968 node->add_property ("backend", (*i)->backend);
1969 node->add_property ("driver", (*i)->driver);
1970 node->add_property ("device", (*i)->device);
1971 node->add_property ("input-device", (*i)->input_device);
1972 node->add_property ("output-device", (*i)->output_device);
1973 node->add_property ("sample-rate", (*i)->sample_rate);
1974 node->add_property ("buffer-size", (*i)->buffer_size);
1975 node->add_property ("n-periods", (*i)->n_periods);
1976 node->add_property ("input-latency", (*i)->input_latency);
1977 node->add_property ("output-latency", (*i)->output_latency);
1978 node->add_property ("input-channels", (*i)->input_channels);
1979 node->add_property ("output-channels", (*i)->output_channels);
1980 node->add_property ("active", (*i)->active ? "yes" : "no");
1981 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1982 node->add_property ("midi-option", (*i)->midi_option);
1983 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1985 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1986 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1987 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1988 midi_device_stuff->add_property (X_("name"), (*p)->name);
1989 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1990 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1991 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1992 midi_devices->add_child_nocopy (*midi_device_stuff);
1994 node->add_child_nocopy (*midi_devices);
1996 state_nodes->add_child_nocopy (*node);
1999 root->add_child_nocopy (*state_nodes);
2006 EngineControl::set_default_state ()
2008 vector<string> backend_names;
2009 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2011 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
2012 backend_names.push_back ((*b)->name);
2014 backend_combo.set_active_text (backend_names.front());
2016 // We could set default backends per platform etc here
2022 EngineControl::set_state (const XMLNode& root)
2024 XMLNodeList clist, cclist;
2025 XMLNodeConstIterator citer, cciter;
2026 XMLNode const * child;
2027 XMLNode const * grandchild;
2028 XMLProperty const * prop = NULL;
2030 if (root.name() != "AudioMIDISetup") {
2034 clist = root.children();
2038 for (citer = clist.begin(); citer != clist.end(); ++citer) {
2042 if (child->name() != "EngineStates") {
2046 cclist = child->children();
2048 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2049 State state (new StateStruct);
2051 grandchild = *cciter;
2053 if (grandchild->name() != "State") {
2057 if ((prop = grandchild->property ("backend")) == 0) {
2060 state->backend = prop->value ();
2062 if ((prop = grandchild->property ("driver")) == 0) {
2065 state->driver = prop->value ();
2067 if ((prop = grandchild->property ("device")) == 0) {
2070 state->device = prop->value ();
2072 if ((prop = grandchild->property ("input-device")) == 0) {
2075 state->input_device = prop->value ();
2077 if ((prop = grandchild->property ("output-device")) == 0) {
2080 state->output_device = prop->value ();
2082 if ((prop = grandchild->property ("sample-rate")) == 0) {
2085 state->sample_rate = atof (prop->value ());
2087 if ((prop = grandchild->property ("buffer-size")) == 0) {
2090 state->buffer_size = atoi (prop->value ());
2092 if ((prop = grandchild->property ("n-periods")) == 0) {
2093 // optional (new value in 4.5)
2094 state->n_periods = 0;
2096 state->n_periods = atoi (prop->value ());
2099 if ((prop = grandchild->property ("input-latency")) == 0) {
2102 state->input_latency = atoi (prop->value ());
2104 if ((prop = grandchild->property ("output-latency")) == 0) {
2107 state->output_latency = atoi (prop->value ());
2109 if ((prop = grandchild->property ("input-channels")) == 0) {
2112 state->input_channels = atoi (prop->value ());
2114 if ((prop = grandchild->property ("output-channels")) == 0) {
2117 state->output_channels = atoi (prop->value ());
2119 if ((prop = grandchild->property ("active")) == 0) {
2122 state->active = string_is_affirmative (prop->value ());
2124 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2127 state->use_buffered_io = string_is_affirmative (prop->value ());
2129 if ((prop = grandchild->property ("midi-option")) == 0) {
2132 state->midi_option = prop->value ();
2134 state->midi_devices.clear();
2136 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2137 const XMLNodeList mnc = midinode->children();
2138 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2139 if ((*n)->property (X_("name")) == 0
2140 || (*n)->property (X_("enabled")) == 0
2141 || (*n)->property (X_("input-latency")) == 0
2142 || (*n)->property (X_("output-latency")) == 0
2147 MidiDeviceSettings ptr (new MidiDeviceSetting(
2148 (*n)->property (X_("name"))->value (),
2149 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2150 atoi ((*n)->property (X_("input-latency"))->value ()),
2151 atoi ((*n)->property (X_("output-latency"))->value ())
2153 state->midi_devices.push_back (ptr);
2157 if ((prop = grandchild->property ("lru"))) {
2158 state->lru = atoi (prop->value ());
2162 /* remove accumulated duplicates (due to bug in ealier version)
2163 * this can be removed again before release
2165 for (StateList::iterator i = states.begin(); i != states.end();) {
2166 if ((*i)->backend == state->backend &&
2167 (*i)->driver == state->driver &&
2168 (*i)->device == state->device) {
2169 i = states.erase(i);
2176 states.push_back (state);
2180 /* now see if there was an active state and switch the setup to it */
2182 // purge states of backend that are not available in this built
2183 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2184 vector<std::string> backend_names;
2186 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2187 backend_names.push_back((*i)->name);
2189 for (StateList::iterator i = states.begin(); i != states.end();) {
2190 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2191 i = states.erase(i);
2197 states.sort (state_sort_cmp);
2199 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2202 return set_current_state (*i);
2209 EngineControl::set_current_state (const State& state)
2211 DEBUG_ECONTROL ("set_current_state");
2213 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2215 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2216 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2217 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2218 // this shouldn't happen as the invalid backend names should have been
2219 // removed from the list of states.
2223 // now reflect the change in the backend in the GUI so backend_changed will
2224 // do the right thing
2225 backend_combo.set_active_text (state->backend);
2227 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2229 // we don't have control don't restore state
2234 if (!state->driver.empty ()) {
2235 if (!backend->requires_driver_selection ()) {
2236 DEBUG_ECONTROL ("Backend should require driver selection");
2237 // A backend has changed from having driver selection to not having
2238 // it or someone has been manually editing a config file and messed
2243 if (backend->set_driver (state->driver) != 0) {
2244 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2245 // Driver names for a backend have changed and the name in the
2246 // config file is now invalid or support for driver is no longer
2247 // included in the backend
2250 // no need to set the driver_combo as backend_changed will use
2251 // backend->driver_name to set the active driver
2254 if (!state->device.empty ()) {
2255 if (backend->set_device_name (state->device) != 0) {
2257 string_compose ("Unable to set device name %1", state->device));
2258 // device is no longer available on the system
2261 // no need to set active device as it will be picked up in
2262 // via backend_changed ()/set_device_popdown_strings
2265 // backend supports separate input/output devices
2266 if (backend->set_input_device_name (state->input_device) != 0) {
2267 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2268 state->input_device));
2269 // input device is no longer available on the system
2273 if (backend->set_output_device_name (state->output_device) != 0) {
2274 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2275 state->input_device));
2276 // output device is no longer available on the system
2279 // no need to set active devices as it will be picked up in via
2280 // backend_changed ()/set_*_device_popdown_strings
2285 // Now restore the state of the rest of the controls
2287 // We don't use a SignalBlocker as set_current_state is currently only
2288 // called from set_state before any signals are connected. If at some point
2289 // a more general named state mechanism is implemented and
2290 // set_current_state is called while signals are connected then a
2291 // SignalBlocker will need to be instantiated before setting these.
2293 device_combo.set_active_text (state->device);
2294 input_device_combo.set_active_text (state->input_device);
2295 output_device_combo.set_active_text (state->output_device);
2296 if (!_desired_sample_rate) {
2297 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2299 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2300 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2301 input_latency.set_value (state->input_latency);
2302 output_latency.set_value (state->output_latency);
2303 midi_option_combo.set_active_text (state->midi_option);
2304 use_buffered_io_button.set_active (state->use_buffered_io);
2309 EngineControl::push_state_to_backend (bool start)
2311 DEBUG_ECONTROL ("push_state_to_backend");
2312 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2313 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2319 /* figure out what is going to change */
2321 bool restart_required = false;
2322 bool was_running = ARDOUR::AudioEngine::instance()->running();
2323 bool change_driver = false;
2324 bool change_device = false;
2325 bool change_rate = false;
2326 bool change_bufsize = false;
2327 bool change_nperiods = false;
2328 bool change_latency = false;
2329 bool change_channels = false;
2330 bool change_midi = false;
2331 bool change_buffered_io = false;
2333 uint32_t ochan = get_output_channels ();
2334 uint32_t ichan = get_input_channels ();
2336 if (_have_control) {
2338 if (started_at_least_once) {
2340 /* we can control the backend */
2342 if (backend->requires_driver_selection()) {
2343 if (get_driver() != backend->driver_name()) {
2344 change_driver = true;
2348 if (backend->use_separate_input_and_output_devices()) {
2349 if (get_input_device_name() != backend->input_device_name()) {
2350 change_device = true;
2352 if (get_output_device_name() != backend->output_device_name()) {
2353 change_device = true;
2356 if (get_device_name() != backend->device_name()) {
2357 change_device = true;
2361 if (queue_device_changed) {
2362 change_device = true;
2365 if (get_rate() != backend->sample_rate()) {
2369 if (get_buffer_size() != backend->buffer_size()) {
2370 change_bufsize = true;
2373 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2374 && get_nperiods() != backend->period_size()) {
2375 change_nperiods = true;
2378 if (get_midi_option() != backend->midi_option()) {
2382 if (backend->can_use_buffered_io()) {
2383 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2384 change_buffered_io = true;
2388 /* zero-requested channels means "all available" */
2391 ichan = backend->input_channels();
2395 ochan = backend->output_channels();
2398 if (ichan != backend->input_channels()) {
2399 change_channels = true;
2402 if (ochan != backend->output_channels()) {
2403 change_channels = true;
2406 if (get_input_latency() != backend->systemic_input_latency() ||
2407 get_output_latency() != backend->systemic_output_latency()) {
2408 change_latency = true;
2411 /* backend never started, so we have to force a group
2414 change_device = true;
2415 if (backend->requires_driver_selection()) {
2416 change_driver = true;
2419 change_bufsize = true;
2420 change_channels = true;
2421 change_latency = true;
2423 change_buffered_io = backend->can_use_buffered_io();
2424 change_channels = true;
2425 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2430 /* we have no control over the backend, meaning that we can
2431 * only possibly change sample rate and buffer size.
2435 if (get_rate() != backend->sample_rate()) {
2436 change_bufsize = true;
2439 if (get_buffer_size() != backend->buffer_size()) {
2440 change_bufsize = true;
2444 queue_device_changed = false;
2446 if (!_have_control) {
2448 /* We do not have control over the backend, so the best we can
2449 * do is try to change the sample rate and/or bufsize and get
2453 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2457 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2462 backend->set_sample_rate (get_rate());
2465 if (change_bufsize) {
2466 backend->set_buffer_size (get_buffer_size());
2470 if (ARDOUR::AudioEngine::instance()->start ()) {
2471 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2481 /* determine if we need to stop the backend before changing parameters */
2483 if (change_driver || change_device || change_channels || change_nperiods ||
2484 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2485 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2486 change_midi || change_buffered_io ||
2487 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2488 restart_required = true;
2490 restart_required = false;
2495 if (restart_required) {
2496 if (ARDOUR::AudioEngine::instance()->stop()) {
2502 if (change_driver && backend->set_driver (get_driver())) {
2503 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2506 if (backend->use_separate_input_and_output_devices()) {
2507 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2508 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2511 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2512 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2516 if (change_device && backend->set_device_name (get_device_name())) {
2517 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2521 if (change_rate && backend->set_sample_rate (get_rate())) {
2522 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2525 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2526 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2529 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2530 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2534 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2535 if (backend->set_input_channels (get_input_channels())) {
2536 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2539 if (backend->set_output_channels (get_output_channels())) {
2540 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2544 if (change_latency) {
2545 if (backend->set_systemic_input_latency (get_input_latency())) {
2546 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2549 if (backend->set_systemic_output_latency (get_output_latency())) {
2550 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2556 backend->set_midi_option (get_midi_option());
2559 if (change_buffered_io) {
2560 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2564 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2565 if (_measure_midi) {
2566 if (*p == _measure_midi) {
2567 backend->set_midi_device_enabled ((*p)->name, true);
2569 backend->set_midi_device_enabled ((*p)->name, false);
2571 if (backend->can_change_systemic_latency_when_running ()) {
2572 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2573 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2577 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2578 if (backend->can_set_systemic_midi_latencies()) {
2579 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2580 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2585 if (start || (was_running && restart_required)) {
2586 if (ARDOUR::AudioEngine::instance()->start()) {
2597 EngineControl::post_push ()
2599 /* get a pointer to the current state object, creating one if
2603 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2606 state = save_state ();
2612 states.sort (state_sort_cmp);
2616 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2617 (*i)->active = false;
2620 /* mark this one active (to be used next time the dialog is
2624 state->active = true;
2626 if (_have_control) { // XXX
2627 manage_control_app_sensitivity ();
2630 /* schedule a redisplay of MIDI ports */
2631 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2636 EngineControl::get_rate () const
2638 float r = atof (sample_rate_combo.get_active_text ());
2639 /* the string may have been translated with an abbreviation for
2640 * thousands, so use a crude heuristic to fix this.
2650 EngineControl::get_buffer_size () const
2652 string txt = buffer_size_combo.get_active_text ();
2655 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2656 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2657 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2665 EngineControl::get_nperiods () const
2667 string txt = nperiods_combo.get_active_text ();
2668 return atoi (txt.c_str());
2672 EngineControl::get_midi_option () const
2674 return midi_option_combo.get_active_text();
2678 EngineControl::get_use_buffered_io () const
2680 return use_buffered_io_button.get_active();
2684 EngineControl::get_input_channels() const
2686 if (ARDOUR::Profile->get_mixbus()) {
2687 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2688 if (!backend) return 0;
2689 return backend->input_channels();
2691 return (uint32_t) input_channels_adjustment.get_value();
2695 EngineControl::get_output_channels() const
2697 if (ARDOUR::Profile->get_mixbus()) {
2698 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2699 if (!backend) return 0;
2700 return backend->input_channels();
2702 return (uint32_t) output_channels_adjustment.get_value();
2706 EngineControl::get_input_latency() const
2708 return (uint32_t) input_latency_adjustment.get_value();
2712 EngineControl::get_output_latency() const
2714 return (uint32_t) output_latency_adjustment.get_value();
2718 EngineControl::get_backend () const
2720 return backend_combo.get_active_text ();
2724 EngineControl::get_driver () const
2726 if (driver_combo.get_parent()) {
2727 return driver_combo.get_active_text ();
2734 EngineControl::get_device_name () const
2736 return device_combo.get_active_text ();
2740 EngineControl::get_input_device_name () const
2742 return input_device_combo.get_active_text ();
2746 EngineControl::get_output_device_name () const
2748 return output_device_combo.get_active_text ();
2752 EngineControl::control_app_button_clicked ()
2754 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2760 backend->launch_control_app ();
2764 EngineControl::start_stop_button_clicked ()
2766 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2772 if (ARDOUR::AudioEngine::instance()->running()) {
2773 ARDOUR::AudioEngine::instance()->stop ();
2780 EngineControl::update_devices_button_clicked ()
2782 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2788 if (backend->update_devices()) {
2789 device_list_changed ();
2794 EngineControl::use_buffered_io_button_clicked ()
2796 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2802 bool set_buffered_io = !use_buffered_io_button.get_active();
2803 use_buffered_io_button.set_active (set_buffered_io);
2804 backend->set_use_buffered_io (set_buffered_io);
2808 EngineControl::manage_control_app_sensitivity ()
2810 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2816 string appname = backend->control_app_name();
2818 if (appname.empty()) {
2819 control_app_button.set_sensitive (false);
2821 control_app_button.set_sensitive (true);
2826 EngineControl::set_desired_sample_rate (uint32_t sr)
2828 _desired_sample_rate = sr;
2829 if (ARDOUR::AudioEngine::instance ()->running ()
2830 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2837 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2839 if (page_num == 0) {
2840 cancel_button->set_sensitive (true);
2841 _measure_midi.reset();
2842 update_sensitivity ();
2844 cancel_button->set_sensitive (false);
2845 ok_button->set_sensitive (false);
2848 if (page_num == midi_tab) {
2850 refresh_midi_display ();
2853 if (page_num == latency_tab) {
2856 if (ARDOUR::AudioEngine::instance()->running()) {
2861 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2863 /* save any existing latency values */
2865 uint32_t il = (uint32_t) input_latency.get_value ();
2866 uint32_t ol = (uint32_t) input_latency.get_value ();
2868 /* reset to zero so that our new test instance
2869 will be clean of any existing latency measures.
2871 NB. this should really be done by the backend
2872 when stated for latency measurement.
2875 input_latency.set_value (0);
2876 output_latency.set_value (0);
2878 push_state_to_backend (false);
2882 input_latency.set_value (il);
2883 output_latency.set_value (ol);
2886 // This should be done in push_state_to_backend()
2887 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2888 disable_latency_tab ();
2891 enable_latency_tab ();
2895 end_latency_detection ();
2896 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2901 /* latency measurement */
2904 EngineControl::check_audio_latency_measurement ()
2906 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2908 if (mtdm->resolve () < 0) {
2909 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2913 if (mtdm->get_peak () > 0.707f) {
2914 // get_peak() resets the peak-hold in the detector.
2915 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2916 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2920 if (mtdm->err () > 0.3) {
2926 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2928 if (sample_rate == 0) {
2929 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2930 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2934 int frames_total = mtdm->del();
2935 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2937 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2938 _("Detected roundtrip latency: "),
2939 frames_total, frames_total * 1000.0f/sample_rate,
2940 _("Systemic latency: "),
2941 extra, extra * 1000.0f/sample_rate);
2945 if (mtdm->err () > 0.2) {
2947 strcat (buf, _("(signal detection error)"));
2953 strcat (buf, _("(inverted - bad wiring)"));
2957 lm_results.set_markup (string_compose (results_markup, buf));
2960 have_lm_results = true;
2961 end_latency_detection ();
2962 lm_use_button.set_sensitive (true);
2970 EngineControl::check_midi_latency_measurement ()
2972 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2974 if (!mididm->have_signal () || mididm->latency () == 0) {
2975 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2980 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2982 if (sample_rate == 0) {
2983 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2984 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2988 ARDOUR::framecnt_t frames_total = mididm->latency();
2989 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2990 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2991 _("Detected roundtrip latency: "),
2992 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2993 _("Systemic latency: "),
2994 extra, extra * 1000.0f / sample_rate);
2998 if (!mididm->ok ()) {
3000 strcat (buf, _("(averaging)"));
3004 if (mididm->deviation () > 50.0) {
3006 strcat (buf, _("(too large jitter)"));
3008 } else if (mididm->deviation () > 10.0) {
3010 strcat (buf, _("(large jitter)"));
3014 have_lm_results = true;
3015 end_latency_detection ();
3016 lm_use_button.set_sensitive (true);
3017 lm_results.set_markup (string_compose (results_markup, buf));
3019 } else if (mididm->processed () > 400) {
3020 have_lm_results = false;
3021 end_latency_detection ();
3022 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3026 lm_results.set_markup (string_compose (results_markup, buf));
3032 EngineControl::start_latency_detection ()
3034 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
3035 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
3037 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3038 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3039 if (_measure_midi) {
3040 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3042 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3044 lm_measure_label.set_text (_("Cancel"));
3045 have_lm_results = false;
3046 lm_use_button.set_sensitive (false);
3047 lm_input_channel_combo.set_sensitive (false);
3048 lm_output_channel_combo.set_sensitive (false);
3054 EngineControl::end_latency_detection ()
3056 latency_timeout.disconnect ();
3057 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3058 lm_measure_label.set_text (_("Measure"));
3059 if (!have_lm_results) {
3060 lm_use_button.set_sensitive (false);
3062 lm_input_channel_combo.set_sensitive (true);
3063 lm_output_channel_combo.set_sensitive (true);
3068 EngineControl::latency_button_clicked ()
3071 start_latency_detection ();
3073 end_latency_detection ();
3078 EngineControl::latency_back_button_clicked ()
3080 ARDOUR::AudioEngine::instance()->stop(true);
3081 notebook.set_current_page(0);
3085 EngineControl::use_latency_button_clicked ()
3087 if (_measure_midi) {
3088 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3092 ARDOUR::framecnt_t frames_total = mididm->latency();
3093 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3094 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3095 _measure_midi->input_latency = one_way;
3096 _measure_midi->output_latency = one_way;
3097 notebook.set_current_page (midi_tab);
3099 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3105 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3106 one_way = std::max (0., one_way);
3108 input_latency_adjustment.set_value (one_way);
3109 output_latency_adjustment.set_value (one_way);
3111 /* back to settings page */
3112 notebook.set_current_page (0);
3117 EngineControl::on_delete_event (GdkEventAny* ev)
3119 if (notebook.get_current_page() == 2) {
3120 /* currently on latency tab - be sure to clean up */
3121 end_latency_detection ();
3123 return ArdourDialog::on_delete_event (ev);
3127 EngineControl::engine_running ()
3129 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3132 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3133 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3135 if (backend->can_set_period_size ()) {
3136 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3139 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3140 connect_disconnect_button.show();
3142 started_at_least_once = true;
3143 if (_have_control) {
3144 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3146 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3148 update_sensitivity();
3150 refill_midi_ports (true);
3151 refill_midi_ports (false);
3155 EngineControl::engine_stopped ()
3157 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3160 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3161 connect_disconnect_button.show();
3163 if (_have_control) {
3164 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3166 engine_status.set_markup(X_(""));
3169 update_sensitivity();
3173 EngineControl::device_list_changed ()
3175 if (ignore_device_changes) {
3178 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3180 midi_option_changed();
3184 EngineControl::connect_disconnect_click()
3186 if (ARDOUR::AudioEngine::instance()->running()) {
3194 EngineControl::calibrate_audio_latency ()
3196 _measure_midi.reset ();
3197 have_lm_results = false;
3198 lm_use_button.set_sensitive (false);
3199 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3200 notebook.set_current_page (latency_tab);
3204 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3207 have_lm_results = false;
3208 lm_use_button.set_sensitive (false);
3209 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3210 notebook.set_current_page (latency_tab);
3214 EngineControl::configure_midi_devices ()
3216 notebook.set_current_page (midi_tab);