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 vector<string> drivers = backend->enumerate_drivers();
847 driver_combo.set_sensitive (true);
849 if (!drivers.empty()) {
851 string current_driver;
852 current_driver = backend->driver_name ();
854 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
856 // driver might not have been set yet
857 if (current_driver == "") {
858 current_driver = driver_combo.get_active_text ();
859 if (current_driver == "")
860 // driver has never been set, make sure it's not blank
861 current_driver = drivers.front ();
864 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
865 set_popdown_strings (driver_combo, drivers);
867 string_compose ("driver_combo.set_active_text: %1", current_driver));
868 driver_combo.set_active_text (current_driver);
875 driver_combo.set_sensitive (false);
876 /* this will change the device text which will cause a call to
877 * device changed which will set up parameters
882 update_midi_options ();
884 connect_disconnect_button.hide();
886 midi_option_changed();
888 started_at_least_once = false;
890 if (!ignore_changes) {
891 maybe_display_saved_state ();
896 EngineControl::update_midi_options ()
898 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
899 vector<string> midi_options = backend->enumerate_midi_options();
901 if (midi_options.size() == 1) {
902 /* only contains the "none" option */
903 midi_option_combo.set_sensitive (false);
906 set_popdown_strings (midi_option_combo, midi_options);
907 midi_option_combo.set_active_text (midi_options.front());
908 midi_option_combo.set_sensitive (true);
910 midi_option_combo.set_sensitive (false);
916 EngineControl::print_channel_count (Gtk::SpinButton* sb)
918 if (ARDOUR::Profile->get_mixbus()) {
922 uint32_t cnt = (uint32_t) sb->get_value();
924 sb->set_text (_("all available channels"));
927 snprintf (buf, sizeof (buf), "%d", cnt);
934 EngineControl::set_driver_popdown_strings ()
936 DEBUG_ECONTROL ("set_driver_popdown_strings");
937 string backend_name = backend_combo.get_active_text();
938 boost::shared_ptr<ARDOUR::AudioBackend> backend;
940 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
941 /* eh? setting the backend failed... how ? */
942 /* A: stale config contains a backend that does not exist in current build */
946 vector<string> drivers = backend->enumerate_drivers();
947 set_popdown_strings (driver_combo, drivers);
951 // @return true if there are devices available
953 EngineControl::set_device_popdown_strings ()
955 DEBUG_ECONTROL ("set_device_popdown_strings");
956 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
957 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
959 /* NOTE: Ardour currently does not display the "available" field of the
962 * Doing so would require a different GUI widget than the combo
963 * box/popdown that we currently use, since it has no way to list
964 * items that are not selectable. Something more like a popup menu,
965 * which could have unselectable items, would be appropriate.
968 vector<string> available_devices;
970 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
971 available_devices.push_back (i->name);
975 if (!available_devices.empty()) {
978 string current_device, found_device;
979 current_device = device_combo.get_active_text ();
980 if (current_device == "") {
981 current_device = backend->device_name ();
984 // Make sure that the active text is still relevant for this
985 // device (it might only be relevant to the previous device!!)
986 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
987 if (*i == current_device)
988 found_device = current_device;
990 if (found_device == "")
991 // device has never been set (or was not relevant
992 // for this backend) Let's make sure it's not blank
993 current_device = available_devices.front ();
995 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
996 set_popdown_strings (device_combo, available_devices);
997 DEBUG_ECONTROL (string_compose ("set device_combo active text: %1", current_device));
999 device_combo.set_active_text (current_device);
1006 // @return true if there are input devices available
1008 EngineControl::set_input_device_popdown_strings ()
1010 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1011 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1012 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1014 vector<string> available_devices;
1016 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1017 available_devices.push_back (i->name);
1020 if (!available_devices.empty()) {
1023 string current_device, found_device;
1024 current_device = input_device_combo.get_active_text ();
1025 if (current_device == "") {
1026 current_device = backend->input_device_name ();
1029 // Make sure that the active text is still relevant for this
1030 // device (it might only be relevant to the previous device!!)
1031 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1032 if (*i == current_device)
1033 found_device = current_device;
1035 if (found_device == "")
1036 // device has never been set (or was not relevant
1037 // for this backend) Let's make sure it's not blank
1038 current_device = available_devices.front ();
1040 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1041 set_popdown_strings (input_device_combo, available_devices);
1043 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1044 input_device_combo.set_active_text (current_device);
1052 // @return true if there are output devices available
1054 EngineControl::set_output_device_popdown_strings ()
1056 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1057 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1058 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1060 vector<string> available_devices;
1062 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1063 available_devices.push_back (i->name);
1066 if (!available_devices.empty()) {
1069 string current_device, found_device;
1070 current_device = output_device_combo.get_active_text ();
1071 if (current_device == "") {
1072 current_device = backend->output_device_name ();
1075 // Make sure that the active text is still relevant for this
1076 // device (it might only be relevant to the previous device!!)
1077 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1078 if (*i == current_device)
1079 found_device = current_device;
1081 if (found_device == "")
1082 // device has never been set (or was not relevant
1083 // for this backend) Let's make sure it's not blank
1084 current_device = available_devices.front ();
1086 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1087 set_popdown_strings (output_device_combo, available_devices);
1089 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1090 output_device_combo.set_active_text (current_device);
1099 EngineControl::list_devices ()
1101 DEBUG_ECONTROL ("list_devices");
1102 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1105 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1107 bool devices_available = false;
1109 if (backend->use_separate_input_and_output_devices ()) {
1110 bool input_devices_available = set_input_device_popdown_strings ();
1111 bool output_devices_available = set_output_device_popdown_strings ();
1112 devices_available = input_devices_available || output_devices_available;
1114 devices_available = set_device_popdown_strings ();
1117 if (devices_available) {
1120 input_latency.set_sensitive (true);
1121 output_latency.set_sensitive (true);
1122 input_channels.set_sensitive (true);
1123 output_channels.set_sensitive (true);
1125 ok_button->set_sensitive (true);
1126 apply_button->set_sensitive (true);
1129 device_combo.clear();
1130 input_device_combo.clear();
1131 output_device_combo.clear();
1132 sample_rate_combo.set_sensitive (false);
1133 buffer_size_combo.set_sensitive (false);
1134 input_latency.set_sensitive (false);
1135 output_latency.set_sensitive (false);
1136 input_channels.set_sensitive (false);
1137 output_channels.set_sensitive (false);
1138 if (_have_control) {
1139 ok_button->set_sensitive (false);
1140 apply_button->set_sensitive (false);
1142 ok_button->set_sensitive (true);
1143 apply_button->set_sensitive (true);
1144 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1145 sample_rate_combo.set_sensitive (true);
1147 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1148 buffer_size_combo.set_sensitive (true);
1156 EngineControl::driver_changed ()
1158 SignalBlocker blocker (*this, "driver_changed");
1159 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1162 backend->set_driver (driver_combo.get_active_text());
1165 if (!ignore_changes) {
1166 maybe_display_saved_state ();
1171 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1173 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1174 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1179 if (_have_control) {
1180 sr = backend->available_sample_rates (device_name);
1183 sr.push_back (8000.0f);
1184 sr.push_back (16000.0f);
1185 sr.push_back (32000.0f);
1186 sr.push_back (44100.0f);
1187 sr.push_back (48000.0f);
1188 sr.push_back (88200.0f);
1189 sr.push_back (96000.0f);
1190 sr.push_back (192000.0f);
1191 sr.push_back (384000.0f);
1194 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1195 s.push_back (rate_as_string (*x));
1196 if (*x == _desired_sample_rate) {
1202 sample_rate_combo.set_sensitive (true);
1203 set_popdown_strings (sample_rate_combo, s);
1205 if (desired.empty()) {
1206 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1208 sample_rate_combo.set_active_text (desired);
1212 sample_rate_combo.set_sensitive (false);
1217 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1219 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1220 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1221 vector<uint32_t> bs;
1224 if (_have_control) {
1225 bs = backend->available_buffer_sizes (device_name);
1226 } else if (backend->can_change_buffer_size_when_running()) {
1234 bs.push_back (1024);
1235 bs.push_back (2048);
1236 bs.push_back (4096);
1237 bs.push_back (8192);
1240 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1241 s.push_back (bufsize_as_string (*x));
1245 buffer_size_combo.set_sensitive (true);
1246 set_popdown_strings (buffer_size_combo, s);
1247 buffer_size_combo.set_active_text (s.front());
1249 uint32_t period = backend->buffer_size();
1251 period = backend->default_buffer_size(device_name);
1253 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1254 show_buffer_duration ();
1256 buffer_size_combo.set_sensitive (false);
1261 EngineControl::device_changed ()
1263 SignalBlocker blocker (*this, "device_changed");
1264 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1267 string device_name_in;
1268 string device_name_out; // only used if backend support separate I/O devices
1270 if (backend->use_separate_input_and_output_devices()) {
1271 device_name_in = get_input_device_name ();
1272 device_name_out = get_output_device_name ();
1274 device_name_in = get_device_name ();
1277 /* we set the backend-device to query various device related intormation.
1278 * This has the side effect that backend->device_name() will match
1279 * the device_name and 'change_device' will never be true.
1280 * so work around this by setting...
1282 if (backend->use_separate_input_and_output_devices()) {
1283 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1284 queue_device_changed = true;
1287 if (device_name_in != backend->device_name()) {
1288 queue_device_changed = true;
1292 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1293 if (backend->use_separate_input_and_output_devices()) {
1294 backend->set_input_device_name (device_name_in);
1295 backend->set_output_device_name (device_name_out);
1297 backend->set_device_name(device_name_in);
1301 /* don't allow programmatic change to combos to cause a
1302 recursive call to this method.
1304 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1306 /* backends that support separate devices, need to ignore
1307 * the device-name - and use the devies set above
1309 set_samplerate_popdown_strings (device_name_in);
1310 set_buffersize_popdown_strings (device_name_in);
1311 /* XXX theoretically need to set min + max channel counts here
1314 manage_control_app_sensitivity ();
1317 /* pick up any saved state for this device */
1319 if (!ignore_changes) {
1320 maybe_display_saved_state ();
1325 EngineControl::input_device_changed ()
1327 DEBUG_ECONTROL ("input_device_changed");
1332 EngineControl::output_device_changed ()
1334 DEBUG_ECONTROL ("output_device_changed");
1339 EngineControl::bufsize_as_string (uint32_t sz)
1341 /* Translators: "samples" is always plural here, so no
1342 need for plural+singular forms.
1345 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1350 EngineControl::sample_rate_changed ()
1352 DEBUG_ECONTROL ("sample_rate_changed");
1353 /* reset the strings for buffer size to show the correct msec value
1354 (reflecting the new sample rate).
1357 show_buffer_duration ();
1362 EngineControl::buffer_size_changed ()
1364 DEBUG_ECONTROL ("buffer_size_changed");
1365 show_buffer_duration ();
1369 EngineControl::show_buffer_duration ()
1371 DEBUG_ECONTROL ("show_buffer_duration");
1372 /* buffer sizes - convert from just samples to samples + msecs for
1373 * the displayed string
1376 string bs_text = buffer_size_combo.get_active_text ();
1377 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1378 uint32_t rate = get_rate();
1380 /* Developers: note the hard-coding of a double buffered model
1381 in the (2 * samples) computation of latency. we always start
1382 the audiobackend in this configuration.
1384 /* note to jack1 developers: ardour also always starts the engine
1385 * in async mode (no jack2 --sync option) which adds an extra cycle
1386 * of latency with jack2 (and *3 would be correct)
1387 * The value can also be wrong if jackd is started externally..
1389 * At the time of writing the ALSA backend always uses double-buffering *2,
1390 * The Dummy backend *1, and who knows what ASIO really does :)
1392 * So just display the period size, that's also what
1393 * ARDOUR_UI::update_sample_rate() does for the status bar.
1394 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1395 * but still, that's the buffer period, not [round-trip] latency)
1398 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1399 buffer_size_duration_label.set_text (buf);
1403 EngineControl::midi_option_changed ()
1405 DEBUG_ECONTROL ("midi_option_changed");
1406 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1409 backend->set_midi_option (get_midi_option());
1411 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1413 //_midi_devices.clear(); // TODO merge with state-saved settings..
1414 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1415 std::vector<MidiDeviceSettings> new_devices;
1417 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1418 MidiDeviceSettings mds = find_midi_device (i->name);
1419 if (i->available && !mds) {
1420 uint32_t input_latency = 0;
1421 uint32_t output_latency = 0;
1422 if (_can_set_midi_latencies) {
1423 input_latency = backend->systemic_midi_input_latency (i->name);
1424 output_latency = backend->systemic_midi_output_latency (i->name);
1426 bool enabled = backend->midi_device_enabled (i->name);
1427 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1428 new_devices.push_back (ptr);
1429 } else if (i->available) {
1430 new_devices.push_back (mds);
1433 _midi_devices = new_devices;
1435 if (_midi_devices.empty()) {
1436 midi_devices_button.set_sensitive (false);
1438 midi_devices_button.set_sensitive (true);
1443 EngineControl::parameter_changed ()
1447 EngineControl::State
1448 EngineControl::get_matching_state (
1449 const string& backend,
1450 const string& driver,
1451 const string& device)
1453 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1454 if ((*i)->backend == backend &&
1455 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1463 EngineControl::State
1464 EngineControl::get_matching_state (
1465 const string& backend,
1466 const string& driver,
1467 const string& input_device,
1468 const string& output_device)
1470 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1471 if ((*i)->backend == backend &&
1472 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1480 EngineControl::State
1481 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1483 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1486 if (backend->use_separate_input_and_output_devices ()) {
1487 return get_matching_state (backend_combo.get_active_text(),
1488 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1489 input_device_combo.get_active_text(),
1490 output_device_combo.get_active_text());
1492 return get_matching_state (backend_combo.get_active_text(),
1493 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1494 device_combo.get_active_text());
1498 return get_matching_state (backend_combo.get_active_text(),
1500 device_combo.get_active_text());
1503 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1504 const EngineControl::State& state2)
1506 if (state1->backend == state2->backend &&
1507 state1->driver == state2->driver &&
1508 state1->device == state2->device &&
1509 state1->input_device == state2->input_device &&
1510 state1->output_device == state2->output_device) {
1516 EngineControl::State
1517 EngineControl::save_state ()
1521 if (!_have_control) {
1522 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1526 state.reset(new StateStruct);
1527 state->backend = get_backend ();
1529 state.reset(new StateStruct);
1530 store_state (state);
1533 for (StateList::iterator i = states.begin(); i != states.end();) {
1534 if (equivalent_states (*i, state)) {
1535 i = states.erase(i);
1541 states.push_back (state);
1547 EngineControl::store_state (State state)
1549 state->backend = get_backend ();
1550 state->driver = get_driver ();
1551 state->device = get_device_name ();
1552 state->input_device = get_input_device_name ();
1553 state->output_device = get_output_device_name ();
1554 state->sample_rate = get_rate ();
1555 state->buffer_size = get_buffer_size ();
1556 state->input_latency = get_input_latency ();
1557 state->output_latency = get_output_latency ();
1558 state->input_channels = get_input_channels ();
1559 state->output_channels = get_output_channels ();
1560 state->midi_option = get_midi_option ();
1561 state->midi_devices = _midi_devices;
1565 EngineControl::maybe_display_saved_state ()
1567 if (!_have_control) {
1571 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1574 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1576 if (!_desired_sample_rate) {
1577 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1579 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1580 /* call this explicitly because we're ignoring changes to
1581 the controls at this point.
1583 show_buffer_duration ();
1584 input_latency.set_value (state->input_latency);
1585 output_latency.set_value (state->output_latency);
1587 if (!state->midi_option.empty()) {
1588 midi_option_combo.set_active_text (state->midi_option);
1589 _midi_devices = state->midi_devices;
1595 EngineControl::get_state ()
1597 LocaleGuard lg (X_("C"));
1599 XMLNode* root = new XMLNode ("AudioMIDISetup");
1602 if (!states.empty()) {
1603 XMLNode* state_nodes = new XMLNode ("EngineStates");
1605 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1607 XMLNode* node = new XMLNode ("State");
1609 node->add_property ("backend", (*i)->backend);
1610 node->add_property ("driver", (*i)->driver);
1611 node->add_property ("device", (*i)->device);
1612 node->add_property ("input-device", (*i)->input_device);
1613 node->add_property ("output-device", (*i)->output_device);
1614 node->add_property ("sample-rate", (*i)->sample_rate);
1615 node->add_property ("buffer-size", (*i)->buffer_size);
1616 node->add_property ("input-latency", (*i)->input_latency);
1617 node->add_property ("output-latency", (*i)->output_latency);
1618 node->add_property ("input-channels", (*i)->input_channels);
1619 node->add_property ("output-channels", (*i)->output_channels);
1620 node->add_property ("active", (*i)->active ? "yes" : "no");
1621 node->add_property ("midi-option", (*i)->midi_option);
1623 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1624 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1625 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1626 midi_device_stuff->add_property (X_("name"), (*p)->name);
1627 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1628 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1629 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1630 midi_devices->add_child_nocopy (*midi_device_stuff);
1632 node->add_child_nocopy (*midi_devices);
1634 state_nodes->add_child_nocopy (*node);
1637 root->add_child_nocopy (*state_nodes);
1644 EngineControl::set_state (const XMLNode& root)
1646 XMLNodeList clist, cclist;
1647 XMLNodeConstIterator citer, cciter;
1649 XMLNode* grandchild;
1650 XMLProperty* prop = NULL;
1652 fprintf (stderr, "EngineControl::set_state\n");
1654 if (root.name() != "AudioMIDISetup") {
1658 clist = root.children();
1662 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1666 if (child->name() != "EngineStates") {
1670 cclist = child->children();
1672 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1673 State state (new StateStruct);
1675 grandchild = *cciter;
1677 if (grandchild->name() != "State") {
1681 if ((prop = grandchild->property ("backend")) == 0) {
1684 state->backend = prop->value ();
1686 if ((prop = grandchild->property ("driver")) == 0) {
1689 state->driver = prop->value ();
1691 if ((prop = grandchild->property ("device")) == 0) {
1694 state->device = prop->value ();
1696 if ((prop = grandchild->property ("input-device")) == 0) {
1699 state->input_device = prop->value ();
1701 if ((prop = grandchild->property ("output-device")) == 0) {
1704 state->output_device = prop->value ();
1706 if ((prop = grandchild->property ("sample-rate")) == 0) {
1709 state->sample_rate = atof (prop->value ());
1711 if ((prop = grandchild->property ("buffer-size")) == 0) {
1714 state->buffer_size = atoi (prop->value ());
1716 if ((prop = grandchild->property ("input-latency")) == 0) {
1719 state->input_latency = atoi (prop->value ());
1721 if ((prop = grandchild->property ("output-latency")) == 0) {
1724 state->output_latency = atoi (prop->value ());
1726 if ((prop = grandchild->property ("input-channels")) == 0) {
1729 state->input_channels = atoi (prop->value ());
1731 if ((prop = grandchild->property ("output-channels")) == 0) {
1734 state->output_channels = atoi (prop->value ());
1736 if ((prop = grandchild->property ("active")) == 0) {
1739 state->active = string_is_affirmative (prop->value ());
1741 if ((prop = grandchild->property ("midi-option")) == 0) {
1744 state->midi_option = prop->value ();
1746 state->midi_devices.clear();
1748 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1749 const XMLNodeList mnc = midinode->children();
1750 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1751 if ((*n)->property (X_("name")) == 0
1752 || (*n)->property (X_("enabled")) == 0
1753 || (*n)->property (X_("input-latency")) == 0
1754 || (*n)->property (X_("output-latency")) == 0
1759 MidiDeviceSettings ptr (new MidiDeviceSetting(
1760 (*n)->property (X_("name"))->value (),
1761 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1762 atoi ((*n)->property (X_("input-latency"))->value ()),
1763 atoi ((*n)->property (X_("output-latency"))->value ())
1765 state->midi_devices.push_back (ptr);
1770 /* remove accumulated duplicates (due to bug in ealier version)
1771 * this can be removed again before release
1773 for (StateList::iterator i = states.begin(); i != states.end();) {
1774 if ((*i)->backend == state->backend &&
1775 (*i)->driver == state->driver &&
1776 (*i)->device == state->device) {
1777 i = states.erase(i);
1784 states.push_back (state);
1788 /* now see if there was an active state and switch the setup to it */
1790 // purge states of backend that are not available in this built
1791 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1792 vector<std::string> backend_names;
1794 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1795 backend_names.push_back((*i)->name);
1797 for (StateList::iterator i = states.begin(); i != states.end();) {
1798 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1799 i = states.erase(i);
1805 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1808 set_current_state (*i);
1815 EngineControl::set_current_state (const State& state)
1817 DEBUG_ECONTROL ("set_current_state");
1818 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1819 backend_combo.set_active_text (state->backend);
1821 /* The driver popdown strings need to be populated now so that
1822 * set_active_text will actually set a valid entry. Then
1823 * backend_changed() will populate all the other combo's so they
1824 * can also be set to valid entries and the state will be restored
1827 if (!state->driver.empty()) {
1828 set_driver_popdown_strings ();
1830 driver_combo.set_active_text (state->driver);
1833 device_combo.set_active_text (state->device);
1834 input_device_combo.set_active_text (state->input_device);
1835 output_device_combo.set_active_text (state->output_device);
1836 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1837 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1838 input_latency.set_value (state->input_latency);
1839 output_latency.set_value (state->output_latency);
1840 midi_option_combo.set_active_text (state->midi_option);
1844 EngineControl::push_state_to_backend (bool start)
1846 DEBUG_ECONTROL ("push_state_to_backend");
1847 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1853 /* figure out what is going to change */
1855 bool restart_required = false;
1856 bool was_running = ARDOUR::AudioEngine::instance()->running();
1857 bool change_driver = false;
1858 bool change_device = false;
1859 bool change_rate = false;
1860 bool change_bufsize = false;
1861 bool change_latency = false;
1862 bool change_channels = false;
1863 bool change_midi = false;
1865 uint32_t ochan = get_output_channels ();
1866 uint32_t ichan = get_input_channels ();
1868 if (_have_control) {
1870 if (started_at_least_once) {
1872 /* we can control the backend */
1874 if (backend->requires_driver_selection()) {
1875 if (get_driver() != backend->driver_name()) {
1876 change_driver = true;
1880 if (backend->use_separate_input_and_output_devices()) {
1881 if (get_input_device_name() != backend->input_device_name()) {
1882 change_device = true;
1884 if (get_output_device_name() != backend->output_device_name()) {
1885 change_device = true;
1888 if (get_device_name() != backend->device_name()) {
1889 change_device = true;
1893 if (queue_device_changed) {
1894 change_device = true;
1897 if (get_rate() != backend->sample_rate()) {
1901 if (get_buffer_size() != backend->buffer_size()) {
1902 change_bufsize = true;
1905 if (get_midi_option() != backend->midi_option()) {
1909 /* zero-requested channels means "all available" */
1912 ichan = backend->input_channels();
1916 ochan = backend->output_channels();
1919 if (ichan != backend->input_channels()) {
1920 change_channels = true;
1923 if (ochan != backend->output_channels()) {
1924 change_channels = true;
1927 if (get_input_latency() != backend->systemic_input_latency() ||
1928 get_output_latency() != backend->systemic_output_latency()) {
1929 change_latency = true;
1932 /* backend never started, so we have to force a group
1935 change_device = true;
1936 if (backend->requires_driver_selection()) {
1937 change_driver = true;
1940 change_bufsize = true;
1941 change_channels = true;
1942 change_latency = true;
1948 /* we have no control over the backend, meaning that we can
1949 * only possibly change sample rate and buffer size.
1953 if (get_rate() != backend->sample_rate()) {
1954 change_bufsize = true;
1957 if (get_buffer_size() != backend->buffer_size()) {
1958 change_bufsize = true;
1962 queue_device_changed = false;
1964 if (!_have_control) {
1966 /* We do not have control over the backend, so the best we can
1967 * do is try to change the sample rate and/or bufsize and get
1971 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1975 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1980 backend->set_sample_rate (get_rate());
1983 if (change_bufsize) {
1984 backend->set_buffer_size (get_buffer_size());
1988 if (ARDOUR::AudioEngine::instance()->start ()) {
1989 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1999 /* determine if we need to stop the backend before changing parameters */
2001 if (change_driver || change_device || change_channels || change_latency ||
2002 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2004 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2005 restart_required = true;
2007 restart_required = false;
2012 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2013 /* no changes in any parameters that absolutely require a
2014 * restart, so check those that might be changeable without a
2018 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2019 /* can't do this while running ... */
2020 restart_required = true;
2023 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2024 /* can't do this while running ... */
2025 restart_required = true;
2031 if (restart_required) {
2032 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2039 if (change_driver && backend->set_driver (get_driver())) {
2040 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2043 if (backend->use_separate_input_and_output_devices()) {
2044 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2045 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2048 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2049 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2053 if (change_device && backend->set_device_name (get_device_name())) {
2054 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2058 if (change_rate && backend->set_sample_rate (get_rate())) {
2059 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2062 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2063 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2067 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2068 if (backend->set_input_channels (get_input_channels())) {
2069 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2072 if (backend->set_output_channels (get_output_channels())) {
2073 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2077 if (change_latency) {
2078 if (backend->set_systemic_input_latency (get_input_latency())) {
2079 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2082 if (backend->set_systemic_output_latency (get_output_latency())) {
2083 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2089 backend->set_midi_option (get_midi_option());
2093 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2094 if (_measure_midi) {
2095 if (*p == _measure_midi) {
2096 backend->set_midi_device_enabled ((*p)->name, true);
2098 backend->set_midi_device_enabled ((*p)->name, false);
2102 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2103 if (backend->can_set_systemic_midi_latencies()) {
2104 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2105 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2110 if (start || (was_running && restart_required)) {
2111 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2122 EngineControl::post_push ()
2124 /* get a pointer to the current state object, creating one if
2128 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2131 state = save_state ();
2139 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2140 (*i)->active = false;
2143 /* mark this one active (to be used next time the dialog is
2147 state->active = true;
2149 if (_have_control) { // XXX
2150 manage_control_app_sensitivity ();
2153 /* schedule a redisplay of MIDI ports */
2154 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2159 EngineControl::get_rate () const
2161 float r = atof (sample_rate_combo.get_active_text ());
2162 /* the string may have been translated with an abbreviation for
2163 * thousands, so use a crude heuristic to fix this.
2173 EngineControl::get_buffer_size () const
2175 string txt = buffer_size_combo.get_active_text ();
2178 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2179 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2180 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2188 EngineControl::get_midi_option () const
2190 return midi_option_combo.get_active_text();
2194 EngineControl::get_input_channels() const
2196 if (ARDOUR::Profile->get_mixbus()) {
2197 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2198 if (!backend) return 0;
2199 return backend->input_channels();
2201 return (uint32_t) input_channels_adjustment.get_value();
2205 EngineControl::get_output_channels() const
2207 if (ARDOUR::Profile->get_mixbus()) {
2208 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2209 if (!backend) return 0;
2210 return backend->input_channels();
2212 return (uint32_t) output_channels_adjustment.get_value();
2216 EngineControl::get_input_latency() const
2218 return (uint32_t) input_latency_adjustment.get_value();
2222 EngineControl::get_output_latency() const
2224 return (uint32_t) output_latency_adjustment.get_value();
2228 EngineControl::get_backend () const
2230 return backend_combo.get_active_text ();
2234 EngineControl::get_driver () const
2236 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2237 return driver_combo.get_active_text ();
2244 EngineControl::get_device_name () const
2246 return device_combo.get_active_text ();
2250 EngineControl::get_input_device_name () const
2252 return input_device_combo.get_active_text ();
2256 EngineControl::get_output_device_name () const
2258 return output_device_combo.get_active_text ();
2262 EngineControl::control_app_button_clicked ()
2264 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2270 backend->launch_control_app ();
2274 EngineControl::manage_control_app_sensitivity ()
2276 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2282 string appname = backend->control_app_name();
2284 if (appname.empty()) {
2285 control_app_button.set_sensitive (false);
2287 control_app_button.set_sensitive (true);
2292 EngineControl::set_desired_sample_rate (uint32_t sr)
2294 _desired_sample_rate = sr;
2299 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2301 if (page_num == 0) {
2302 cancel_button->set_sensitive (true);
2303 ok_button->set_sensitive (true);
2304 apply_button->set_sensitive (true);
2305 _measure_midi.reset();
2307 cancel_button->set_sensitive (false);
2308 ok_button->set_sensitive (false);
2309 apply_button->set_sensitive (false);
2312 if (page_num == midi_tab) {
2314 refresh_midi_display ();
2317 if (page_num == latency_tab) {
2320 if (ARDOUR::AudioEngine::instance()->running()) {
2321 // TODO - mark as 'stopped for latency
2322 ARDOUR_UI::instance()->disconnect_from_engine ();
2326 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2328 /* save any existing latency values */
2330 uint32_t il = (uint32_t) input_latency.get_value ();
2331 uint32_t ol = (uint32_t) input_latency.get_value ();
2333 /* reset to zero so that our new test instance
2334 will be clean of any existing latency measures.
2336 NB. this should really be done by the backend
2337 when stated for latency measurement.
2340 input_latency.set_value (0);
2341 output_latency.set_value (0);
2343 push_state_to_backend (false);
2347 input_latency.set_value (il);
2348 output_latency.set_value (ol);
2351 // This should be done in push_state_to_backend()
2352 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2353 disable_latency_tab ();
2356 enable_latency_tab ();
2360 end_latency_detection ();
2361 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2366 /* latency measurement */
2369 EngineControl::check_audio_latency_measurement ()
2371 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2373 if (mtdm->resolve () < 0) {
2374 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2378 if (mtdm->err () > 0.3) {
2384 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2386 if (sample_rate == 0) {
2387 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2388 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2392 int frames_total = mtdm->del();
2393 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2395 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2396 _("Detected roundtrip latency: "),
2397 frames_total, frames_total * 1000.0f/sample_rate,
2398 _("Systemic latency: "),
2399 extra, extra * 1000.0f/sample_rate);
2403 if (mtdm->err () > 0.2) {
2405 strcat (buf, _("(signal detection error)"));
2411 strcat (buf, _("(inverted - bad wiring)"));
2415 lm_results.set_markup (string_compose (results_markup, buf));
2418 have_lm_results = true;
2419 end_latency_detection ();
2420 lm_use_button.set_sensitive (true);
2428 EngineControl::check_midi_latency_measurement ()
2430 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2432 if (!mididm->have_signal () || mididm->latency () == 0) {
2433 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2438 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2440 if (sample_rate == 0) {
2441 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2442 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2446 ARDOUR::framecnt_t frames_total = mididm->latency();
2447 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2448 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2449 _("Detected roundtrip latency: "),
2450 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2451 _("Systemic latency: "),
2452 extra, extra * 1000.0f / sample_rate);
2456 if (!mididm->ok ()) {
2458 strcat (buf, _("(averaging)"));
2462 if (mididm->deviation () > 50.0) {
2464 strcat (buf, _("(too large jitter)"));
2466 } else if (mididm->deviation () > 10.0) {
2468 strcat (buf, _("(large jitter)"));
2472 have_lm_results = true;
2473 end_latency_detection ();
2474 lm_use_button.set_sensitive (true);
2475 lm_results.set_markup (string_compose (results_markup, buf));
2477 } else if (mididm->processed () > 400) {
2478 have_lm_results = false;
2479 end_latency_detection ();
2480 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2484 lm_results.set_markup (string_compose (results_markup, buf));
2490 EngineControl::start_latency_detection ()
2492 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2493 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2495 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2496 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2497 if (_measure_midi) {
2498 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2500 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2502 lm_measure_label.set_text (_("Cancel"));
2503 have_lm_results = false;
2504 lm_use_button.set_sensitive (false);
2505 lm_input_channel_combo.set_sensitive (false);
2506 lm_output_channel_combo.set_sensitive (false);
2512 EngineControl::end_latency_detection ()
2514 latency_timeout.disconnect ();
2515 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2516 lm_measure_label.set_text (_("Measure"));
2517 if (!have_lm_results) {
2518 lm_use_button.set_sensitive (false);
2520 lm_input_channel_combo.set_sensitive (true);
2521 lm_output_channel_combo.set_sensitive (true);
2526 EngineControl::latency_button_clicked ()
2529 start_latency_detection ();
2531 end_latency_detection ();
2536 EngineControl::use_latency_button_clicked ()
2538 if (_measure_midi) {
2539 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2543 ARDOUR::framecnt_t frames_total = mididm->latency();
2544 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2545 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2546 _measure_midi->input_latency = one_way;
2547 _measure_midi->output_latency = one_way;
2548 notebook.set_current_page (midi_tab);
2550 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2556 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2557 one_way = std::max (0., one_way);
2559 input_latency_adjustment.set_value (one_way);
2560 output_latency_adjustment.set_value (one_way);
2562 /* back to settings page */
2563 notebook.set_current_page (0);
2569 EngineControl::on_delete_event (GdkEventAny* ev)
2571 if (notebook.get_current_page() == 2) {
2572 /* currently on latency tab - be sure to clean up */
2573 end_latency_detection ();
2575 return ArdourDialog::on_delete_event (ev);
2579 EngineControl::engine_running ()
2581 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2584 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2585 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2587 buffer_size_combo.set_sensitive (true);
2588 sample_rate_combo.set_sensitive (true);
2590 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2591 connect_disconnect_button.show();
2593 started_at_least_once = true;
2594 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2598 EngineControl::engine_stopped ()
2600 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2603 buffer_size_combo.set_sensitive (false);
2604 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2605 connect_disconnect_button.show();
2607 sample_rate_combo.set_sensitive (true);
2608 buffer_size_combo.set_sensitive (true);
2609 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2613 EngineControl::device_list_changed ()
2615 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2617 midi_option_changed();
2621 EngineControl::connect_disconnect_click()
2623 if (ARDOUR::AudioEngine::instance()->running()) {
2624 ARDOUR_UI::instance()->disconnect_from_engine ();
2626 ARDOUR_UI::instance()->reconnect_to_engine ();
2631 EngineControl::calibrate_audio_latency ()
2633 _measure_midi.reset ();
2634 have_lm_results = false;
2635 lm_use_button.set_sensitive (false);
2636 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2637 notebook.set_current_page (latency_tab);
2641 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2644 have_lm_results = false;
2645 lm_use_button.set_sensitive (false);
2646 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2647 notebook.set_current_page (latency_tab);
2651 EngineControl::configure_midi_devices ()
2653 notebook.set_current_page (midi_tab);