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 set_state (*audio_setup);
289 if (backend_combo.get_active_text().empty()) {
290 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
291 backend_combo.set_active_text (backend_names.front());
296 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
297 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
298 backend_combo.set_active_text (backend_names.back());
299 /* ignore: don't save state */
300 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
304 connect_changed_signals ();
306 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
308 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
309 connect_disconnect_button.set_no_show_all();
314 EngineControl::connect_changed_signals ()
316 backend_combo_connection = backend_combo.signal_changed ().connect (
317 sigc::mem_fun (*this, &EngineControl::backend_changed));
318 driver_combo_connection = driver_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::driver_changed));
320 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
322 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
323 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
324 device_combo_connection = device_combo.signal_changed ().connect (
325 sigc::mem_fun (*this, &EngineControl::device_changed));
326 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
327 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
329 input_device_combo_connection = input_device_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::input_device_changed));
331 output_device_combo_connection = output_device_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::output_device_changed));
334 input_latency_connection = input_latency.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::parameter_changed));
336 output_latency_connection = output_latency.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::parameter_changed));
338 input_channels_connection = input_channels.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::parameter_changed));
340 output_channels_connection = output_channels.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::parameter_changed));
345 EngineControl::block_changed_signals ()
347 if (block_signals++ == 0) {
348 DEBUG_ECONTROL ("Blocking changed signals");
349 backend_combo_connection.block ();
350 driver_combo_connection.block ();
351 sample_rate_combo_connection.block ();
352 buffer_size_combo_connection.block ();
353 device_combo_connection.block ();
354 input_device_combo_connection.block ();
355 output_device_combo_connection.block ();
356 midi_option_combo_connection.block ();
357 input_latency_connection.block ();
358 output_latency_connection.block ();
359 input_channels_connection.block ();
360 output_channels_connection.block ();
365 EngineControl::unblock_changed_signals ()
367 if (--block_signals == 0) {
368 DEBUG_ECONTROL ("Unblocking changed signals");
369 backend_combo_connection.unblock ();
370 driver_combo_connection.unblock ();
371 sample_rate_combo_connection.unblock ();
372 buffer_size_combo_connection.unblock ();
373 device_combo_connection.unblock ();
374 input_device_combo_connection.unblock ();
375 output_device_combo_connection.unblock ();
376 midi_option_combo_connection.unblock ();
377 input_latency_connection.unblock ();
378 output_latency_connection.unblock ();
379 input_channels_connection.unblock ();
380 output_channels_connection.unblock ();
384 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
385 const std::string& reason)
386 : ec (engine_control)
389 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
390 ec.block_changed_signals ();
393 EngineControl::SignalBlocker::~SignalBlocker ()
395 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
396 ec.unblock_changed_signals ();
400 EngineControl::on_show ()
402 ArdourDialog::on_show ();
403 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
404 // re-check _have_control (jackd running) see #6041
408 ok_button->grab_focus();
412 EngineControl::on_response (int response_id)
414 ArdourDialog::on_response (response_id);
416 switch (response_id) {
418 push_state_to_backend (true);
421 #ifdef PLATFORM_WINDOWS
422 // For some reason we don't understand, 'hide()'
423 // needs to get called first in Windows
426 // But if there's no session open, this can produce
427 // a long gap when nothing appears to be happening.
428 // Let's show the splash image while we're waiting.
429 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
430 if ( ARDOUR_UI::instance() ) {
431 if ( !ARDOUR_UI::instance()->session_loaded ) {
432 ARDOUR_UI::instance()->show_splash();
436 push_state_to_backend (true);
439 push_state_to_backend (true);
443 case RESPONSE_DELETE_EVENT:
446 ev.type = GDK_BUTTON_PRESS;
448 on_delete_event ((GdkEventAny*) &ev);
457 EngineControl::build_notebook ()
460 AttachOptions xopt = AttachOptions (FILL|EXPAND);
462 /* clear the table */
464 Gtkmm2ext::container_clear (basic_vbox);
465 Gtkmm2ext::container_clear (basic_packer);
467 if (control_app_button.get_parent()) {
468 control_app_button.get_parent()->remove (control_app_button);
471 label = manage (left_aligned_label (_("Audio System:")));
472 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
473 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
475 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
476 lm_button_audio.set_name ("generic button");
477 lm_button_audio.set_can_focus(true);
480 build_full_control_notebook ();
482 build_no_control_notebook ();
485 basic_vbox.pack_start (basic_hbox, false, false);
488 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
489 basic_vbox.show_all ();
494 EngineControl::build_full_control_notebook ()
496 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
499 using namespace Notebook_Helpers;
501 vector<string> strings;
502 AttachOptions xopt = AttachOptions (FILL|EXPAND);
503 int row = 1; // row zero == backend combo
505 /* start packing it up */
507 if (backend->requires_driver_selection()) {
508 label = manage (left_aligned_label (_("Driver:")));
509 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
510 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
514 if (backend->use_separate_input_and_output_devices()) {
515 label = manage (left_aligned_label (_("Input Device:")));
516 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
517 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
519 label = manage (left_aligned_label (_("Output Device:")));
520 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
521 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
523 // reset so it isn't used in state comparisons
524 device_combo.set_active_text ("");
526 label = manage (left_aligned_label (_("Device:")));
527 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
528 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
530 // reset these so they don't get used in state comparisons
531 input_device_combo.set_active_text ("");
532 output_device_combo.set_active_text ("");
535 label = manage (left_aligned_label (_("Sample rate:")));
536 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
537 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
541 label = manage (left_aligned_label (_("Buffer size:")));
542 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
543 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
544 buffer_size_duration_label.set_alignment (0.0); /* left-align */
545 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
547 /* button spans 2 rows */
549 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
552 input_channels.set_name ("InputChannels");
553 input_channels.set_flags (Gtk::CAN_FOCUS);
554 input_channels.set_digits (0);
555 input_channels.set_wrap (false);
556 output_channels.set_editable (true);
558 if (!ARDOUR::Profile->get_mixbus()) {
559 label = manage (left_aligned_label (_("Input Channels:")));
560 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
561 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
565 output_channels.set_name ("OutputChannels");
566 output_channels.set_flags (Gtk::CAN_FOCUS);
567 output_channels.set_digits (0);
568 output_channels.set_wrap (false);
569 output_channels.set_editable (true);
571 if (!ARDOUR::Profile->get_mixbus()) {
572 label = manage (left_aligned_label (_("Output Channels:")));
573 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
574 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
578 input_latency.set_name ("InputLatency");
579 input_latency.set_flags (Gtk::CAN_FOCUS);
580 input_latency.set_digits (0);
581 input_latency.set_wrap (false);
582 input_latency.set_editable (true);
584 label = manage (left_aligned_label (_("Hardware input latency:")));
585 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
586 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
587 label = manage (left_aligned_label (_("samples")));
588 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
591 output_latency.set_name ("OutputLatency");
592 output_latency.set_flags (Gtk::CAN_FOCUS);
593 output_latency.set_digits (0);
594 output_latency.set_wrap (false);
595 output_latency.set_editable (true);
597 label = manage (left_aligned_label (_("Hardware output latency:")));
598 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
599 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
600 label = manage (left_aligned_label (_("samples")));
601 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
603 /* button spans 2 rows */
605 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
608 label = manage (left_aligned_label (_("MIDI System:")));
609 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
610 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
611 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
616 EngineControl::build_no_control_notebook ()
618 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
621 using namespace Notebook_Helpers;
623 vector<string> strings;
624 AttachOptions xopt = AttachOptions (FILL|EXPAND);
625 int row = 1; // row zero == backend combo
626 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
628 label = manage (new Label);
629 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
630 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
633 if (backend->can_change_sample_rate_when_running()) {
634 label = manage (left_aligned_label (_("Sample rate:")));
635 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
636 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
640 if (backend->can_change_buffer_size_when_running()) {
641 label = manage (left_aligned_label (_("Buffer size:")));
642 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
643 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
644 buffer_size_duration_label.set_alignment (0.0); /* left-align */
645 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
649 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
653 EngineControl::~EngineControl ()
655 ignore_changes = true;
659 EngineControl::disable_latency_tab ()
661 vector<string> empty;
662 set_popdown_strings (lm_output_channel_combo, empty);
663 set_popdown_strings (lm_input_channel_combo, empty);
664 lm_measure_button.set_sensitive (false);
665 lm_use_button.set_sensitive (false);
669 EngineControl::enable_latency_tab ()
671 vector<string> outputs;
672 vector<string> inputs;
674 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
675 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
676 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
678 if (!ARDOUR::AudioEngine::instance()->running()) {
679 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
680 notebook.set_current_page (0);
684 else if (inputs.empty() || outputs.empty()) {
685 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
686 notebook.set_current_page (0);
691 lm_back_button_signal.disconnect();
693 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
696 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
700 set_popdown_strings (lm_output_channel_combo, outputs);
701 lm_output_channel_combo.set_active_text (outputs.front());
702 lm_output_channel_combo.set_sensitive (true);
704 set_popdown_strings (lm_input_channel_combo, inputs);
705 lm_input_channel_combo.set_active_text (inputs.front());
706 lm_input_channel_combo.set_sensitive (true);
708 lm_measure_button.set_sensitive (true);
712 EngineControl::setup_midi_tab_for_backend ()
714 string backend = backend_combo.get_active_text ();
716 Gtkmm2ext::container_clear (midi_vbox);
718 midi_vbox.set_border_width (12);
719 midi_device_table.set_border_width (12);
721 if (backend == "JACK") {
722 setup_midi_tab_for_jack ();
725 midi_vbox.pack_start (midi_device_table, true, true);
726 midi_vbox.pack_start (midi_back_button, false, false);
727 midi_vbox.show_all ();
731 EngineControl::setup_midi_tab_for_jack ()
736 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
738 device->input_latency = a->get_value();
740 device->output_latency = a->get_value();
745 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
746 b->set_active (!b->get_active());
747 device->enabled = b->get_active();
748 refresh_midi_display(device->name);
752 EngineControl::refresh_midi_display (std::string focus)
754 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
758 AttachOptions xopt = AttachOptions (FILL|EXPAND);
761 Gtkmm2ext::container_clear (midi_device_table);
763 midi_device_table.set_spacings (6);
765 l = manage (new Label);
766 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
767 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
768 l->set_alignment (0.5, 0.5);
772 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
773 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
774 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
775 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
777 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
778 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
779 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
780 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
783 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
788 bool enabled = (*p)->enabled;
790 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
791 m->set_name ("midi device");
792 m->set_can_focus (Gtk::CAN_FOCUS);
793 m->add_events (Gdk::BUTTON_RELEASE_MASK);
794 m->set_active (enabled);
795 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
796 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
797 if ((*p)->name == focus) {
801 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
802 s = manage (new Gtk::SpinButton (*a));
803 a->set_value ((*p)->input_latency);
804 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
805 s->set_sensitive (_can_set_midi_latencies && enabled);
806 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
808 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
809 s = manage (new Gtk::SpinButton (*a));
810 a->set_value ((*p)->output_latency);
811 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
812 s->set_sensitive (_can_set_midi_latencies && enabled);
813 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
815 b = manage (new Button (_("Calibrate")));
816 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
817 b->set_sensitive (_can_set_midi_latencies && enabled);
818 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
825 EngineControl::backend_changed ()
827 SignalBlocker blocker (*this, "backend_changed");
828 string backend_name = backend_combo.get_active_text();
829 boost::shared_ptr<ARDOUR::AudioBackend> backend;
831 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
832 /* eh? setting the backend failed... how ? */
833 /* A: stale config contains a backend that does not exist in current build */
837 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
839 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
842 setup_midi_tab_for_backend ();
843 _midi_devices.clear();
845 if (backend->requires_driver_selection()) {
846 if (set_driver_popdown_strings ()) {
847 driver_combo.set_sensitive (true);
852 driver_combo.set_sensitive (false);
853 /* this will change the device text which will cause a call to
854 * device changed which will set up parameters
859 update_midi_options ();
861 connect_disconnect_button.hide();
863 midi_option_changed();
865 started_at_least_once = false;
867 if (!ignore_changes) {
868 maybe_display_saved_state ();
873 EngineControl::update_midi_options ()
875 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
876 vector<string> midi_options = backend->enumerate_midi_options();
878 if (midi_options.size() == 1) {
879 /* only contains the "none" option */
880 midi_option_combo.set_sensitive (false);
883 set_popdown_strings (midi_option_combo, midi_options);
884 midi_option_combo.set_active_text (midi_options.front());
885 midi_option_combo.set_sensitive (true);
887 midi_option_combo.set_sensitive (false);
893 EngineControl::print_channel_count (Gtk::SpinButton* sb)
895 if (ARDOUR::Profile->get_mixbus()) {
899 uint32_t cnt = (uint32_t) sb->get_value();
901 sb->set_text (_("all available channels"));
904 snprintf (buf, sizeof (buf), "%d", cnt);
910 // @return true if there are drivers available
912 EngineControl::set_driver_popdown_strings ()
914 DEBUG_ECONTROL ("set_driver_popdown_strings");
915 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
916 vector<string> drivers = backend->enumerate_drivers();
918 if (drivers.empty ()) {
919 // This is an error...?
923 string current_driver = backend->driver_name ();
925 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
927 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
930 current_driver = drivers.front ();
933 set_popdown_strings (driver_combo, drivers);
935 string_compose ("driver_combo.set_active_text: %1", current_driver));
936 driver_combo.set_active_text (current_driver);
940 // @return true if there are devices available
942 EngineControl::set_device_popdown_strings ()
944 DEBUG_ECONTROL ("set_device_popdown_strings");
945 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
946 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
948 /* NOTE: Ardour currently does not display the "available" field of the
951 * Doing so would require a different GUI widget than the combo
952 * box/popdown that we currently use, since it has no way to list
953 * items that are not selectable. Something more like a popup menu,
954 * which could have unselectable items, would be appropriate.
957 vector<string> available_devices;
959 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
960 available_devices.push_back (i->name);
964 if (!available_devices.empty()) {
967 string current_device, found_device;
968 current_device = device_combo.get_active_text ();
969 if (current_device == "") {
970 current_device = backend->device_name ();
973 // Make sure that the active text is still relevant for this
974 // device (it might only be relevant to the previous device!!)
975 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
976 if (*i == current_device)
977 found_device = current_device;
979 if (found_device == "")
980 // device has never been set (or was not relevant
981 // for this backend) Let's make sure it's not blank
982 current_device = available_devices.front ();
984 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
985 set_popdown_strings (device_combo, available_devices);
986 DEBUG_ECONTROL (string_compose ("set device_combo active text: %1", current_device));
988 device_combo.set_active_text (current_device);
995 // @return true if there are input devices available
997 EngineControl::set_input_device_popdown_strings ()
999 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1000 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1001 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1003 vector<string> available_devices;
1005 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1006 available_devices.push_back (i->name);
1009 if (!available_devices.empty()) {
1012 string current_device, found_device;
1013 current_device = input_device_combo.get_active_text ();
1014 if (current_device == "") {
1015 current_device = backend->input_device_name ();
1018 // Make sure that the active text is still relevant for this
1019 // device (it might only be relevant to the previous device!!)
1020 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1021 if (*i == current_device)
1022 found_device = current_device;
1024 if (found_device == "")
1025 // device has never been set (or was not relevant
1026 // for this backend) Let's make sure it's not blank
1027 current_device = available_devices.front ();
1029 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1030 set_popdown_strings (input_device_combo, available_devices);
1032 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1033 input_device_combo.set_active_text (current_device);
1041 // @return true if there are output devices available
1043 EngineControl::set_output_device_popdown_strings ()
1045 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1046 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1047 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1049 vector<string> available_devices;
1051 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1052 available_devices.push_back (i->name);
1055 if (!available_devices.empty()) {
1058 string current_device, found_device;
1059 current_device = output_device_combo.get_active_text ();
1060 if (current_device == "") {
1061 current_device = backend->output_device_name ();
1064 // Make sure that the active text is still relevant for this
1065 // device (it might only be relevant to the previous device!!)
1066 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1067 if (*i == current_device)
1068 found_device = current_device;
1070 if (found_device == "")
1071 // device has never been set (or was not relevant
1072 // for this backend) Let's make sure it's not blank
1073 current_device = available_devices.front ();
1075 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1076 set_popdown_strings (output_device_combo, available_devices);
1078 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1079 output_device_combo.set_active_text (current_device);
1088 EngineControl::list_devices ()
1090 DEBUG_ECONTROL ("list_devices");
1091 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1094 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1096 bool devices_available = false;
1098 if (backend->use_separate_input_and_output_devices ()) {
1099 bool input_devices_available = set_input_device_popdown_strings ();
1100 bool output_devices_available = set_output_device_popdown_strings ();
1101 devices_available = input_devices_available || output_devices_available;
1103 devices_available = set_device_popdown_strings ();
1106 if (devices_available) {
1109 input_latency.set_sensitive (true);
1110 output_latency.set_sensitive (true);
1111 input_channels.set_sensitive (true);
1112 output_channels.set_sensitive (true);
1114 ok_button->set_sensitive (true);
1115 apply_button->set_sensitive (true);
1118 device_combo.clear();
1119 input_device_combo.clear();
1120 output_device_combo.clear();
1121 sample_rate_combo.set_sensitive (false);
1122 buffer_size_combo.set_sensitive (false);
1123 input_latency.set_sensitive (false);
1124 output_latency.set_sensitive (false);
1125 input_channels.set_sensitive (false);
1126 output_channels.set_sensitive (false);
1127 if (_have_control) {
1128 ok_button->set_sensitive (false);
1129 apply_button->set_sensitive (false);
1131 ok_button->set_sensitive (true);
1132 apply_button->set_sensitive (true);
1133 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1134 sample_rate_combo.set_sensitive (true);
1136 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1137 buffer_size_combo.set_sensitive (true);
1145 EngineControl::driver_changed ()
1147 SignalBlocker blocker (*this, "driver_changed");
1148 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1151 backend->set_driver (driver_combo.get_active_text());
1154 if (!ignore_changes) {
1155 maybe_display_saved_state ();
1160 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1162 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1163 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1168 if (_have_control) {
1169 sr = backend->available_sample_rates (device_name);
1172 sr.push_back (8000.0f);
1173 sr.push_back (16000.0f);
1174 sr.push_back (32000.0f);
1175 sr.push_back (44100.0f);
1176 sr.push_back (48000.0f);
1177 sr.push_back (88200.0f);
1178 sr.push_back (96000.0f);
1179 sr.push_back (192000.0f);
1180 sr.push_back (384000.0f);
1183 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1184 s.push_back (rate_as_string (*x));
1185 if (*x == _desired_sample_rate) {
1191 sample_rate_combo.set_sensitive (true);
1192 set_popdown_strings (sample_rate_combo, s);
1194 if (desired.empty()) {
1195 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1197 sample_rate_combo.set_active_text (desired);
1201 sample_rate_combo.set_sensitive (false);
1206 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1208 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1209 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1210 vector<uint32_t> bs;
1213 if (_have_control) {
1214 bs = backend->available_buffer_sizes (device_name);
1215 } else if (backend->can_change_buffer_size_when_running()) {
1223 bs.push_back (1024);
1224 bs.push_back (2048);
1225 bs.push_back (4096);
1226 bs.push_back (8192);
1229 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1230 s.push_back (bufsize_as_string (*x));
1234 buffer_size_combo.set_sensitive (true);
1235 set_popdown_strings (buffer_size_combo, s);
1236 buffer_size_combo.set_active_text (s.front());
1238 uint32_t period = backend->buffer_size();
1240 period = backend->default_buffer_size(device_name);
1242 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1243 show_buffer_duration ();
1245 buffer_size_combo.set_sensitive (false);
1250 EngineControl::device_changed ()
1252 SignalBlocker blocker (*this, "device_changed");
1253 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1256 string device_name_in;
1257 string device_name_out; // only used if backend support separate I/O devices
1259 if (backend->use_separate_input_and_output_devices()) {
1260 device_name_in = get_input_device_name ();
1261 device_name_out = get_output_device_name ();
1263 device_name_in = get_device_name ();
1266 /* we set the backend-device to query various device related intormation.
1267 * This has the side effect that backend->device_name() will match
1268 * the device_name and 'change_device' will never be true.
1269 * so work around this by setting...
1271 if (backend->use_separate_input_and_output_devices()) {
1272 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1273 queue_device_changed = true;
1276 if (device_name_in != backend->device_name()) {
1277 queue_device_changed = true;
1281 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1282 if (backend->use_separate_input_and_output_devices()) {
1283 backend->set_input_device_name (device_name_in);
1284 backend->set_output_device_name (device_name_out);
1286 backend->set_device_name(device_name_in);
1290 /* don't allow programmatic change to combos to cause a
1291 recursive call to this method.
1293 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1295 /* backends that support separate devices, need to ignore
1296 * the device-name - and use the devies set above
1298 set_samplerate_popdown_strings (device_name_in);
1299 set_buffersize_popdown_strings (device_name_in);
1300 /* XXX theoretically need to set min + max channel counts here
1303 manage_control_app_sensitivity ();
1306 /* pick up any saved state for this device */
1308 if (!ignore_changes) {
1309 maybe_display_saved_state ();
1314 EngineControl::input_device_changed ()
1316 DEBUG_ECONTROL ("input_device_changed");
1321 EngineControl::output_device_changed ()
1323 DEBUG_ECONTROL ("output_device_changed");
1328 EngineControl::bufsize_as_string (uint32_t sz)
1330 /* Translators: "samples" is always plural here, so no
1331 need for plural+singular forms.
1334 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1339 EngineControl::sample_rate_changed ()
1341 DEBUG_ECONTROL ("sample_rate_changed");
1342 /* reset the strings for buffer size to show the correct msec value
1343 (reflecting the new sample rate).
1346 show_buffer_duration ();
1351 EngineControl::buffer_size_changed ()
1353 DEBUG_ECONTROL ("buffer_size_changed");
1354 show_buffer_duration ();
1358 EngineControl::show_buffer_duration ()
1360 DEBUG_ECONTROL ("show_buffer_duration");
1361 /* buffer sizes - convert from just samples to samples + msecs for
1362 * the displayed string
1365 string bs_text = buffer_size_combo.get_active_text ();
1366 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1367 uint32_t rate = get_rate();
1369 /* Developers: note the hard-coding of a double buffered model
1370 in the (2 * samples) computation of latency. we always start
1371 the audiobackend in this configuration.
1373 /* note to jack1 developers: ardour also always starts the engine
1374 * in async mode (no jack2 --sync option) which adds an extra cycle
1375 * of latency with jack2 (and *3 would be correct)
1376 * The value can also be wrong if jackd is started externally..
1378 * At the time of writing the ALSA backend always uses double-buffering *2,
1379 * The Dummy backend *1, and who knows what ASIO really does :)
1381 * So just display the period size, that's also what
1382 * ARDOUR_UI::update_sample_rate() does for the status bar.
1383 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1384 * but still, that's the buffer period, not [round-trip] latency)
1387 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1388 buffer_size_duration_label.set_text (buf);
1392 EngineControl::midi_option_changed ()
1394 DEBUG_ECONTROL ("midi_option_changed");
1395 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1398 backend->set_midi_option (get_midi_option());
1400 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1402 //_midi_devices.clear(); // TODO merge with state-saved settings..
1403 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1404 std::vector<MidiDeviceSettings> new_devices;
1406 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1407 MidiDeviceSettings mds = find_midi_device (i->name);
1408 if (i->available && !mds) {
1409 uint32_t input_latency = 0;
1410 uint32_t output_latency = 0;
1411 if (_can_set_midi_latencies) {
1412 input_latency = backend->systemic_midi_input_latency (i->name);
1413 output_latency = backend->systemic_midi_output_latency (i->name);
1415 bool enabled = backend->midi_device_enabled (i->name);
1416 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1417 new_devices.push_back (ptr);
1418 } else if (i->available) {
1419 new_devices.push_back (mds);
1422 _midi_devices = new_devices;
1424 if (_midi_devices.empty()) {
1425 midi_devices_button.set_sensitive (false);
1427 midi_devices_button.set_sensitive (true);
1432 EngineControl::parameter_changed ()
1436 EngineControl::State
1437 EngineControl::get_matching_state (
1438 const string& backend,
1439 const string& driver,
1440 const string& device)
1442 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1443 if ((*i)->backend == backend &&
1444 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1452 EngineControl::State
1453 EngineControl::get_matching_state (
1454 const string& backend,
1455 const string& driver,
1456 const string& input_device,
1457 const string& output_device)
1459 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1460 if ((*i)->backend == backend &&
1461 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1469 EngineControl::State
1470 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1472 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1475 if (backend->use_separate_input_and_output_devices ()) {
1476 return get_matching_state (backend_combo.get_active_text(),
1477 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1478 input_device_combo.get_active_text(),
1479 output_device_combo.get_active_text());
1481 return get_matching_state (backend_combo.get_active_text(),
1482 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1483 device_combo.get_active_text());
1487 return get_matching_state (backend_combo.get_active_text(),
1489 device_combo.get_active_text());
1492 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1493 const EngineControl::State& state2)
1495 if (state1->backend == state2->backend &&
1496 state1->driver == state2->driver &&
1497 state1->device == state2->device &&
1498 state1->input_device == state2->input_device &&
1499 state1->output_device == state2->output_device) {
1505 EngineControl::State
1506 EngineControl::save_state ()
1510 if (!_have_control) {
1511 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1515 state.reset(new StateStruct);
1516 state->backend = get_backend ();
1518 state.reset(new StateStruct);
1519 store_state (state);
1522 for (StateList::iterator i = states.begin(); i != states.end();) {
1523 if (equivalent_states (*i, state)) {
1524 i = states.erase(i);
1530 states.push_back (state);
1536 EngineControl::store_state (State state)
1538 state->backend = get_backend ();
1539 state->driver = get_driver ();
1540 state->device = get_device_name ();
1541 state->input_device = get_input_device_name ();
1542 state->output_device = get_output_device_name ();
1543 state->sample_rate = get_rate ();
1544 state->buffer_size = get_buffer_size ();
1545 state->input_latency = get_input_latency ();
1546 state->output_latency = get_output_latency ();
1547 state->input_channels = get_input_channels ();
1548 state->output_channels = get_output_channels ();
1549 state->midi_option = get_midi_option ();
1550 state->midi_devices = _midi_devices;
1554 EngineControl::maybe_display_saved_state ()
1556 if (!_have_control) {
1560 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1563 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1565 if (!_desired_sample_rate) {
1566 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1568 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1569 /* call this explicitly because we're ignoring changes to
1570 the controls at this point.
1572 show_buffer_duration ();
1573 input_latency.set_value (state->input_latency);
1574 output_latency.set_value (state->output_latency);
1576 if (!state->midi_option.empty()) {
1577 midi_option_combo.set_active_text (state->midi_option);
1578 _midi_devices = state->midi_devices;
1584 EngineControl::get_state ()
1586 LocaleGuard lg (X_("C"));
1588 XMLNode* root = new XMLNode ("AudioMIDISetup");
1591 if (!states.empty()) {
1592 XMLNode* state_nodes = new XMLNode ("EngineStates");
1594 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1596 XMLNode* node = new XMLNode ("State");
1598 node->add_property ("backend", (*i)->backend);
1599 node->add_property ("driver", (*i)->driver);
1600 node->add_property ("device", (*i)->device);
1601 node->add_property ("input-device", (*i)->input_device);
1602 node->add_property ("output-device", (*i)->output_device);
1603 node->add_property ("sample-rate", (*i)->sample_rate);
1604 node->add_property ("buffer-size", (*i)->buffer_size);
1605 node->add_property ("input-latency", (*i)->input_latency);
1606 node->add_property ("output-latency", (*i)->output_latency);
1607 node->add_property ("input-channels", (*i)->input_channels);
1608 node->add_property ("output-channels", (*i)->output_channels);
1609 node->add_property ("active", (*i)->active ? "yes" : "no");
1610 node->add_property ("midi-option", (*i)->midi_option);
1612 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1613 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1614 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1615 midi_device_stuff->add_property (X_("name"), (*p)->name);
1616 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1617 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1618 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1619 midi_devices->add_child_nocopy (*midi_device_stuff);
1621 node->add_child_nocopy (*midi_devices);
1623 state_nodes->add_child_nocopy (*node);
1626 root->add_child_nocopy (*state_nodes);
1633 EngineControl::set_state (const XMLNode& root)
1635 XMLNodeList clist, cclist;
1636 XMLNodeConstIterator citer, cciter;
1638 XMLNode* grandchild;
1639 XMLProperty* prop = NULL;
1641 fprintf (stderr, "EngineControl::set_state\n");
1643 if (root.name() != "AudioMIDISetup") {
1647 clist = root.children();
1651 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1655 if (child->name() != "EngineStates") {
1659 cclist = child->children();
1661 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1662 State state (new StateStruct);
1664 grandchild = *cciter;
1666 if (grandchild->name() != "State") {
1670 if ((prop = grandchild->property ("backend")) == 0) {
1673 state->backend = prop->value ();
1675 if ((prop = grandchild->property ("driver")) == 0) {
1678 state->driver = prop->value ();
1680 if ((prop = grandchild->property ("device")) == 0) {
1683 state->device = prop->value ();
1685 if ((prop = grandchild->property ("input-device")) == 0) {
1688 state->input_device = prop->value ();
1690 if ((prop = grandchild->property ("output-device")) == 0) {
1693 state->output_device = prop->value ();
1695 if ((prop = grandchild->property ("sample-rate")) == 0) {
1698 state->sample_rate = atof (prop->value ());
1700 if ((prop = grandchild->property ("buffer-size")) == 0) {
1703 state->buffer_size = atoi (prop->value ());
1705 if ((prop = grandchild->property ("input-latency")) == 0) {
1708 state->input_latency = atoi (prop->value ());
1710 if ((prop = grandchild->property ("output-latency")) == 0) {
1713 state->output_latency = atoi (prop->value ());
1715 if ((prop = grandchild->property ("input-channels")) == 0) {
1718 state->input_channels = atoi (prop->value ());
1720 if ((prop = grandchild->property ("output-channels")) == 0) {
1723 state->output_channels = atoi (prop->value ());
1725 if ((prop = grandchild->property ("active")) == 0) {
1728 state->active = string_is_affirmative (prop->value ());
1730 if ((prop = grandchild->property ("midi-option")) == 0) {
1733 state->midi_option = prop->value ();
1735 state->midi_devices.clear();
1737 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1738 const XMLNodeList mnc = midinode->children();
1739 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1740 if ((*n)->property (X_("name")) == 0
1741 || (*n)->property (X_("enabled")) == 0
1742 || (*n)->property (X_("input-latency")) == 0
1743 || (*n)->property (X_("output-latency")) == 0
1748 MidiDeviceSettings ptr (new MidiDeviceSetting(
1749 (*n)->property (X_("name"))->value (),
1750 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1751 atoi ((*n)->property (X_("input-latency"))->value ()),
1752 atoi ((*n)->property (X_("output-latency"))->value ())
1754 state->midi_devices.push_back (ptr);
1759 /* remove accumulated duplicates (due to bug in ealier version)
1760 * this can be removed again before release
1762 for (StateList::iterator i = states.begin(); i != states.end();) {
1763 if ((*i)->backend == state->backend &&
1764 (*i)->driver == state->driver &&
1765 (*i)->device == state->device) {
1766 i = states.erase(i);
1773 states.push_back (state);
1777 /* now see if there was an active state and switch the setup to it */
1779 // purge states of backend that are not available in this built
1780 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1781 vector<std::string> backend_names;
1783 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1784 backend_names.push_back((*i)->name);
1786 for (StateList::iterator i = states.begin(); i != states.end();) {
1787 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1788 i = states.erase(i);
1794 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1797 set_current_state (*i);
1804 EngineControl::set_current_state (const State& state)
1806 DEBUG_ECONTROL ("set_current_state");
1807 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1808 backend_combo.set_active_text (state->backend);
1809 driver_combo.set_active_text (state->driver);
1812 device_combo.set_active_text (state->device);
1813 input_device_combo.set_active_text (state->input_device);
1814 output_device_combo.set_active_text (state->output_device);
1815 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1816 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1817 input_latency.set_value (state->input_latency);
1818 output_latency.set_value (state->output_latency);
1819 midi_option_combo.set_active_text (state->midi_option);
1823 EngineControl::push_state_to_backend (bool start)
1825 DEBUG_ECONTROL ("push_state_to_backend");
1826 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1832 /* figure out what is going to change */
1834 bool restart_required = false;
1835 bool was_running = ARDOUR::AudioEngine::instance()->running();
1836 bool change_driver = false;
1837 bool change_device = false;
1838 bool change_rate = false;
1839 bool change_bufsize = false;
1840 bool change_latency = false;
1841 bool change_channels = false;
1842 bool change_midi = false;
1844 uint32_t ochan = get_output_channels ();
1845 uint32_t ichan = get_input_channels ();
1847 if (_have_control) {
1849 if (started_at_least_once) {
1851 /* we can control the backend */
1853 if (backend->requires_driver_selection()) {
1854 if (get_driver() != backend->driver_name()) {
1855 change_driver = true;
1859 if (backend->use_separate_input_and_output_devices()) {
1860 if (get_input_device_name() != backend->input_device_name()) {
1861 change_device = true;
1863 if (get_output_device_name() != backend->output_device_name()) {
1864 change_device = true;
1867 if (get_device_name() != backend->device_name()) {
1868 change_device = true;
1872 if (queue_device_changed) {
1873 change_device = true;
1876 if (get_rate() != backend->sample_rate()) {
1880 if (get_buffer_size() != backend->buffer_size()) {
1881 change_bufsize = true;
1884 if (get_midi_option() != backend->midi_option()) {
1888 /* zero-requested channels means "all available" */
1891 ichan = backend->input_channels();
1895 ochan = backend->output_channels();
1898 if (ichan != backend->input_channels()) {
1899 change_channels = true;
1902 if (ochan != backend->output_channels()) {
1903 change_channels = true;
1906 if (get_input_latency() != backend->systemic_input_latency() ||
1907 get_output_latency() != backend->systemic_output_latency()) {
1908 change_latency = true;
1911 /* backend never started, so we have to force a group
1914 change_device = true;
1915 if (backend->requires_driver_selection()) {
1916 change_driver = true;
1919 change_bufsize = true;
1920 change_channels = true;
1921 change_latency = true;
1927 /* we have no control over the backend, meaning that we can
1928 * only possibly change sample rate and buffer size.
1932 if (get_rate() != backend->sample_rate()) {
1933 change_bufsize = true;
1936 if (get_buffer_size() != backend->buffer_size()) {
1937 change_bufsize = true;
1941 queue_device_changed = false;
1943 if (!_have_control) {
1945 /* We do not have control over the backend, so the best we can
1946 * do is try to change the sample rate and/or bufsize and get
1950 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1954 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1959 backend->set_sample_rate (get_rate());
1962 if (change_bufsize) {
1963 backend->set_buffer_size (get_buffer_size());
1967 if (ARDOUR::AudioEngine::instance()->start ()) {
1968 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1978 /* determine if we need to stop the backend before changing parameters */
1980 if (change_driver || change_device || change_channels || change_latency ||
1981 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1983 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1984 restart_required = true;
1986 restart_required = false;
1991 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1992 /* no changes in any parameters that absolutely require a
1993 * restart, so check those that might be changeable without a
1997 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1998 /* can't do this while running ... */
1999 restart_required = true;
2002 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2003 /* can't do this while running ... */
2004 restart_required = true;
2010 if (restart_required) {
2011 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2018 if (change_driver && backend->set_driver (get_driver())) {
2019 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2022 if (backend->use_separate_input_and_output_devices()) {
2023 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2024 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2027 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2028 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2032 if (change_device && backend->set_device_name (get_device_name())) {
2033 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2037 if (change_rate && backend->set_sample_rate (get_rate())) {
2038 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2041 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2042 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2046 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2047 if (backend->set_input_channels (get_input_channels())) {
2048 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2051 if (backend->set_output_channels (get_output_channels())) {
2052 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2056 if (change_latency) {
2057 if (backend->set_systemic_input_latency (get_input_latency())) {
2058 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2061 if (backend->set_systemic_output_latency (get_output_latency())) {
2062 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2068 backend->set_midi_option (get_midi_option());
2072 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2073 if (_measure_midi) {
2074 if (*p == _measure_midi) {
2075 backend->set_midi_device_enabled ((*p)->name, true);
2077 backend->set_midi_device_enabled ((*p)->name, false);
2081 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2082 if (backend->can_set_systemic_midi_latencies()) {
2083 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2084 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2089 if (start || (was_running && restart_required)) {
2090 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2101 EngineControl::post_push ()
2103 /* get a pointer to the current state object, creating one if
2107 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2110 state = save_state ();
2118 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2119 (*i)->active = false;
2122 /* mark this one active (to be used next time the dialog is
2126 state->active = true;
2128 if (_have_control) { // XXX
2129 manage_control_app_sensitivity ();
2132 /* schedule a redisplay of MIDI ports */
2133 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2138 EngineControl::get_rate () const
2140 float r = atof (sample_rate_combo.get_active_text ());
2141 /* the string may have been translated with an abbreviation for
2142 * thousands, so use a crude heuristic to fix this.
2152 EngineControl::get_buffer_size () const
2154 string txt = buffer_size_combo.get_active_text ();
2157 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2158 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2159 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2167 EngineControl::get_midi_option () const
2169 return midi_option_combo.get_active_text();
2173 EngineControl::get_input_channels() const
2175 if (ARDOUR::Profile->get_mixbus()) {
2176 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2177 if (!backend) return 0;
2178 return backend->input_channels();
2180 return (uint32_t) input_channels_adjustment.get_value();
2184 EngineControl::get_output_channels() const
2186 if (ARDOUR::Profile->get_mixbus()) {
2187 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2188 if (!backend) return 0;
2189 return backend->input_channels();
2191 return (uint32_t) output_channels_adjustment.get_value();
2195 EngineControl::get_input_latency() const
2197 return (uint32_t) input_latency_adjustment.get_value();
2201 EngineControl::get_output_latency() const
2203 return (uint32_t) output_latency_adjustment.get_value();
2207 EngineControl::get_backend () const
2209 return backend_combo.get_active_text ();
2213 EngineControl::get_driver () const
2215 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2216 return driver_combo.get_active_text ();
2223 EngineControl::get_device_name () const
2225 return device_combo.get_active_text ();
2229 EngineControl::get_input_device_name () const
2231 return input_device_combo.get_active_text ();
2235 EngineControl::get_output_device_name () const
2237 return output_device_combo.get_active_text ();
2241 EngineControl::control_app_button_clicked ()
2243 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2249 backend->launch_control_app ();
2253 EngineControl::manage_control_app_sensitivity ()
2255 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2261 string appname = backend->control_app_name();
2263 if (appname.empty()) {
2264 control_app_button.set_sensitive (false);
2266 control_app_button.set_sensitive (true);
2271 EngineControl::set_desired_sample_rate (uint32_t sr)
2273 _desired_sample_rate = sr;
2278 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2280 if (page_num == 0) {
2281 cancel_button->set_sensitive (true);
2282 ok_button->set_sensitive (true);
2283 apply_button->set_sensitive (true);
2284 _measure_midi.reset();
2286 cancel_button->set_sensitive (false);
2287 ok_button->set_sensitive (false);
2288 apply_button->set_sensitive (false);
2291 if (page_num == midi_tab) {
2293 refresh_midi_display ();
2296 if (page_num == latency_tab) {
2299 if (ARDOUR::AudioEngine::instance()->running()) {
2300 // TODO - mark as 'stopped for latency
2301 ARDOUR_UI::instance()->disconnect_from_engine ();
2305 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2307 /* save any existing latency values */
2309 uint32_t il = (uint32_t) input_latency.get_value ();
2310 uint32_t ol = (uint32_t) input_latency.get_value ();
2312 /* reset to zero so that our new test instance
2313 will be clean of any existing latency measures.
2315 NB. this should really be done by the backend
2316 when stated for latency measurement.
2319 input_latency.set_value (0);
2320 output_latency.set_value (0);
2322 push_state_to_backend (false);
2326 input_latency.set_value (il);
2327 output_latency.set_value (ol);
2330 // This should be done in push_state_to_backend()
2331 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2332 disable_latency_tab ();
2335 enable_latency_tab ();
2339 end_latency_detection ();
2340 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2345 /* latency measurement */
2348 EngineControl::check_audio_latency_measurement ()
2350 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2352 if (mtdm->resolve () < 0) {
2353 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2357 if (mtdm->err () > 0.3) {
2363 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2365 if (sample_rate == 0) {
2366 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2367 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2371 int frames_total = mtdm->del();
2372 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2374 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2375 _("Detected roundtrip latency: "),
2376 frames_total, frames_total * 1000.0f/sample_rate,
2377 _("Systemic latency: "),
2378 extra, extra * 1000.0f/sample_rate);
2382 if (mtdm->err () > 0.2) {
2384 strcat (buf, _("(signal detection error)"));
2390 strcat (buf, _("(inverted - bad wiring)"));
2394 lm_results.set_markup (string_compose (results_markup, buf));
2397 have_lm_results = true;
2398 end_latency_detection ();
2399 lm_use_button.set_sensitive (true);
2407 EngineControl::check_midi_latency_measurement ()
2409 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2411 if (!mididm->have_signal () || mididm->latency () == 0) {
2412 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2417 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2419 if (sample_rate == 0) {
2420 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2421 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2425 ARDOUR::framecnt_t frames_total = mididm->latency();
2426 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2427 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2428 _("Detected roundtrip latency: "),
2429 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2430 _("Systemic latency: "),
2431 extra, extra * 1000.0f / sample_rate);
2435 if (!mididm->ok ()) {
2437 strcat (buf, _("(averaging)"));
2441 if (mididm->deviation () > 50.0) {
2443 strcat (buf, _("(too large jitter)"));
2445 } else if (mididm->deviation () > 10.0) {
2447 strcat (buf, _("(large jitter)"));
2451 have_lm_results = true;
2452 end_latency_detection ();
2453 lm_use_button.set_sensitive (true);
2454 lm_results.set_markup (string_compose (results_markup, buf));
2456 } else if (mididm->processed () > 400) {
2457 have_lm_results = false;
2458 end_latency_detection ();
2459 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2463 lm_results.set_markup (string_compose (results_markup, buf));
2469 EngineControl::start_latency_detection ()
2471 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2472 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2474 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2475 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2476 if (_measure_midi) {
2477 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2479 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2481 lm_measure_label.set_text (_("Cancel"));
2482 have_lm_results = false;
2483 lm_use_button.set_sensitive (false);
2484 lm_input_channel_combo.set_sensitive (false);
2485 lm_output_channel_combo.set_sensitive (false);
2491 EngineControl::end_latency_detection ()
2493 latency_timeout.disconnect ();
2494 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2495 lm_measure_label.set_text (_("Measure"));
2496 if (!have_lm_results) {
2497 lm_use_button.set_sensitive (false);
2499 lm_input_channel_combo.set_sensitive (true);
2500 lm_output_channel_combo.set_sensitive (true);
2505 EngineControl::latency_button_clicked ()
2508 start_latency_detection ();
2510 end_latency_detection ();
2515 EngineControl::use_latency_button_clicked ()
2517 if (_measure_midi) {
2518 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2522 ARDOUR::framecnt_t frames_total = mididm->latency();
2523 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2524 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2525 _measure_midi->input_latency = one_way;
2526 _measure_midi->output_latency = one_way;
2527 notebook.set_current_page (midi_tab);
2529 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2535 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2536 one_way = std::max (0., one_way);
2538 input_latency_adjustment.set_value (one_way);
2539 output_latency_adjustment.set_value (one_way);
2541 /* back to settings page */
2542 notebook.set_current_page (0);
2548 EngineControl::on_delete_event (GdkEventAny* ev)
2550 if (notebook.get_current_page() == 2) {
2551 /* currently on latency tab - be sure to clean up */
2552 end_latency_detection ();
2554 return ArdourDialog::on_delete_event (ev);
2558 EngineControl::engine_running ()
2560 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2563 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2564 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2566 buffer_size_combo.set_sensitive (true);
2567 sample_rate_combo.set_sensitive (true);
2569 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2570 connect_disconnect_button.show();
2572 started_at_least_once = true;
2573 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2577 EngineControl::engine_stopped ()
2579 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2582 buffer_size_combo.set_sensitive (false);
2583 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2584 connect_disconnect_button.show();
2586 sample_rate_combo.set_sensitive (true);
2587 buffer_size_combo.set_sensitive (true);
2588 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2592 EngineControl::device_list_changed ()
2594 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2596 midi_option_changed();
2600 EngineControl::connect_disconnect_click()
2602 if (ARDOUR::AudioEngine::instance()->running()) {
2603 ARDOUR_UI::instance()->disconnect_from_engine ();
2605 ARDOUR_UI::instance()->reconnect_to_engine ();
2610 EngineControl::calibrate_audio_latency ()
2612 _measure_midi.reset ();
2613 have_lm_results = false;
2614 lm_use_button.set_sensitive (false);
2615 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2616 notebook.set_current_page (latency_tab);
2620 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2623 have_lm_results = false;
2624 lm_use_button.set_sensitive (false);
2625 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2626 notebook.set_current_page (latency_tab);
2630 EngineControl::configure_midi_devices ()
2632 notebook.set_current_page (midi_tab);