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);
1820 driver_combo.set_active_text (state->driver);
1823 device_combo.set_active_text (state->device);
1824 input_device_combo.set_active_text (state->input_device);
1825 output_device_combo.set_active_text (state->output_device);
1826 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1827 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1828 input_latency.set_value (state->input_latency);
1829 output_latency.set_value (state->output_latency);
1830 midi_option_combo.set_active_text (state->midi_option);
1834 EngineControl::push_state_to_backend (bool start)
1836 DEBUG_ECONTROL ("push_state_to_backend");
1837 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1843 /* figure out what is going to change */
1845 bool restart_required = false;
1846 bool was_running = ARDOUR::AudioEngine::instance()->running();
1847 bool change_driver = false;
1848 bool change_device = false;
1849 bool change_rate = false;
1850 bool change_bufsize = false;
1851 bool change_latency = false;
1852 bool change_channels = false;
1853 bool change_midi = false;
1855 uint32_t ochan = get_output_channels ();
1856 uint32_t ichan = get_input_channels ();
1858 if (_have_control) {
1860 if (started_at_least_once) {
1862 /* we can control the backend */
1864 if (backend->requires_driver_selection()) {
1865 if (get_driver() != backend->driver_name()) {
1866 change_driver = true;
1870 if (backend->use_separate_input_and_output_devices()) {
1871 if (get_input_device_name() != backend->input_device_name()) {
1872 change_device = true;
1874 if (get_output_device_name() != backend->output_device_name()) {
1875 change_device = true;
1878 if (get_device_name() != backend->device_name()) {
1879 change_device = true;
1883 if (queue_device_changed) {
1884 change_device = true;
1887 if (get_rate() != backend->sample_rate()) {
1891 if (get_buffer_size() != backend->buffer_size()) {
1892 change_bufsize = true;
1895 if (get_midi_option() != backend->midi_option()) {
1899 /* zero-requested channels means "all available" */
1902 ichan = backend->input_channels();
1906 ochan = backend->output_channels();
1909 if (ichan != backend->input_channels()) {
1910 change_channels = true;
1913 if (ochan != backend->output_channels()) {
1914 change_channels = true;
1917 if (get_input_latency() != backend->systemic_input_latency() ||
1918 get_output_latency() != backend->systemic_output_latency()) {
1919 change_latency = true;
1922 /* backend never started, so we have to force a group
1925 change_device = true;
1926 if (backend->requires_driver_selection()) {
1927 change_driver = true;
1930 change_bufsize = true;
1931 change_channels = true;
1932 change_latency = true;
1938 /* we have no control over the backend, meaning that we can
1939 * only possibly change sample rate and buffer size.
1943 if (get_rate() != backend->sample_rate()) {
1944 change_bufsize = true;
1947 if (get_buffer_size() != backend->buffer_size()) {
1948 change_bufsize = true;
1952 queue_device_changed = false;
1954 if (!_have_control) {
1956 /* We do not have control over the backend, so the best we can
1957 * do is try to change the sample rate and/or bufsize and get
1961 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1965 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1970 backend->set_sample_rate (get_rate());
1973 if (change_bufsize) {
1974 backend->set_buffer_size (get_buffer_size());
1978 if (ARDOUR::AudioEngine::instance()->start ()) {
1979 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1989 /* determine if we need to stop the backend before changing parameters */
1991 if (change_driver || change_device || change_channels || change_latency ||
1992 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1994 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1995 restart_required = true;
1997 restart_required = false;
2002 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2003 /* no changes in any parameters that absolutely require a
2004 * restart, so check those that might be changeable without a
2008 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2009 /* can't do this while running ... */
2010 restart_required = true;
2013 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2014 /* can't do this while running ... */
2015 restart_required = true;
2021 if (restart_required) {
2022 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2029 if (change_driver && backend->set_driver (get_driver())) {
2030 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2033 if (backend->use_separate_input_and_output_devices()) {
2034 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2035 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2038 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2039 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2043 if (change_device && backend->set_device_name (get_device_name())) {
2044 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2048 if (change_rate && backend->set_sample_rate (get_rate())) {
2049 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2052 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2053 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2057 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2058 if (backend->set_input_channels (get_input_channels())) {
2059 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2062 if (backend->set_output_channels (get_output_channels())) {
2063 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2067 if (change_latency) {
2068 if (backend->set_systemic_input_latency (get_input_latency())) {
2069 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2072 if (backend->set_systemic_output_latency (get_output_latency())) {
2073 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2079 backend->set_midi_option (get_midi_option());
2083 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2084 if (_measure_midi) {
2085 if (*p == _measure_midi) {
2086 backend->set_midi_device_enabled ((*p)->name, true);
2088 backend->set_midi_device_enabled ((*p)->name, false);
2092 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2093 if (backend->can_set_systemic_midi_latencies()) {
2094 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2095 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2100 if (start || (was_running && restart_required)) {
2101 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2112 EngineControl::post_push ()
2114 /* get a pointer to the current state object, creating one if
2118 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2121 state = save_state ();
2129 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2130 (*i)->active = false;
2133 /* mark this one active (to be used next time the dialog is
2137 state->active = true;
2139 if (_have_control) { // XXX
2140 manage_control_app_sensitivity ();
2143 /* schedule a redisplay of MIDI ports */
2144 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2149 EngineControl::get_rate () const
2151 float r = atof (sample_rate_combo.get_active_text ());
2152 /* the string may have been translated with an abbreviation for
2153 * thousands, so use a crude heuristic to fix this.
2163 EngineControl::get_buffer_size () const
2165 string txt = buffer_size_combo.get_active_text ();
2168 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2169 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2170 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2178 EngineControl::get_midi_option () const
2180 return midi_option_combo.get_active_text();
2184 EngineControl::get_input_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) input_channels_adjustment.get_value();
2195 EngineControl::get_output_channels() const
2197 if (ARDOUR::Profile->get_mixbus()) {
2198 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2199 if (!backend) return 0;
2200 return backend->input_channels();
2202 return (uint32_t) output_channels_adjustment.get_value();
2206 EngineControl::get_input_latency() const
2208 return (uint32_t) input_latency_adjustment.get_value();
2212 EngineControl::get_output_latency() const
2214 return (uint32_t) output_latency_adjustment.get_value();
2218 EngineControl::get_backend () const
2220 return backend_combo.get_active_text ();
2224 EngineControl::get_driver () const
2226 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2227 return driver_combo.get_active_text ();
2234 EngineControl::get_device_name () const
2236 return device_combo.get_active_text ();
2240 EngineControl::get_input_device_name () const
2242 return input_device_combo.get_active_text ();
2246 EngineControl::get_output_device_name () const
2248 return output_device_combo.get_active_text ();
2252 EngineControl::control_app_button_clicked ()
2254 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2260 backend->launch_control_app ();
2264 EngineControl::manage_control_app_sensitivity ()
2266 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2272 string appname = backend->control_app_name();
2274 if (appname.empty()) {
2275 control_app_button.set_sensitive (false);
2277 control_app_button.set_sensitive (true);
2282 EngineControl::set_desired_sample_rate (uint32_t sr)
2284 _desired_sample_rate = sr;
2289 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2291 if (page_num == 0) {
2292 cancel_button->set_sensitive (true);
2293 ok_button->set_sensitive (true);
2294 apply_button->set_sensitive (true);
2295 _measure_midi.reset();
2297 cancel_button->set_sensitive (false);
2298 ok_button->set_sensitive (false);
2299 apply_button->set_sensitive (false);
2302 if (page_num == midi_tab) {
2304 refresh_midi_display ();
2307 if (page_num == latency_tab) {
2310 if (ARDOUR::AudioEngine::instance()->running()) {
2311 // TODO - mark as 'stopped for latency
2312 ARDOUR_UI::instance()->disconnect_from_engine ();
2316 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2318 /* save any existing latency values */
2320 uint32_t il = (uint32_t) input_latency.get_value ();
2321 uint32_t ol = (uint32_t) input_latency.get_value ();
2323 /* reset to zero so that our new test instance
2324 will be clean of any existing latency measures.
2326 NB. this should really be done by the backend
2327 when stated for latency measurement.
2330 input_latency.set_value (0);
2331 output_latency.set_value (0);
2333 push_state_to_backend (false);
2337 input_latency.set_value (il);
2338 output_latency.set_value (ol);
2341 // This should be done in push_state_to_backend()
2342 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2343 disable_latency_tab ();
2346 enable_latency_tab ();
2350 end_latency_detection ();
2351 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2356 /* latency measurement */
2359 EngineControl::check_audio_latency_measurement ()
2361 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2363 if (mtdm->resolve () < 0) {
2364 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2368 if (mtdm->err () > 0.3) {
2374 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2376 if (sample_rate == 0) {
2377 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2378 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2382 int frames_total = mtdm->del();
2383 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2385 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2386 _("Detected roundtrip latency: "),
2387 frames_total, frames_total * 1000.0f/sample_rate,
2388 _("Systemic latency: "),
2389 extra, extra * 1000.0f/sample_rate);
2393 if (mtdm->err () > 0.2) {
2395 strcat (buf, _("(signal detection error)"));
2401 strcat (buf, _("(inverted - bad wiring)"));
2405 lm_results.set_markup (string_compose (results_markup, buf));
2408 have_lm_results = true;
2409 end_latency_detection ();
2410 lm_use_button.set_sensitive (true);
2418 EngineControl::check_midi_latency_measurement ()
2420 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2422 if (!mididm->have_signal () || mididm->latency () == 0) {
2423 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2428 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2430 if (sample_rate == 0) {
2431 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2432 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2436 ARDOUR::framecnt_t frames_total = mididm->latency();
2437 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2438 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2439 _("Detected roundtrip latency: "),
2440 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2441 _("Systemic latency: "),
2442 extra, extra * 1000.0f / sample_rate);
2446 if (!mididm->ok ()) {
2448 strcat (buf, _("(averaging)"));
2452 if (mididm->deviation () > 50.0) {
2454 strcat (buf, _("(too large jitter)"));
2456 } else if (mididm->deviation () > 10.0) {
2458 strcat (buf, _("(large jitter)"));
2462 have_lm_results = true;
2463 end_latency_detection ();
2464 lm_use_button.set_sensitive (true);
2465 lm_results.set_markup (string_compose (results_markup, buf));
2467 } else if (mididm->processed () > 400) {
2468 have_lm_results = false;
2469 end_latency_detection ();
2470 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2474 lm_results.set_markup (string_compose (results_markup, buf));
2480 EngineControl::start_latency_detection ()
2482 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2483 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2485 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2486 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2487 if (_measure_midi) {
2488 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2490 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2492 lm_measure_label.set_text (_("Cancel"));
2493 have_lm_results = false;
2494 lm_use_button.set_sensitive (false);
2495 lm_input_channel_combo.set_sensitive (false);
2496 lm_output_channel_combo.set_sensitive (false);
2502 EngineControl::end_latency_detection ()
2504 latency_timeout.disconnect ();
2505 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2506 lm_measure_label.set_text (_("Measure"));
2507 if (!have_lm_results) {
2508 lm_use_button.set_sensitive (false);
2510 lm_input_channel_combo.set_sensitive (true);
2511 lm_output_channel_combo.set_sensitive (true);
2516 EngineControl::latency_button_clicked ()
2519 start_latency_detection ();
2521 end_latency_detection ();
2526 EngineControl::use_latency_button_clicked ()
2528 if (_measure_midi) {
2529 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2533 ARDOUR::framecnt_t frames_total = mididm->latency();
2534 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2535 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2536 _measure_midi->input_latency = one_way;
2537 _measure_midi->output_latency = one_way;
2538 notebook.set_current_page (midi_tab);
2540 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2546 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2547 one_way = std::max (0., one_way);
2549 input_latency_adjustment.set_value (one_way);
2550 output_latency_adjustment.set_value (one_way);
2552 /* back to settings page */
2553 notebook.set_current_page (0);
2559 EngineControl::on_delete_event (GdkEventAny* ev)
2561 if (notebook.get_current_page() == 2) {
2562 /* currently on latency tab - be sure to clean up */
2563 end_latency_detection ();
2565 return ArdourDialog::on_delete_event (ev);
2569 EngineControl::engine_running ()
2571 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2574 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2575 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2577 buffer_size_combo.set_sensitive (true);
2578 sample_rate_combo.set_sensitive (true);
2580 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2581 connect_disconnect_button.show();
2583 started_at_least_once = true;
2584 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2588 EngineControl::engine_stopped ()
2590 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2593 buffer_size_combo.set_sensitive (false);
2594 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2595 connect_disconnect_button.show();
2597 sample_rate_combo.set_sensitive (true);
2598 buffer_size_combo.set_sensitive (true);
2599 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2603 EngineControl::device_list_changed ()
2605 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2607 midi_option_changed();
2611 EngineControl::connect_disconnect_click()
2613 if (ARDOUR::AudioEngine::instance()->running()) {
2614 ARDOUR_UI::instance()->disconnect_from_engine ();
2616 ARDOUR_UI::instance()->reconnect_to_engine ();
2621 EngineControl::calibrate_audio_latency ()
2623 _measure_midi.reset ();
2624 have_lm_results = false;
2625 lm_use_button.set_sensitive (false);
2626 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2627 notebook.set_current_page (latency_tab);
2631 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
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::configure_midi_devices ()
2643 notebook.set_current_page (midi_tab);