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.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.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"
61 using namespace Gtkmm2ext;
64 using namespace ARDOUR_UI_UTILS;
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
73 EngineControl::EngineControl ()
74 : ArdourDialog (_("Audio/MIDI Setup"))
77 , input_latency_adjustment (0, 0, 99999, 1)
78 , input_latency (input_latency_adjustment)
79 , output_latency_adjustment (0, 0, 99999, 1)
80 , output_latency (output_latency_adjustment)
81 , input_channels_adjustment (0, 0, 256, 1)
82 , input_channels (input_channels_adjustment)
83 , output_channels_adjustment (0, 0, 256, 1)
84 , output_channels (output_channels_adjustment)
85 , ports_adjustment (128, 8, 1024, 1, 16)
86 , ports_spinner (ports_adjustment)
87 , control_app_button (_("Device Control Panel"))
88 , midi_devices_button (_("Midi Device Setup"))
89 , lm_measure_label (_("Measure"))
90 , lm_use_button (_("Use results"))
91 , lm_back_button (_("Back to settings ... (ignore results)"))
92 , lm_button_audio (_("Calibrate Audio"))
94 , have_lm_results (false)
96 , midi_back_button (_("Back to settings"))
98 , _desired_sample_rate (0)
99 , started_at_least_once (false)
100 , queue_device_changed (false)
103 using namespace Notebook_Helpers;
104 vector<string> backend_names;
106 AttachOptions xopt = AttachOptions (FILL|EXPAND);
109 set_name (X_("AudioMIDISetup"));
111 /* the backend combo is the one thing that is ALWAYS visible */
113 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
115 if (backends.empty()) {
116 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));
118 throw failed_constructor ();
121 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
122 backend_names.push_back ((*b)->name);
125 set_popdown_strings (backend_combo, backend_names);
127 /* setup basic packing characteristics for the table used on the main
128 * tab of the notebook
131 basic_packer.set_spacings (6);
132 basic_packer.set_border_width (12);
133 basic_packer.set_homogeneous (false);
137 basic_hbox.pack_start (basic_packer, false, false);
139 /* latency measurement tab */
141 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
144 lm_table.set_row_spacings (12);
145 lm_table.set_col_spacings (6);
146 lm_table.set_homogeneous (false);
148 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
151 lm_preamble.set_width_chars (60);
152 lm_preamble.set_line_wrap (true);
153 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
155 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
158 Gtk::Label* preamble;
159 preamble = manage (new Label);
160 preamble->set_width_chars (60);
161 preamble->set_line_wrap (true);
162 preamble->set_markup (_("Select two channels below and connect them using a cable."));
164 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
167 label = manage (new Label (_("Output channel")));
168 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
170 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
171 misc_align->add (lm_output_channel_combo);
172 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
175 label = manage (new Label (_("Input channel")));
176 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
178 misc_align = manage (new Alignment (0.0, 0.5));
179 misc_align->add (lm_input_channel_combo);
180 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
183 lm_measure_label.set_padding (10, 10);
184 lm_measure_button.add (lm_measure_label);
185 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
186 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
187 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
189 lm_use_button.set_sensitive (false);
191 /* Increase the default spacing around the labels of these three
197 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
198 l->set_padding (10, 10);
201 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
202 l->set_padding (10, 10);
205 preamble = manage (new Label);
206 preamble->set_width_chars (60);
207 preamble->set_line_wrap (true);
208 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
209 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
212 preamble = manage (new Label);
213 preamble->set_width_chars (60);
214 preamble->set_line_wrap (true);
215 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
216 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
218 ++row; // skip a row in the table
219 ++row; // skip a row in the table
221 lm_table.attach (lm_results, 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_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
232 lm_vbox.set_border_width (12);
233 lm_vbox.pack_start (lm_table, false, false);
235 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
239 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
240 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
241 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
242 notebook.set_border_width (12);
244 notebook.set_show_tabs (false);
245 notebook.show_all ();
247 notebook.set_name ("SettingsNotebook");
249 /* packup the notebook */
251 get_vbox()->set_border_width (12);
252 get_vbox()->pack_start (notebook);
254 get_action_area()->pack_start (engine_status);
255 engine_status.show();
257 /* need a special function to print "all available channels" when the
258 * channel counts hit zero.
261 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
262 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
264 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
265 midi_devices_button.set_sensitive (false);
266 midi_devices_button.set_name ("generic button");
267 midi_devices_button.set_can_focus(true);
269 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
270 manage_control_app_sensitivity ();
272 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
273 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
274 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
276 /* Pick up any existing audio setup configuration, if appropriate */
278 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
280 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
281 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
282 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
283 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
286 if (!set_state (*audio_setup)) {
287 set_default_state ();
290 set_default_state ();
293 connect_changed_signals ();
295 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
297 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
298 connect_disconnect_button.set_no_show_all();
303 EngineControl::connect_changed_signals ()
305 backend_combo_connection = backend_combo.signal_changed ().connect (
306 sigc::mem_fun (*this, &EngineControl::backend_changed));
307 driver_combo_connection = driver_combo.signal_changed ().connect (
308 sigc::mem_fun (*this, &EngineControl::driver_changed));
309 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
310 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
311 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
312 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
313 device_combo_connection = device_combo.signal_changed ().connect (
314 sigc::mem_fun (*this, &EngineControl::device_changed));
315 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
316 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
318 input_device_combo_connection = input_device_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::input_device_changed));
320 output_device_combo_connection = output_device_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::output_device_changed));
323 input_latency_connection = input_latency.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::parameter_changed));
325 output_latency_connection = output_latency.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::parameter_changed));
327 input_channels_connection = input_channels.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::parameter_changed));
329 output_channels_connection = output_channels.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::parameter_changed));
334 EngineControl::block_changed_signals ()
336 if (block_signals++ == 0) {
337 DEBUG_ECONTROL ("Blocking changed signals");
338 backend_combo_connection.block ();
339 driver_combo_connection.block ();
340 sample_rate_combo_connection.block ();
341 buffer_size_combo_connection.block ();
342 device_combo_connection.block ();
343 input_device_combo_connection.block ();
344 output_device_combo_connection.block ();
345 midi_option_combo_connection.block ();
346 input_latency_connection.block ();
347 output_latency_connection.block ();
348 input_channels_connection.block ();
349 output_channels_connection.block ();
354 EngineControl::unblock_changed_signals ()
356 if (--block_signals == 0) {
357 DEBUG_ECONTROL ("Unblocking changed signals");
358 backend_combo_connection.unblock ();
359 driver_combo_connection.unblock ();
360 sample_rate_combo_connection.unblock ();
361 buffer_size_combo_connection.unblock ();
362 device_combo_connection.unblock ();
363 input_device_combo_connection.unblock ();
364 output_device_combo_connection.unblock ();
365 midi_option_combo_connection.unblock ();
366 input_latency_connection.unblock ();
367 output_latency_connection.unblock ();
368 input_channels_connection.unblock ();
369 output_channels_connection.unblock ();
373 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
374 const std::string& reason)
375 : ec (engine_control)
378 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
379 ec.block_changed_signals ();
382 EngineControl::SignalBlocker::~SignalBlocker ()
384 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
385 ec.unblock_changed_signals ();
389 EngineControl::on_show ()
391 ArdourDialog::on_show ();
392 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
393 // re-check _have_control (jackd running) see #6041
397 ok_button->grab_focus();
401 EngineControl::on_response (int response_id)
403 ArdourDialog::on_response (response_id);
405 switch (response_id) {
407 push_state_to_backend (true);
410 #ifdef PLATFORM_WINDOWS
411 // For some reason we don't understand, 'hide()'
412 // needs to get called first in Windows
415 // But if there's no session open, this can produce
416 // a long gap when nothing appears to be happening.
417 // Let's show the splash image while we're waiting.
418 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
419 if ( ARDOUR_UI::instance() ) {
420 if ( !ARDOUR_UI::instance()->session_loaded ) {
421 ARDOUR_UI::instance()->show_splash();
425 push_state_to_backend (true);
428 push_state_to_backend (true);
432 case RESPONSE_DELETE_EVENT:
435 ev.type = GDK_BUTTON_PRESS;
437 on_delete_event ((GdkEventAny*) &ev);
446 EngineControl::build_notebook ()
449 AttachOptions xopt = AttachOptions (FILL|EXPAND);
451 /* clear the table */
453 Gtkmm2ext::container_clear (basic_vbox);
454 Gtkmm2ext::container_clear (basic_packer);
456 if (control_app_button.get_parent()) {
457 control_app_button.get_parent()->remove (control_app_button);
460 label = manage (left_aligned_label (_("Audio System:")));
461 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
462 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
464 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
465 lm_button_audio.set_name ("generic button");
466 lm_button_audio.set_can_focus(true);
469 build_full_control_notebook ();
471 build_no_control_notebook ();
474 basic_vbox.pack_start (basic_hbox, false, false);
477 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
478 basic_vbox.show_all ();
483 EngineControl::build_full_control_notebook ()
485 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
488 using namespace Notebook_Helpers;
490 vector<string> strings;
491 AttachOptions xopt = AttachOptions (FILL|EXPAND);
492 int row = 1; // row zero == backend combo
494 /* start packing it up */
496 if (backend->requires_driver_selection()) {
497 label = manage (left_aligned_label (_("Driver:")));
498 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
499 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
503 if (backend->use_separate_input_and_output_devices()) {
504 label = manage (left_aligned_label (_("Input Device:")));
505 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
506 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
508 label = manage (left_aligned_label (_("Output Device:")));
509 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
510 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
512 // reset so it isn't used in state comparisons
513 device_combo.set_active_text ("");
515 label = manage (left_aligned_label (_("Device:")));
516 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
517 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
519 // reset these so they don't get used in state comparisons
520 input_device_combo.set_active_text ("");
521 output_device_combo.set_active_text ("");
524 label = manage (left_aligned_label (_("Sample rate:")));
525 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
526 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
530 label = manage (left_aligned_label (_("Buffer size:")));
531 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
532 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
533 buffer_size_duration_label.set_alignment (0.0); /* left-align */
534 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
536 /* button spans 2 rows */
538 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
541 input_channels.set_name ("InputChannels");
542 input_channels.set_flags (Gtk::CAN_FOCUS);
543 input_channels.set_digits (0);
544 input_channels.set_wrap (false);
545 output_channels.set_editable (true);
547 if (!ARDOUR::Profile->get_mixbus()) {
548 label = manage (left_aligned_label (_("Input Channels:")));
549 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
550 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
554 output_channels.set_name ("OutputChannels");
555 output_channels.set_flags (Gtk::CAN_FOCUS);
556 output_channels.set_digits (0);
557 output_channels.set_wrap (false);
558 output_channels.set_editable (true);
560 if (!ARDOUR::Profile->get_mixbus()) {
561 label = manage (left_aligned_label (_("Output Channels:")));
562 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
563 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
567 input_latency.set_name ("InputLatency");
568 input_latency.set_flags (Gtk::CAN_FOCUS);
569 input_latency.set_digits (0);
570 input_latency.set_wrap (false);
571 input_latency.set_editable (true);
573 label = manage (left_aligned_label (_("Hardware input latency:")));
574 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
575 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
576 label = manage (left_aligned_label (_("samples")));
577 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
580 output_latency.set_name ("OutputLatency");
581 output_latency.set_flags (Gtk::CAN_FOCUS);
582 output_latency.set_digits (0);
583 output_latency.set_wrap (false);
584 output_latency.set_editable (true);
586 label = manage (left_aligned_label (_("Hardware output latency:")));
587 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
588 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
589 label = manage (left_aligned_label (_("samples")));
590 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
592 /* button spans 2 rows */
594 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
597 label = manage (left_aligned_label (_("MIDI System:")));
598 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
599 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
600 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
605 EngineControl::build_no_control_notebook ()
607 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
610 using namespace Notebook_Helpers;
612 vector<string> strings;
613 AttachOptions xopt = AttachOptions (FILL|EXPAND);
614 int row = 1; // row zero == backend combo
615 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
617 label = manage (new Label);
618 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
619 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
622 if (backend->can_change_sample_rate_when_running()) {
623 label = manage (left_aligned_label (_("Sample rate:")));
624 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
625 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
629 if (backend->can_change_buffer_size_when_running()) {
630 label = manage (left_aligned_label (_("Buffer size:")));
631 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
632 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
633 buffer_size_duration_label.set_alignment (0.0); /* left-align */
634 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
638 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
642 EngineControl::~EngineControl ()
644 ignore_changes = true;
648 EngineControl::disable_latency_tab ()
650 vector<string> empty;
651 set_popdown_strings (lm_output_channel_combo, empty);
652 set_popdown_strings (lm_input_channel_combo, empty);
653 lm_measure_button.set_sensitive (false);
654 lm_use_button.set_sensitive (false);
658 EngineControl::enable_latency_tab ()
660 vector<string> outputs;
661 vector<string> inputs;
663 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
664 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
665 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
667 if (!ARDOUR::AudioEngine::instance()->running()) {
668 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
669 notebook.set_current_page (0);
673 else if (inputs.empty() || outputs.empty()) {
674 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
675 notebook.set_current_page (0);
680 lm_back_button_signal.disconnect();
682 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
685 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
689 set_popdown_strings (lm_output_channel_combo, outputs);
690 lm_output_channel_combo.set_active_text (outputs.front());
691 lm_output_channel_combo.set_sensitive (true);
693 set_popdown_strings (lm_input_channel_combo, inputs);
694 lm_input_channel_combo.set_active_text (inputs.front());
695 lm_input_channel_combo.set_sensitive (true);
697 lm_measure_button.set_sensitive (true);
701 EngineControl::setup_midi_tab_for_backend ()
703 string backend = backend_combo.get_active_text ();
705 Gtkmm2ext::container_clear (midi_vbox);
707 midi_vbox.set_border_width (12);
708 midi_device_table.set_border_width (12);
710 if (backend == "JACK") {
711 setup_midi_tab_for_jack ();
714 midi_vbox.pack_start (midi_device_table, true, true);
715 midi_vbox.pack_start (midi_back_button, false, false);
716 midi_vbox.show_all ();
720 EngineControl::setup_midi_tab_for_jack ()
725 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
727 device->input_latency = a->get_value();
729 device->output_latency = a->get_value();
734 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
735 b->set_active (!b->get_active());
736 device->enabled = b->get_active();
737 refresh_midi_display(device->name);
741 EngineControl::refresh_midi_display (std::string focus)
743 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
747 AttachOptions xopt = AttachOptions (FILL|EXPAND);
750 Gtkmm2ext::container_clear (midi_device_table);
752 midi_device_table.set_spacings (6);
754 l = manage (new Label);
755 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
756 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
757 l->set_alignment (0.5, 0.5);
761 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
762 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
763 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
764 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
766 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
767 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
768 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
769 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
772 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
777 bool enabled = (*p)->enabled;
779 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
780 m->set_name ("midi device");
781 m->set_can_focus (Gtk::CAN_FOCUS);
782 m->add_events (Gdk::BUTTON_RELEASE_MASK);
783 m->set_active (enabled);
784 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
785 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
786 if ((*p)->name == focus) {
790 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
791 s = manage (new Gtk::SpinButton (*a));
792 a->set_value ((*p)->input_latency);
793 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
794 s->set_sensitive (_can_set_midi_latencies && enabled);
795 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
797 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
798 s = manage (new Gtk::SpinButton (*a));
799 a->set_value ((*p)->output_latency);
800 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
801 s->set_sensitive (_can_set_midi_latencies && enabled);
802 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
804 b = manage (new Button (_("Calibrate")));
805 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
806 b->set_sensitive (_can_set_midi_latencies && enabled);
807 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
814 EngineControl::backend_changed ()
816 SignalBlocker blocker (*this, "backend_changed");
817 string backend_name = backend_combo.get_active_text();
818 boost::shared_ptr<ARDOUR::AudioBackend> backend;
820 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
821 /* eh? setting the backend failed... how ? */
822 /* A: stale config contains a backend that does not exist in current build */
826 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
828 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
831 setup_midi_tab_for_backend ();
832 _midi_devices.clear();
834 if (backend->requires_driver_selection()) {
835 if (set_driver_popdown_strings ()) {
836 driver_combo.set_sensitive (true);
841 driver_combo.set_sensitive (false);
842 /* this will change the device text which will cause a call to
843 * device changed which will set up parameters
848 update_midi_options ();
850 connect_disconnect_button.hide();
852 midi_option_changed();
854 started_at_least_once = false;
856 if (!ignore_changes) {
857 maybe_display_saved_state ();
862 EngineControl::update_midi_options ()
864 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
865 vector<string> midi_options = backend->enumerate_midi_options();
867 if (midi_options.size() == 1) {
868 /* only contains the "none" option */
869 midi_option_combo.set_sensitive (false);
872 set_popdown_strings (midi_option_combo, midi_options);
873 midi_option_combo.set_active_text (midi_options.front());
874 midi_option_combo.set_sensitive (true);
876 midi_option_combo.set_sensitive (false);
882 EngineControl::print_channel_count (Gtk::SpinButton* sb)
884 if (ARDOUR::Profile->get_mixbus()) {
888 uint32_t cnt = (uint32_t) sb->get_value();
890 sb->set_text (_("all available channels"));
893 snprintf (buf, sizeof (buf), "%d", cnt);
899 // @return true if there are drivers available
901 EngineControl::set_driver_popdown_strings ()
903 DEBUG_ECONTROL ("set_driver_popdown_strings");
904 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
905 vector<string> drivers = backend->enumerate_drivers();
907 if (drivers.empty ()) {
908 // This is an error...?
912 string current_driver = backend->driver_name ();
914 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
916 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
919 current_driver = drivers.front ();
922 set_popdown_strings (driver_combo, drivers);
924 string_compose ("driver_combo.set_active_text: %1", current_driver));
925 driver_combo.set_active_text (current_driver);
929 // @return true if there are devices available
931 EngineControl::set_device_popdown_strings ()
933 DEBUG_ECONTROL ("set_device_popdown_strings");
934 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
935 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
937 /* NOTE: Ardour currently does not display the "available" field of the
940 * Doing so would require a different GUI widget than the combo
941 * box/popdown that we currently use, since it has no way to list
942 * items that are not selectable. Something more like a popup menu,
943 * which could have unselectable items, would be appropriate.
946 vector<string> available_devices;
948 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
949 available_devices.push_back (i->name);
952 if (available_devices.empty ()) {
956 string current_device = backend->device_name ();
958 // Make sure that backend->device_name () is a valid
959 // device, the backend may not return a valid device if it hasn't
961 if (std::find (available_devices.begin (),
962 available_devices.end (),
963 current_device) == available_devices.end ()) {
965 current_device = available_devices.front ();
968 set_popdown_strings (device_combo, available_devices);
970 string_compose ("set device_combo active text: %1", current_device));
972 device_combo.set_active_text (current_device);
976 // @return true if there are input devices available
978 EngineControl::set_input_device_popdown_strings ()
980 DEBUG_ECONTROL ("set_input_device_popdown_strings");
981 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
982 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
984 vector<string> available_devices;
986 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
987 available_devices.push_back (i->name);
990 if (available_devices.empty()) {
994 string current_device = backend->input_device_name ();
996 // Make sure that backend->input_device_name () is a valid
997 // device, the backend may not return a valid device if it hasn't
999 if (std::find (available_devices.begin (),
1000 available_devices.end (),
1001 current_device) == available_devices.end ()) {
1003 current_device = available_devices.front ();
1006 set_popdown_strings (input_device_combo, available_devices);
1009 string_compose ("set input_device_combo active text: %1", current_device));
1010 input_device_combo.set_active_text (current_device);
1014 // @return true if there are output devices available
1016 EngineControl::set_output_device_popdown_strings ()
1018 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1019 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1020 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1022 vector<string> available_devices;
1024 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1025 available_devices.push_back (i->name);
1028 if (available_devices.empty()) {
1032 string current_device = backend->output_device_name ();
1034 // Make sure that backend->output_device_name () is a valid
1035 // device, the backend may not return a valid device if it hasn't
1037 if (std::find (available_devices.begin (),
1038 available_devices.end (),
1039 current_device) == available_devices.end ()) {
1041 current_device = available_devices.front ();
1044 set_popdown_strings (output_device_combo, available_devices);
1047 string_compose ("set output_device_combo active text: %1", current_device));
1048 output_device_combo.set_active_text (current_device);
1053 EngineControl::list_devices ()
1055 DEBUG_ECONTROL ("list_devices");
1056 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1059 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1061 bool devices_available = false;
1063 if (backend->use_separate_input_and_output_devices ()) {
1064 bool input_devices_available = set_input_device_popdown_strings ();
1065 bool output_devices_available = set_output_device_popdown_strings ();
1066 devices_available = input_devices_available || output_devices_available;
1068 devices_available = set_device_popdown_strings ();
1071 if (devices_available) {
1074 input_latency.set_sensitive (true);
1075 output_latency.set_sensitive (true);
1076 input_channels.set_sensitive (true);
1077 output_channels.set_sensitive (true);
1079 ok_button->set_sensitive (true);
1080 apply_button->set_sensitive (true);
1083 device_combo.clear();
1084 input_device_combo.clear();
1085 output_device_combo.clear();
1086 sample_rate_combo.set_sensitive (false);
1087 buffer_size_combo.set_sensitive (false);
1088 input_latency.set_sensitive (false);
1089 output_latency.set_sensitive (false);
1090 input_channels.set_sensitive (false);
1091 output_channels.set_sensitive (false);
1092 if (_have_control) {
1093 ok_button->set_sensitive (false);
1094 apply_button->set_sensitive (false);
1096 ok_button->set_sensitive (true);
1097 apply_button->set_sensitive (true);
1098 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1099 sample_rate_combo.set_sensitive (true);
1101 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1102 buffer_size_combo.set_sensitive (true);
1110 EngineControl::driver_changed ()
1112 SignalBlocker blocker (*this, "driver_changed");
1113 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1116 backend->set_driver (driver_combo.get_active_text());
1119 if (!ignore_changes) {
1120 maybe_display_saved_state ();
1125 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1127 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1128 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1133 if (_have_control) {
1134 sr = backend->available_sample_rates (device_name);
1137 sr.push_back (8000.0f);
1138 sr.push_back (16000.0f);
1139 sr.push_back (32000.0f);
1140 sr.push_back (44100.0f);
1141 sr.push_back (48000.0f);
1142 sr.push_back (88200.0f);
1143 sr.push_back (96000.0f);
1144 sr.push_back (192000.0f);
1145 sr.push_back (384000.0f);
1148 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1149 s.push_back (rate_as_string (*x));
1150 if (*x == _desired_sample_rate) {
1156 sample_rate_combo.set_sensitive (true);
1157 set_popdown_strings (sample_rate_combo, s);
1159 if (desired.empty ()) {
1160 float new_active_sr = backend->default_sample_rate ();
1162 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1163 new_active_sr = sr.front ();
1166 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1168 sample_rate_combo.set_active_text (desired);
1172 sample_rate_combo.set_sensitive (false);
1177 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1179 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1180 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1181 vector<uint32_t> bs;
1184 if (_have_control) {
1185 bs = backend->available_buffer_sizes (device_name);
1186 } else if (backend->can_change_buffer_size_when_running()) {
1194 bs.push_back (1024);
1195 bs.push_back (2048);
1196 bs.push_back (4096);
1197 bs.push_back (8192);
1200 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1201 s.push_back (bufsize_as_string (*x));
1205 buffer_size_combo.set_sensitive (true);
1206 set_popdown_strings (buffer_size_combo, s);
1207 buffer_size_combo.set_active_text (s.front());
1209 uint32_t period = backend->buffer_size();
1211 period = backend->default_buffer_size(device_name);
1213 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1214 show_buffer_duration ();
1216 buffer_size_combo.set_sensitive (false);
1221 EngineControl::device_changed ()
1223 SignalBlocker blocker (*this, "device_changed");
1224 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1227 string device_name_in;
1228 string device_name_out; // only used if backend support separate I/O devices
1230 if (backend->use_separate_input_and_output_devices()) {
1231 device_name_in = get_input_device_name ();
1232 device_name_out = get_output_device_name ();
1234 device_name_in = get_device_name ();
1237 /* we set the backend-device to query various device related intormation.
1238 * This has the side effect that backend->device_name() will match
1239 * the device_name and 'change_device' will never be true.
1240 * so work around this by setting...
1242 if (backend->use_separate_input_and_output_devices()) {
1243 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1244 queue_device_changed = true;
1247 if (device_name_in != backend->device_name()) {
1248 queue_device_changed = true;
1252 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1253 if (backend->use_separate_input_and_output_devices()) {
1254 backend->set_input_device_name (device_name_in);
1255 backend->set_output_device_name (device_name_out);
1257 backend->set_device_name(device_name_in);
1261 /* don't allow programmatic change to combos to cause a
1262 recursive call to this method.
1264 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1266 /* backends that support separate devices, need to ignore
1267 * the device-name - and use the devies set above
1269 set_samplerate_popdown_strings (device_name_in);
1270 set_buffersize_popdown_strings (device_name_in);
1271 /* XXX theoretically need to set min + max channel counts here
1274 manage_control_app_sensitivity ();
1277 /* pick up any saved state for this device */
1279 if (!ignore_changes) {
1280 maybe_display_saved_state ();
1285 EngineControl::input_device_changed ()
1287 DEBUG_ECONTROL ("input_device_changed");
1292 EngineControl::output_device_changed ()
1294 DEBUG_ECONTROL ("output_device_changed");
1299 EngineControl::bufsize_as_string (uint32_t sz)
1301 /* Translators: "samples" is always plural here, so no
1302 need for plural+singular forms.
1305 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1310 EngineControl::sample_rate_changed ()
1312 DEBUG_ECONTROL ("sample_rate_changed");
1313 /* reset the strings for buffer size to show the correct msec value
1314 (reflecting the new sample rate).
1317 show_buffer_duration ();
1322 EngineControl::buffer_size_changed ()
1324 DEBUG_ECONTROL ("buffer_size_changed");
1325 show_buffer_duration ();
1329 EngineControl::show_buffer_duration ()
1331 DEBUG_ECONTROL ("show_buffer_duration");
1332 /* buffer sizes - convert from just samples to samples + msecs for
1333 * the displayed string
1336 string bs_text = buffer_size_combo.get_active_text ();
1337 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1338 uint32_t rate = get_rate();
1340 /* Developers: note the hard-coding of a double buffered model
1341 in the (2 * samples) computation of latency. we always start
1342 the audiobackend in this configuration.
1344 /* note to jack1 developers: ardour also always starts the engine
1345 * in async mode (no jack2 --sync option) which adds an extra cycle
1346 * of latency with jack2 (and *3 would be correct)
1347 * The value can also be wrong if jackd is started externally..
1349 * At the time of writing the ALSA backend always uses double-buffering *2,
1350 * The Dummy backend *1, and who knows what ASIO really does :)
1352 * So just display the period size, that's also what
1353 * ARDOUR_UI::update_sample_rate() does for the status bar.
1354 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1355 * but still, that's the buffer period, not [round-trip] latency)
1358 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1359 buffer_size_duration_label.set_text (buf);
1363 EngineControl::midi_option_changed ()
1365 DEBUG_ECONTROL ("midi_option_changed");
1366 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1369 backend->set_midi_option (get_midi_option());
1371 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1373 //_midi_devices.clear(); // TODO merge with state-saved settings..
1374 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1375 std::vector<MidiDeviceSettings> new_devices;
1377 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1378 MidiDeviceSettings mds = find_midi_device (i->name);
1379 if (i->available && !mds) {
1380 uint32_t input_latency = 0;
1381 uint32_t output_latency = 0;
1382 if (_can_set_midi_latencies) {
1383 input_latency = backend->systemic_midi_input_latency (i->name);
1384 output_latency = backend->systemic_midi_output_latency (i->name);
1386 bool enabled = backend->midi_device_enabled (i->name);
1387 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1388 new_devices.push_back (ptr);
1389 } else if (i->available) {
1390 new_devices.push_back (mds);
1393 _midi_devices = new_devices;
1395 if (_midi_devices.empty()) {
1396 midi_devices_button.set_sensitive (false);
1398 midi_devices_button.set_sensitive (true);
1403 EngineControl::parameter_changed ()
1407 EngineControl::State
1408 EngineControl::get_matching_state (
1409 const string& backend,
1410 const string& driver,
1411 const string& device)
1413 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1414 if ((*i)->backend == backend &&
1415 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1423 EngineControl::State
1424 EngineControl::get_matching_state (
1425 const string& backend,
1426 const string& driver,
1427 const string& input_device,
1428 const string& output_device)
1430 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1431 if ((*i)->backend == backend &&
1432 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1440 EngineControl::State
1441 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1443 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1446 if (backend->use_separate_input_and_output_devices ()) {
1447 return get_matching_state (backend_combo.get_active_text(),
1448 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1449 input_device_combo.get_active_text(),
1450 output_device_combo.get_active_text());
1452 return get_matching_state (backend_combo.get_active_text(),
1453 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1454 device_combo.get_active_text());
1458 return get_matching_state (backend_combo.get_active_text(),
1460 device_combo.get_active_text());
1463 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1464 const EngineControl::State& state2)
1466 if (state1->backend == state2->backend &&
1467 state1->driver == state2->driver &&
1468 state1->device == state2->device &&
1469 state1->input_device == state2->input_device &&
1470 state1->output_device == state2->output_device) {
1476 EngineControl::State
1477 EngineControl::save_state ()
1481 if (!_have_control) {
1482 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1486 state.reset(new StateStruct);
1487 state->backend = get_backend ();
1489 state.reset(new StateStruct);
1490 store_state (state);
1493 for (StateList::iterator i = states.begin(); i != states.end();) {
1494 if (equivalent_states (*i, state)) {
1495 i = states.erase(i);
1501 states.push_back (state);
1507 EngineControl::store_state (State state)
1509 state->backend = get_backend ();
1510 state->driver = get_driver ();
1511 state->device = get_device_name ();
1512 state->input_device = get_input_device_name ();
1513 state->output_device = get_output_device_name ();
1514 state->sample_rate = get_rate ();
1515 state->buffer_size = get_buffer_size ();
1516 state->input_latency = get_input_latency ();
1517 state->output_latency = get_output_latency ();
1518 state->input_channels = get_input_channels ();
1519 state->output_channels = get_output_channels ();
1520 state->midi_option = get_midi_option ();
1521 state->midi_devices = _midi_devices;
1525 EngineControl::maybe_display_saved_state ()
1527 if (!_have_control) {
1531 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1534 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1536 if (!_desired_sample_rate) {
1537 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1539 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1540 /* call this explicitly because we're ignoring changes to
1541 the controls at this point.
1543 show_buffer_duration ();
1544 input_latency.set_value (state->input_latency);
1545 output_latency.set_value (state->output_latency);
1547 if (!state->midi_option.empty()) {
1548 midi_option_combo.set_active_text (state->midi_option);
1549 _midi_devices = state->midi_devices;
1555 EngineControl::get_state ()
1557 LocaleGuard lg (X_("C"));
1559 XMLNode* root = new XMLNode ("AudioMIDISetup");
1562 if (!states.empty()) {
1563 XMLNode* state_nodes = new XMLNode ("EngineStates");
1565 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1567 XMLNode* node = new XMLNode ("State");
1569 node->add_property ("backend", (*i)->backend);
1570 node->add_property ("driver", (*i)->driver);
1571 node->add_property ("device", (*i)->device);
1572 node->add_property ("input-device", (*i)->input_device);
1573 node->add_property ("output-device", (*i)->output_device);
1574 node->add_property ("sample-rate", (*i)->sample_rate);
1575 node->add_property ("buffer-size", (*i)->buffer_size);
1576 node->add_property ("input-latency", (*i)->input_latency);
1577 node->add_property ("output-latency", (*i)->output_latency);
1578 node->add_property ("input-channels", (*i)->input_channels);
1579 node->add_property ("output-channels", (*i)->output_channels);
1580 node->add_property ("active", (*i)->active ? "yes" : "no");
1581 node->add_property ("midi-option", (*i)->midi_option);
1583 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1584 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1585 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1586 midi_device_stuff->add_property (X_("name"), (*p)->name);
1587 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1588 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1589 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1590 midi_devices->add_child_nocopy (*midi_device_stuff);
1592 node->add_child_nocopy (*midi_devices);
1594 state_nodes->add_child_nocopy (*node);
1597 root->add_child_nocopy (*state_nodes);
1604 EngineControl::set_default_state ()
1606 vector<string> backend_names;
1607 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1609 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1610 backend_names.push_back ((*b)->name);
1612 backend_combo.set_active_text (backend_names.front());
1614 // We could set default backends per platform etc here
1620 EngineControl::set_state (const XMLNode& root)
1622 XMLNodeList clist, cclist;
1623 XMLNodeConstIterator citer, cciter;
1625 XMLNode* grandchild;
1626 XMLProperty* prop = NULL;
1628 fprintf (stderr, "EngineControl::set_state\n");
1630 if (root.name() != "AudioMIDISetup") {
1634 clist = root.children();
1638 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1642 if (child->name() != "EngineStates") {
1646 cclist = child->children();
1648 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1649 State state (new StateStruct);
1651 grandchild = *cciter;
1653 if (grandchild->name() != "State") {
1657 if ((prop = grandchild->property ("backend")) == 0) {
1660 state->backend = prop->value ();
1662 if ((prop = grandchild->property ("driver")) == 0) {
1665 state->driver = prop->value ();
1667 if ((prop = grandchild->property ("device")) == 0) {
1670 state->device = prop->value ();
1672 if ((prop = grandchild->property ("input-device")) == 0) {
1675 state->input_device = prop->value ();
1677 if ((prop = grandchild->property ("output-device")) == 0) {
1680 state->output_device = prop->value ();
1682 if ((prop = grandchild->property ("sample-rate")) == 0) {
1685 state->sample_rate = atof (prop->value ());
1687 if ((prop = grandchild->property ("buffer-size")) == 0) {
1690 state->buffer_size = atoi (prop->value ());
1692 if ((prop = grandchild->property ("input-latency")) == 0) {
1695 state->input_latency = atoi (prop->value ());
1697 if ((prop = grandchild->property ("output-latency")) == 0) {
1700 state->output_latency = atoi (prop->value ());
1702 if ((prop = grandchild->property ("input-channels")) == 0) {
1705 state->input_channels = atoi (prop->value ());
1707 if ((prop = grandchild->property ("output-channels")) == 0) {
1710 state->output_channels = atoi (prop->value ());
1712 if ((prop = grandchild->property ("active")) == 0) {
1715 state->active = string_is_affirmative (prop->value ());
1717 if ((prop = grandchild->property ("midi-option")) == 0) {
1720 state->midi_option = prop->value ();
1722 state->midi_devices.clear();
1724 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1725 const XMLNodeList mnc = midinode->children();
1726 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1727 if ((*n)->property (X_("name")) == 0
1728 || (*n)->property (X_("enabled")) == 0
1729 || (*n)->property (X_("input-latency")) == 0
1730 || (*n)->property (X_("output-latency")) == 0
1735 MidiDeviceSettings ptr (new MidiDeviceSetting(
1736 (*n)->property (X_("name"))->value (),
1737 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1738 atoi ((*n)->property (X_("input-latency"))->value ()),
1739 atoi ((*n)->property (X_("output-latency"))->value ())
1741 state->midi_devices.push_back (ptr);
1746 /* remove accumulated duplicates (due to bug in ealier version)
1747 * this can be removed again before release
1749 for (StateList::iterator i = states.begin(); i != states.end();) {
1750 if ((*i)->backend == state->backend &&
1751 (*i)->driver == state->driver &&
1752 (*i)->device == state->device) {
1753 i = states.erase(i);
1760 states.push_back (state);
1764 /* now see if there was an active state and switch the setup to it */
1766 // purge states of backend that are not available in this built
1767 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1768 vector<std::string> backend_names;
1770 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1771 backend_names.push_back((*i)->name);
1773 for (StateList::iterator i = states.begin(); i != states.end();) {
1774 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1775 i = states.erase(i);
1781 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1784 return set_current_state (*i);
1791 EngineControl::set_current_state (const State& state)
1793 DEBUG_ECONTROL ("set_current_state");
1795 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1797 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1798 state->backend, "ardour", ""))) {
1799 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1800 // this shouldn't happen as the invalid backend names should have been
1801 // removed from the list of states.
1805 // now reflect the change in the backend in the GUI so backend_changed will
1806 // do the right thing
1807 backend_combo.set_active_text (state->backend);
1809 if (!state->driver.empty ()) {
1810 if (!backend->requires_driver_selection ()) {
1811 DEBUG_ECONTROL ("Backend should require driver selection");
1812 // A backend has changed from having driver selection to not having
1813 // it or someone has been manually editing a config file and messed
1818 if (backend->set_driver (state->driver) != 0) {
1819 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1820 // Driver names for a backend have changed and the name in the
1821 // config file is now invalid or support for driver is no longer
1822 // included in the backend
1825 // no need to set the driver_combo as backend_changed will use
1826 // backend->driver_name to set the active driver
1829 if (!state->device.empty ()) {
1830 if (backend->set_device_name (state->device) != 0) {
1832 string_compose ("Unable to set device name %1", state->device));
1833 // device is no longer available on the system
1836 // no need to set active device as it will be picked up in
1837 // via backend_changed ()/set_device_popdown_strings
1840 // backend supports separate input/output devices
1841 if (backend->set_input_device_name (state->input_device) != 0) {
1842 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1843 state->input_device));
1844 // input device is no longer available on the system
1848 if (backend->set_output_device_name (state->output_device) != 0) {
1849 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1850 state->input_device));
1851 // output device is no longer available on the system
1854 // no need to set active devices as it will be picked up in via
1855 // backend_changed ()/set_*_device_popdown_strings
1860 // Now restore the state of the rest of the controls
1862 // We don't use a SignalBlocker as set_current_state is currently only
1863 // called from set_state before any signals are connected. If at some point
1864 // a more general named state mechanism is implemented and
1865 // set_current_state is called while signals are connected then a
1866 // SignalBlocker will need to be instantiated before setting these.
1868 device_combo.set_active_text (state->device);
1869 input_device_combo.set_active_text (state->input_device);
1870 output_device_combo.set_active_text (state->output_device);
1871 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1872 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1873 input_latency.set_value (state->input_latency);
1874 output_latency.set_value (state->output_latency);
1875 midi_option_combo.set_active_text (state->midi_option);
1880 EngineControl::push_state_to_backend (bool start)
1882 DEBUG_ECONTROL ("push_state_to_backend");
1883 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1889 /* figure out what is going to change */
1891 bool restart_required = false;
1892 bool was_running = ARDOUR::AudioEngine::instance()->running();
1893 bool change_driver = false;
1894 bool change_device = false;
1895 bool change_rate = false;
1896 bool change_bufsize = false;
1897 bool change_latency = false;
1898 bool change_channels = false;
1899 bool change_midi = false;
1901 uint32_t ochan = get_output_channels ();
1902 uint32_t ichan = get_input_channels ();
1904 if (_have_control) {
1906 if (started_at_least_once) {
1908 /* we can control the backend */
1910 if (backend->requires_driver_selection()) {
1911 if (get_driver() != backend->driver_name()) {
1912 change_driver = true;
1916 if (backend->use_separate_input_and_output_devices()) {
1917 if (get_input_device_name() != backend->input_device_name()) {
1918 change_device = true;
1920 if (get_output_device_name() != backend->output_device_name()) {
1921 change_device = true;
1924 if (get_device_name() != backend->device_name()) {
1925 change_device = true;
1929 if (queue_device_changed) {
1930 change_device = true;
1933 if (get_rate() != backend->sample_rate()) {
1937 if (get_buffer_size() != backend->buffer_size()) {
1938 change_bufsize = true;
1941 if (get_midi_option() != backend->midi_option()) {
1945 /* zero-requested channels means "all available" */
1948 ichan = backend->input_channels();
1952 ochan = backend->output_channels();
1955 if (ichan != backend->input_channels()) {
1956 change_channels = true;
1959 if (ochan != backend->output_channels()) {
1960 change_channels = true;
1963 if (get_input_latency() != backend->systemic_input_latency() ||
1964 get_output_latency() != backend->systemic_output_latency()) {
1965 change_latency = true;
1968 /* backend never started, so we have to force a group
1971 change_device = true;
1972 if (backend->requires_driver_selection()) {
1973 change_driver = true;
1976 change_bufsize = true;
1977 change_channels = true;
1978 change_latency = true;
1984 /* we have no control over the backend, meaning that we can
1985 * only possibly change sample rate and buffer size.
1989 if (get_rate() != backend->sample_rate()) {
1990 change_bufsize = true;
1993 if (get_buffer_size() != backend->buffer_size()) {
1994 change_bufsize = true;
1998 queue_device_changed = false;
2000 if (!_have_control) {
2002 /* We do not have control over the backend, so the best we can
2003 * do is try to change the sample rate and/or bufsize and get
2007 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2011 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2016 backend->set_sample_rate (get_rate());
2019 if (change_bufsize) {
2020 backend->set_buffer_size (get_buffer_size());
2024 if (ARDOUR::AudioEngine::instance()->start ()) {
2025 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2035 /* determine if we need to stop the backend before changing parameters */
2037 if (change_driver || change_device || change_channels || change_latency ||
2038 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2040 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2041 restart_required = true;
2043 restart_required = false;
2048 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2049 /* no changes in any parameters that absolutely require a
2050 * restart, so check those that might be changeable without a
2054 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2055 /* can't do this while running ... */
2056 restart_required = true;
2059 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2060 /* can't do this while running ... */
2061 restart_required = true;
2067 if (restart_required) {
2068 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2075 if (change_driver && backend->set_driver (get_driver())) {
2076 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2079 if (backend->use_separate_input_and_output_devices()) {
2080 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2081 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2084 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2085 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2089 if (change_device && backend->set_device_name (get_device_name())) {
2090 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2094 if (change_rate && backend->set_sample_rate (get_rate())) {
2095 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2098 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2099 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2103 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2104 if (backend->set_input_channels (get_input_channels())) {
2105 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2108 if (backend->set_output_channels (get_output_channels())) {
2109 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2113 if (change_latency) {
2114 if (backend->set_systemic_input_latency (get_input_latency())) {
2115 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2118 if (backend->set_systemic_output_latency (get_output_latency())) {
2119 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2125 backend->set_midi_option (get_midi_option());
2129 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2130 if (_measure_midi) {
2131 if (*p == _measure_midi) {
2132 backend->set_midi_device_enabled ((*p)->name, true);
2134 backend->set_midi_device_enabled ((*p)->name, false);
2138 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2139 if (backend->can_set_systemic_midi_latencies()) {
2140 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2141 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2146 if (start || (was_running && restart_required)) {
2147 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2158 EngineControl::post_push ()
2160 /* get a pointer to the current state object, creating one if
2164 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2167 state = save_state ();
2175 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2176 (*i)->active = false;
2179 /* mark this one active (to be used next time the dialog is
2183 state->active = true;
2185 if (_have_control) { // XXX
2186 manage_control_app_sensitivity ();
2189 /* schedule a redisplay of MIDI ports */
2190 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2195 EngineControl::get_rate () const
2197 float r = atof (sample_rate_combo.get_active_text ());
2198 /* the string may have been translated with an abbreviation for
2199 * thousands, so use a crude heuristic to fix this.
2209 EngineControl::get_buffer_size () const
2211 string txt = buffer_size_combo.get_active_text ();
2214 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2215 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2216 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2224 EngineControl::get_midi_option () const
2226 return midi_option_combo.get_active_text();
2230 EngineControl::get_input_channels() const
2232 if (ARDOUR::Profile->get_mixbus()) {
2233 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2234 if (!backend) return 0;
2235 return backend->input_channels();
2237 return (uint32_t) input_channels_adjustment.get_value();
2241 EngineControl::get_output_channels() const
2243 if (ARDOUR::Profile->get_mixbus()) {
2244 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2245 if (!backend) return 0;
2246 return backend->input_channels();
2248 return (uint32_t) output_channels_adjustment.get_value();
2252 EngineControl::get_input_latency() const
2254 return (uint32_t) input_latency_adjustment.get_value();
2258 EngineControl::get_output_latency() const
2260 return (uint32_t) output_latency_adjustment.get_value();
2264 EngineControl::get_backend () const
2266 return backend_combo.get_active_text ();
2270 EngineControl::get_driver () const
2272 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2273 return driver_combo.get_active_text ();
2280 EngineControl::get_device_name () const
2282 return device_combo.get_active_text ();
2286 EngineControl::get_input_device_name () const
2288 return input_device_combo.get_active_text ();
2292 EngineControl::get_output_device_name () const
2294 return output_device_combo.get_active_text ();
2298 EngineControl::control_app_button_clicked ()
2300 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2306 backend->launch_control_app ();
2310 EngineControl::manage_control_app_sensitivity ()
2312 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2318 string appname = backend->control_app_name();
2320 if (appname.empty()) {
2321 control_app_button.set_sensitive (false);
2323 control_app_button.set_sensitive (true);
2328 EngineControl::set_desired_sample_rate (uint32_t sr)
2330 _desired_sample_rate = sr;
2335 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2337 if (page_num == 0) {
2338 cancel_button->set_sensitive (true);
2339 ok_button->set_sensitive (true);
2340 apply_button->set_sensitive (true);
2341 _measure_midi.reset();
2343 cancel_button->set_sensitive (false);
2344 ok_button->set_sensitive (false);
2345 apply_button->set_sensitive (false);
2348 if (page_num == midi_tab) {
2350 refresh_midi_display ();
2353 if (page_num == latency_tab) {
2356 if (ARDOUR::AudioEngine::instance()->running()) {
2357 // TODO - mark as 'stopped for latency
2358 ARDOUR_UI::instance()->disconnect_from_engine ();
2362 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2364 /* save any existing latency values */
2366 uint32_t il = (uint32_t) input_latency.get_value ();
2367 uint32_t ol = (uint32_t) input_latency.get_value ();
2369 /* reset to zero so that our new test instance
2370 will be clean of any existing latency measures.
2372 NB. this should really be done by the backend
2373 when stated for latency measurement.
2376 input_latency.set_value (0);
2377 output_latency.set_value (0);
2379 push_state_to_backend (false);
2383 input_latency.set_value (il);
2384 output_latency.set_value (ol);
2387 // This should be done in push_state_to_backend()
2388 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2389 disable_latency_tab ();
2392 enable_latency_tab ();
2396 end_latency_detection ();
2397 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2402 /* latency measurement */
2405 EngineControl::check_audio_latency_measurement ()
2407 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2409 if (mtdm->resolve () < 0) {
2410 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2414 if (mtdm->err () > 0.3) {
2420 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2422 if (sample_rate == 0) {
2423 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2424 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2428 int frames_total = mtdm->del();
2429 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2431 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2432 _("Detected roundtrip latency: "),
2433 frames_total, frames_total * 1000.0f/sample_rate,
2434 _("Systemic latency: "),
2435 extra, extra * 1000.0f/sample_rate);
2439 if (mtdm->err () > 0.2) {
2441 strcat (buf, _("(signal detection error)"));
2447 strcat (buf, _("(inverted - bad wiring)"));
2451 lm_results.set_markup (string_compose (results_markup, buf));
2454 have_lm_results = true;
2455 end_latency_detection ();
2456 lm_use_button.set_sensitive (true);
2464 EngineControl::check_midi_latency_measurement ()
2466 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2468 if (!mididm->have_signal () || mididm->latency () == 0) {
2469 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2474 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2476 if (sample_rate == 0) {
2477 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2478 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2482 ARDOUR::framecnt_t frames_total = mididm->latency();
2483 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2484 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2485 _("Detected roundtrip latency: "),
2486 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2487 _("Systemic latency: "),
2488 extra, extra * 1000.0f / sample_rate);
2492 if (!mididm->ok ()) {
2494 strcat (buf, _("(averaging)"));
2498 if (mididm->deviation () > 50.0) {
2500 strcat (buf, _("(too large jitter)"));
2502 } else if (mididm->deviation () > 10.0) {
2504 strcat (buf, _("(large jitter)"));
2508 have_lm_results = true;
2509 end_latency_detection ();
2510 lm_use_button.set_sensitive (true);
2511 lm_results.set_markup (string_compose (results_markup, buf));
2513 } else if (mididm->processed () > 400) {
2514 have_lm_results = false;
2515 end_latency_detection ();
2516 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2520 lm_results.set_markup (string_compose (results_markup, buf));
2526 EngineControl::start_latency_detection ()
2528 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2529 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2531 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2532 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2533 if (_measure_midi) {
2534 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2536 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2538 lm_measure_label.set_text (_("Cancel"));
2539 have_lm_results = false;
2540 lm_use_button.set_sensitive (false);
2541 lm_input_channel_combo.set_sensitive (false);
2542 lm_output_channel_combo.set_sensitive (false);
2548 EngineControl::end_latency_detection ()
2550 latency_timeout.disconnect ();
2551 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2552 lm_measure_label.set_text (_("Measure"));
2553 if (!have_lm_results) {
2554 lm_use_button.set_sensitive (false);
2556 lm_input_channel_combo.set_sensitive (true);
2557 lm_output_channel_combo.set_sensitive (true);
2562 EngineControl::latency_button_clicked ()
2565 start_latency_detection ();
2567 end_latency_detection ();
2572 EngineControl::use_latency_button_clicked ()
2574 if (_measure_midi) {
2575 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2579 ARDOUR::framecnt_t frames_total = mididm->latency();
2580 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2581 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2582 _measure_midi->input_latency = one_way;
2583 _measure_midi->output_latency = one_way;
2584 notebook.set_current_page (midi_tab);
2586 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2592 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2593 one_way = std::max (0., one_way);
2595 input_latency_adjustment.set_value (one_way);
2596 output_latency_adjustment.set_value (one_way);
2598 /* back to settings page */
2599 notebook.set_current_page (0);
2605 EngineControl::on_delete_event (GdkEventAny* ev)
2607 if (notebook.get_current_page() == 2) {
2608 /* currently on latency tab - be sure to clean up */
2609 end_latency_detection ();
2611 return ArdourDialog::on_delete_event (ev);
2615 EngineControl::engine_running ()
2617 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2620 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2621 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2623 buffer_size_combo.set_sensitive (true);
2624 sample_rate_combo.set_sensitive (true);
2626 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2627 connect_disconnect_button.show();
2629 started_at_least_once = true;
2630 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2634 EngineControl::engine_stopped ()
2636 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2639 buffer_size_combo.set_sensitive (false);
2640 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2641 connect_disconnect_button.show();
2643 sample_rate_combo.set_sensitive (true);
2644 buffer_size_combo.set_sensitive (true);
2645 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2649 EngineControl::device_list_changed ()
2651 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2653 midi_option_changed();
2657 EngineControl::connect_disconnect_click()
2659 if (ARDOUR::AudioEngine::instance()->running()) {
2660 ARDOUR_UI::instance()->disconnect_from_engine ();
2662 ARDOUR_UI::instance()->reconnect_to_engine ();
2667 EngineControl::calibrate_audio_latency ()
2669 _measure_midi.reset ();
2670 have_lm_results = false;
2671 lm_use_button.set_sensitive (false);
2672 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2673 notebook.set_current_page (latency_tab);
2677 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2680 have_lm_results = false;
2681 lm_use_button.set_sensitive (false);
2682 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2683 notebook.set_current_page (latency_tab);
2687 EngineControl::configure_midi_devices ()
2689 notebook.set_current_page (midi_tab);