2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
61 using namespace Gtkmm2ext;
64 using namespace ARDOUR_UI_UTILS;
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
73 EngineControl::EngineControl ()
74 : ArdourDialog (_("Audio/MIDI Setup"))
77 , input_latency_adjustment (0, 0, 99999, 1)
78 , input_latency (input_latency_adjustment)
79 , output_latency_adjustment (0, 0, 99999, 1)
80 , output_latency (output_latency_adjustment)
81 , input_channels_adjustment (0, 0, 256, 1)
82 , input_channels (input_channels_adjustment)
83 , output_channels_adjustment (0, 0, 256, 1)
84 , output_channels (output_channels_adjustment)
85 , ports_adjustment (128, 8, 1024, 1, 16)
86 , ports_spinner (ports_adjustment)
87 , control_app_button (_("Device Control Panel"))
88 , midi_devices_button (_("Midi Device Setup"))
89 , lm_measure_label (_("Measure"))
90 , lm_use_button (_("Use results"))
91 , lm_back_button (_("Back to settings ... (ignore results)"))
92 , lm_button_audio (_("Calibrate Audio"))
94 , have_lm_results (false)
96 , midi_back_button (_("Back to settings"))
98 , _desired_sample_rate (0)
99 , started_at_least_once (false)
100 , queue_device_changed (false)
103 using namespace Notebook_Helpers;
104 vector<string> backend_names;
106 AttachOptions xopt = AttachOptions (FILL|EXPAND);
109 set_name (X_("AudioMIDISetup"));
111 /* the backend combo is the one thing that is ALWAYS visible */
113 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
115 if (backends.empty()) {
116 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
118 throw failed_constructor ();
121 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
122 backend_names.push_back ((*b)->name);
125 set_popdown_strings (backend_combo, backend_names);
127 /* setup basic packing characteristics for the table used on the main
128 * tab of the notebook
131 basic_packer.set_spacings (6);
132 basic_packer.set_border_width (12);
133 basic_packer.set_homogeneous (false);
137 basic_hbox.pack_start (basic_packer, false, false);
139 /* latency measurement tab */
141 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
144 lm_table.set_row_spacings (12);
145 lm_table.set_col_spacings (6);
146 lm_table.set_homogeneous (false);
148 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
151 lm_preamble.set_width_chars (60);
152 lm_preamble.set_line_wrap (true);
153 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
155 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
158 Gtk::Label* preamble;
159 preamble = manage (new Label);
160 preamble->set_width_chars (60);
161 preamble->set_line_wrap (true);
162 preamble->set_markup (_("Select two channels below and connect them using a cable."));
164 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
167 label = manage (new Label (_("Output channel")));
168 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
170 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
171 misc_align->add (lm_output_channel_combo);
172 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
175 label = manage (new Label (_("Input channel")));
176 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
178 misc_align = manage (new Alignment (0.0, 0.5));
179 misc_align->add (lm_input_channel_combo);
180 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
183 lm_measure_label.set_padding (10, 10);
184 lm_measure_button.add (lm_measure_label);
185 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
186 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
187 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
189 lm_use_button.set_sensitive (false);
191 /* Increase the default spacing around the labels of these three
197 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
198 l->set_padding (10, 10);
201 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
202 l->set_padding (10, 10);
205 preamble = manage (new Label);
206 preamble->set_width_chars (60);
207 preamble->set_line_wrap (true);
208 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
209 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
212 preamble = manage (new Label);
213 preamble->set_width_chars (60);
214 preamble->set_line_wrap (true);
215 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
216 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
218 ++row; // skip a row in the table
219 ++row; // skip a row in the table
221 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 ++row; // skip a row in the table
224 ++row; // skip a row in the table
226 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
232 lm_vbox.set_border_width (12);
233 lm_vbox.pack_start (lm_table, false, false);
235 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
239 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
240 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
241 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
242 notebook.set_border_width (12);
244 notebook.set_show_tabs (false);
245 notebook.show_all ();
247 notebook.set_name ("SettingsNotebook");
249 /* packup the notebook */
251 get_vbox()->set_border_width (12);
252 get_vbox()->pack_start (notebook);
254 get_action_area()->pack_start (engine_status);
255 engine_status.show();
257 /* need a special function to print "all available channels" when the
258 * channel counts hit zero.
261 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
262 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
264 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
265 midi_devices_button.set_sensitive (false);
266 midi_devices_button.set_name ("generic button");
267 midi_devices_button.set_can_focus(true);
269 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
270 manage_control_app_sensitivity ();
272 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
273 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
274 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
276 /* Pick up any existing audio setup configuration, if appropriate */
278 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
280 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
281 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
282 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
283 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
286 set_state (*audio_setup);
289 if (backend_combo.get_active_text().empty()) {
290 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
291 backend_combo.set_active_text (backend_names.front());
296 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
297 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
298 backend_combo.set_active_text (backend_names.back());
299 /* ignore: don't save state */
300 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
304 connect_changed_signals ();
306 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
308 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
309 connect_disconnect_button.set_no_show_all();
314 EngineControl::connect_changed_signals ()
316 backend_combo_connection = backend_combo.signal_changed ().connect (
317 sigc::mem_fun (*this, &EngineControl::backend_changed));
318 driver_combo_connection = driver_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::driver_changed));
320 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
322 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
323 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
324 device_combo_connection = device_combo.signal_changed ().connect (
325 sigc::mem_fun (*this, &EngineControl::device_changed));
326 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
327 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
329 input_device_combo_connection = input_device_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::input_device_changed));
331 output_device_combo_connection = output_device_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::output_device_changed));
334 input_latency_connection = input_latency.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::parameter_changed));
336 output_latency_connection = output_latency.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::parameter_changed));
338 input_channels_connection = input_channels.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::parameter_changed));
340 output_channels_connection = output_channels.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::parameter_changed));
345 EngineControl::block_changed_signals ()
347 if (block_signals++ == 0) {
348 DEBUG_ECONTROL ("Blocking changed signals");
349 backend_combo_connection.block ();
350 driver_combo_connection.block ();
351 sample_rate_combo_connection.block ();
352 buffer_size_combo_connection.block ();
353 device_combo_connection.block ();
354 input_device_combo_connection.block ();
355 output_device_combo_connection.block ();
356 midi_option_combo_connection.block ();
357 input_latency_connection.block ();
358 output_latency_connection.block ();
359 input_channels_connection.block ();
360 output_channels_connection.block ();
365 EngineControl::unblock_changed_signals ()
367 if (--block_signals == 0) {
368 DEBUG_ECONTROL ("Unblocking changed signals");
369 backend_combo_connection.unblock ();
370 driver_combo_connection.unblock ();
371 sample_rate_combo_connection.unblock ();
372 buffer_size_combo_connection.unblock ();
373 device_combo_connection.unblock ();
374 input_device_combo_connection.unblock ();
375 output_device_combo_connection.unblock ();
376 midi_option_combo_connection.unblock ();
377 input_latency_connection.unblock ();
378 output_latency_connection.unblock ();
379 input_channels_connection.unblock ();
380 output_channels_connection.unblock ();
384 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
385 const std::string& reason)
386 : ec (engine_control)
389 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
390 ec.block_changed_signals ();
393 EngineControl::SignalBlocker::~SignalBlocker ()
395 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
396 ec.unblock_changed_signals ();
400 EngineControl::on_show ()
402 ArdourDialog::on_show ();
403 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
404 // re-check _have_control (jackd running) see #6041
408 ok_button->grab_focus();
412 EngineControl::on_response (int response_id)
414 ArdourDialog::on_response (response_id);
416 switch (response_id) {
418 push_state_to_backend (true);
421 #ifdef PLATFORM_WINDOWS
422 // For some reason we don't understand, 'hide()'
423 // needs to get called first in Windows
426 // But if there's no session open, this can produce
427 // a long gap when nothing appears to be happening.
428 // Let's show the splash image while we're waiting.
429 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
430 if ( ARDOUR_UI::instance() ) {
431 if ( !ARDOUR_UI::instance()->session_loaded ) {
432 ARDOUR_UI::instance()->show_splash();
436 push_state_to_backend (true);
439 push_state_to_backend (true);
443 case RESPONSE_DELETE_EVENT:
446 ev.type = GDK_BUTTON_PRESS;
448 on_delete_event ((GdkEventAny*) &ev);
457 EngineControl::build_notebook ()
460 AttachOptions xopt = AttachOptions (FILL|EXPAND);
462 /* clear the table */
464 Gtkmm2ext::container_clear (basic_vbox);
465 Gtkmm2ext::container_clear (basic_packer);
467 if (control_app_button.get_parent()) {
468 control_app_button.get_parent()->remove (control_app_button);
471 label = manage (left_aligned_label (_("Audio System:")));
472 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
473 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
475 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
476 lm_button_audio.set_name ("generic button");
477 lm_button_audio.set_can_focus(true);
480 build_full_control_notebook ();
482 build_no_control_notebook ();
485 basic_vbox.pack_start (basic_hbox, false, false);
488 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
489 basic_vbox.show_all ();
494 EngineControl::build_full_control_notebook ()
496 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
499 using namespace Notebook_Helpers;
501 vector<string> strings;
502 AttachOptions xopt = AttachOptions (FILL|EXPAND);
503 int row = 1; // row zero == backend combo
505 /* start packing it up */
507 if (backend->requires_driver_selection()) {
508 label = manage (left_aligned_label (_("Driver:")));
509 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
510 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
514 if (backend->use_separate_input_and_output_devices()) {
515 label = manage (left_aligned_label (_("Input Device:")));
516 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
517 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
519 label = manage (left_aligned_label (_("Output Device:")));
520 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
521 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
523 // reset so it isn't used in state comparisons
524 device_combo.set_active_text ("");
526 label = manage (left_aligned_label (_("Device:")));
527 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
528 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
530 // reset these so they don't get used in state comparisons
531 input_device_combo.set_active_text ("");
532 output_device_combo.set_active_text ("");
535 label = manage (left_aligned_label (_("Sample rate:")));
536 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
537 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
541 label = manage (left_aligned_label (_("Buffer size:")));
542 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
543 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
544 buffer_size_duration_label.set_alignment (0.0); /* left-align */
545 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
547 /* button spans 2 rows */
549 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
552 input_channels.set_name ("InputChannels");
553 input_channels.set_flags (Gtk::CAN_FOCUS);
554 input_channels.set_digits (0);
555 input_channels.set_wrap (false);
556 output_channels.set_editable (true);
558 if (!ARDOUR::Profile->get_mixbus()) {
559 label = manage (left_aligned_label (_("Input Channels:")));
560 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
561 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
565 output_channels.set_name ("OutputChannels");
566 output_channels.set_flags (Gtk::CAN_FOCUS);
567 output_channels.set_digits (0);
568 output_channels.set_wrap (false);
569 output_channels.set_editable (true);
571 if (!ARDOUR::Profile->get_mixbus()) {
572 label = manage (left_aligned_label (_("Output Channels:")));
573 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
574 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
578 input_latency.set_name ("InputLatency");
579 input_latency.set_flags (Gtk::CAN_FOCUS);
580 input_latency.set_digits (0);
581 input_latency.set_wrap (false);
582 input_latency.set_editable (true);
584 label = manage (left_aligned_label (_("Hardware input latency:")));
585 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
586 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
587 label = manage (left_aligned_label (_("samples")));
588 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
591 output_latency.set_name ("OutputLatency");
592 output_latency.set_flags (Gtk::CAN_FOCUS);
593 output_latency.set_digits (0);
594 output_latency.set_wrap (false);
595 output_latency.set_editable (true);
597 label = manage (left_aligned_label (_("Hardware output latency:")));
598 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
599 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
600 label = manage (left_aligned_label (_("samples")));
601 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
603 /* button spans 2 rows */
605 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
608 label = manage (left_aligned_label (_("MIDI System:")));
609 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
610 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
611 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
616 EngineControl::build_no_control_notebook ()
618 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
621 using namespace Notebook_Helpers;
623 vector<string> strings;
624 AttachOptions xopt = AttachOptions (FILL|EXPAND);
625 int row = 1; // row zero == backend combo
626 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
628 label = manage (new Label);
629 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
630 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
633 if (backend->can_change_sample_rate_when_running()) {
634 label = manage (left_aligned_label (_("Sample rate:")));
635 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
636 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
640 if (backend->can_change_buffer_size_when_running()) {
641 label = manage (left_aligned_label (_("Buffer size:")));
642 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
643 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
644 buffer_size_duration_label.set_alignment (0.0); /* left-align */
645 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
649 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
653 EngineControl::~EngineControl ()
655 ignore_changes = true;
659 EngineControl::disable_latency_tab ()
661 vector<string> empty;
662 set_popdown_strings (lm_output_channel_combo, empty);
663 set_popdown_strings (lm_input_channel_combo, empty);
664 lm_measure_button.set_sensitive (false);
665 lm_use_button.set_sensitive (false);
669 EngineControl::enable_latency_tab ()
671 vector<string> outputs;
672 vector<string> inputs;
674 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
675 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
676 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
678 if (!ARDOUR::AudioEngine::instance()->running()) {
679 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
680 notebook.set_current_page (0);
684 else if (inputs.empty() || outputs.empty()) {
685 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
686 notebook.set_current_page (0);
691 lm_back_button_signal.disconnect();
693 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
696 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
700 set_popdown_strings (lm_output_channel_combo, outputs);
701 lm_output_channel_combo.set_active_text (outputs.front());
702 lm_output_channel_combo.set_sensitive (true);
704 set_popdown_strings (lm_input_channel_combo, inputs);
705 lm_input_channel_combo.set_active_text (inputs.front());
706 lm_input_channel_combo.set_sensitive (true);
708 lm_measure_button.set_sensitive (true);
712 EngineControl::setup_midi_tab_for_backend ()
714 string backend = backend_combo.get_active_text ();
716 Gtkmm2ext::container_clear (midi_vbox);
718 midi_vbox.set_border_width (12);
719 midi_device_table.set_border_width (12);
721 if (backend == "JACK") {
722 setup_midi_tab_for_jack ();
725 midi_vbox.pack_start (midi_device_table, true, true);
726 midi_vbox.pack_start (midi_back_button, false, false);
727 midi_vbox.show_all ();
731 EngineControl::setup_midi_tab_for_jack ()
736 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
738 device->input_latency = a->get_value();
740 device->output_latency = a->get_value();
745 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
746 b->set_active (!b->get_active());
747 device->enabled = b->get_active();
748 refresh_midi_display(device->name);
752 EngineControl::refresh_midi_display (std::string focus)
754 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
758 AttachOptions xopt = AttachOptions (FILL|EXPAND);
761 Gtkmm2ext::container_clear (midi_device_table);
763 midi_device_table.set_spacings (6);
765 l = manage (new Label);
766 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
767 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
768 l->set_alignment (0.5, 0.5);
772 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
773 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
774 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
775 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
777 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
778 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
779 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
780 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
783 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
788 bool enabled = (*p)->enabled;
790 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
791 m->set_name ("midi device");
792 m->set_can_focus (Gtk::CAN_FOCUS);
793 m->add_events (Gdk::BUTTON_RELEASE_MASK);
794 m->set_active (enabled);
795 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
796 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
797 if ((*p)->name == focus) {
801 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
802 s = manage (new Gtk::SpinButton (*a));
803 a->set_value ((*p)->input_latency);
804 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
805 s->set_sensitive (_can_set_midi_latencies && enabled);
806 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
808 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
809 s = manage (new Gtk::SpinButton (*a));
810 a->set_value ((*p)->output_latency);
811 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
812 s->set_sensitive (_can_set_midi_latencies && enabled);
813 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
815 b = manage (new Button (_("Calibrate")));
816 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
817 b->set_sensitive (_can_set_midi_latencies && enabled);
818 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
825 EngineControl::backend_changed ()
827 SignalBlocker blocker (*this, "backend_changed");
828 string backend_name = backend_combo.get_active_text();
829 boost::shared_ptr<ARDOUR::AudioBackend> backend;
831 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
832 /* eh? setting the backend failed... how ? */
833 /* A: stale config contains a backend that does not exist in current build */
837 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
839 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
842 setup_midi_tab_for_backend ();
843 _midi_devices.clear();
845 if (backend->requires_driver_selection()) {
846 if (set_driver_popdown_strings ()) {
847 driver_combo.set_sensitive (true);
852 driver_combo.set_sensitive (false);
853 /* this will change the device text which will cause a call to
854 * device changed which will set up parameters
859 update_midi_options ();
861 connect_disconnect_button.hide();
863 midi_option_changed();
865 started_at_least_once = false;
867 if (!ignore_changes) {
868 maybe_display_saved_state ();
873 EngineControl::update_midi_options ()
875 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
876 vector<string> midi_options = backend->enumerate_midi_options();
878 if (midi_options.size() == 1) {
879 /* only contains the "none" option */
880 midi_option_combo.set_sensitive (false);
883 set_popdown_strings (midi_option_combo, midi_options);
884 midi_option_combo.set_active_text (midi_options.front());
885 midi_option_combo.set_sensitive (true);
887 midi_option_combo.set_sensitive (false);
893 EngineControl::print_channel_count (Gtk::SpinButton* sb)
895 if (ARDOUR::Profile->get_mixbus()) {
899 uint32_t cnt = (uint32_t) sb->get_value();
901 sb->set_text (_("all available channels"));
904 snprintf (buf, sizeof (buf), "%d", cnt);
910 // @return true if there are drivers available
912 EngineControl::set_driver_popdown_strings ()
914 DEBUG_ECONTROL ("set_driver_popdown_strings");
915 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
916 vector<string> drivers = backend->enumerate_drivers();
918 if (drivers.empty()) {
919 // This is an error...?
923 string current_driver;
924 current_driver = backend->driver_name ();
926 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
928 // driver might not have been set yet
929 if (current_driver == "") {
930 current_driver = driver_combo.get_active_text ();
931 if (current_driver == "")
932 // driver has never been set, make sure it's not blank
933 current_driver = drivers.front ();
936 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
937 set_popdown_strings (driver_combo, drivers);
939 string_compose ("driver_combo.set_active_text: %1", current_driver));
940 driver_combo.set_active_text (current_driver);
944 // @return true if there are devices available
946 EngineControl::set_device_popdown_strings ()
948 DEBUG_ECONTROL ("set_device_popdown_strings");
949 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
950 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
952 /* NOTE: Ardour currently does not display the "available" field of the
955 * Doing so would require a different GUI widget than the combo
956 * box/popdown that we currently use, since it has no way to list
957 * items that are not selectable. Something more like a popup menu,
958 * which could have unselectable items, would be appropriate.
961 vector<string> available_devices;
963 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
964 available_devices.push_back (i->name);
968 if (!available_devices.empty()) {
971 string current_device, found_device;
972 current_device = device_combo.get_active_text ();
973 if (current_device == "") {
974 current_device = backend->device_name ();
977 // Make sure that the active text is still relevant for this
978 // device (it might only be relevant to the previous device!!)
979 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
980 if (*i == current_device)
981 found_device = current_device;
983 if (found_device == "")
984 // device has never been set (or was not relevant
985 // for this backend) Let's make sure it's not blank
986 current_device = available_devices.front ();
988 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
989 set_popdown_strings (device_combo, available_devices);
990 DEBUG_ECONTROL (string_compose ("set device_combo active text: %1", current_device));
992 device_combo.set_active_text (current_device);
999 // @return true if there are input devices available
1001 EngineControl::set_input_device_popdown_strings ()
1003 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1004 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1005 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1007 vector<string> available_devices;
1009 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1010 available_devices.push_back (i->name);
1013 if (!available_devices.empty()) {
1016 string current_device, found_device;
1017 current_device = input_device_combo.get_active_text ();
1018 if (current_device == "") {
1019 current_device = backend->input_device_name ();
1022 // Make sure that the active text is still relevant for this
1023 // device (it might only be relevant to the previous device!!)
1024 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1025 if (*i == current_device)
1026 found_device = current_device;
1028 if (found_device == "")
1029 // device has never been set (or was not relevant
1030 // for this backend) Let's make sure it's not blank
1031 current_device = available_devices.front ();
1033 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1034 set_popdown_strings (input_device_combo, available_devices);
1036 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1037 input_device_combo.set_active_text (current_device);
1045 // @return true if there are output devices available
1047 EngineControl::set_output_device_popdown_strings ()
1049 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1050 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1051 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1053 vector<string> available_devices;
1055 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1056 available_devices.push_back (i->name);
1059 if (!available_devices.empty()) {
1062 string current_device, found_device;
1063 current_device = output_device_combo.get_active_text ();
1064 if (current_device == "") {
1065 current_device = backend->output_device_name ();
1068 // Make sure that the active text is still relevant for this
1069 // device (it might only be relevant to the previous device!!)
1070 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1071 if (*i == current_device)
1072 found_device = current_device;
1074 if (found_device == "")
1075 // device has never been set (or was not relevant
1076 // for this backend) Let's make sure it's not blank
1077 current_device = available_devices.front ();
1079 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1080 set_popdown_strings (output_device_combo, available_devices);
1082 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1083 output_device_combo.set_active_text (current_device);
1092 EngineControl::list_devices ()
1094 DEBUG_ECONTROL ("list_devices");
1095 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1098 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1100 bool devices_available = false;
1102 if (backend->use_separate_input_and_output_devices ()) {
1103 bool input_devices_available = set_input_device_popdown_strings ();
1104 bool output_devices_available = set_output_device_popdown_strings ();
1105 devices_available = input_devices_available || output_devices_available;
1107 devices_available = set_device_popdown_strings ();
1110 if (devices_available) {
1113 input_latency.set_sensitive (true);
1114 output_latency.set_sensitive (true);
1115 input_channels.set_sensitive (true);
1116 output_channels.set_sensitive (true);
1118 ok_button->set_sensitive (true);
1119 apply_button->set_sensitive (true);
1122 device_combo.clear();
1123 input_device_combo.clear();
1124 output_device_combo.clear();
1125 sample_rate_combo.set_sensitive (false);
1126 buffer_size_combo.set_sensitive (false);
1127 input_latency.set_sensitive (false);
1128 output_latency.set_sensitive (false);
1129 input_channels.set_sensitive (false);
1130 output_channels.set_sensitive (false);
1131 if (_have_control) {
1132 ok_button->set_sensitive (false);
1133 apply_button->set_sensitive (false);
1135 ok_button->set_sensitive (true);
1136 apply_button->set_sensitive (true);
1137 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1138 sample_rate_combo.set_sensitive (true);
1140 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1141 buffer_size_combo.set_sensitive (true);
1149 EngineControl::driver_changed ()
1151 SignalBlocker blocker (*this, "driver_changed");
1152 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1155 backend->set_driver (driver_combo.get_active_text());
1158 if (!ignore_changes) {
1159 maybe_display_saved_state ();
1164 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1166 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1167 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1172 if (_have_control) {
1173 sr = backend->available_sample_rates (device_name);
1176 sr.push_back (8000.0f);
1177 sr.push_back (16000.0f);
1178 sr.push_back (32000.0f);
1179 sr.push_back (44100.0f);
1180 sr.push_back (48000.0f);
1181 sr.push_back (88200.0f);
1182 sr.push_back (96000.0f);
1183 sr.push_back (192000.0f);
1184 sr.push_back (384000.0f);
1187 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1188 s.push_back (rate_as_string (*x));
1189 if (*x == _desired_sample_rate) {
1195 sample_rate_combo.set_sensitive (true);
1196 set_popdown_strings (sample_rate_combo, s);
1198 if (desired.empty()) {
1199 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1201 sample_rate_combo.set_active_text (desired);
1205 sample_rate_combo.set_sensitive (false);
1210 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1212 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1213 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1214 vector<uint32_t> bs;
1217 if (_have_control) {
1218 bs = backend->available_buffer_sizes (device_name);
1219 } else if (backend->can_change_buffer_size_when_running()) {
1227 bs.push_back (1024);
1228 bs.push_back (2048);
1229 bs.push_back (4096);
1230 bs.push_back (8192);
1233 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1234 s.push_back (bufsize_as_string (*x));
1238 buffer_size_combo.set_sensitive (true);
1239 set_popdown_strings (buffer_size_combo, s);
1240 buffer_size_combo.set_active_text (s.front());
1242 uint32_t period = backend->buffer_size();
1244 period = backend->default_buffer_size(device_name);
1246 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1247 show_buffer_duration ();
1249 buffer_size_combo.set_sensitive (false);
1254 EngineControl::device_changed ()
1256 SignalBlocker blocker (*this, "device_changed");
1257 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1260 string device_name_in;
1261 string device_name_out; // only used if backend support separate I/O devices
1263 if (backend->use_separate_input_and_output_devices()) {
1264 device_name_in = get_input_device_name ();
1265 device_name_out = get_output_device_name ();
1267 device_name_in = get_device_name ();
1270 /* we set the backend-device to query various device related intormation.
1271 * This has the side effect that backend->device_name() will match
1272 * the device_name and 'change_device' will never be true.
1273 * so work around this by setting...
1275 if (backend->use_separate_input_and_output_devices()) {
1276 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1277 queue_device_changed = true;
1280 if (device_name_in != backend->device_name()) {
1281 queue_device_changed = true;
1285 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1286 if (backend->use_separate_input_and_output_devices()) {
1287 backend->set_input_device_name (device_name_in);
1288 backend->set_output_device_name (device_name_out);
1290 backend->set_device_name(device_name_in);
1294 /* don't allow programmatic change to combos to cause a
1295 recursive call to this method.
1297 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1299 /* backends that support separate devices, need to ignore
1300 * the device-name - and use the devies set above
1302 set_samplerate_popdown_strings (device_name_in);
1303 set_buffersize_popdown_strings (device_name_in);
1304 /* XXX theoretically need to set min + max channel counts here
1307 manage_control_app_sensitivity ();
1310 /* pick up any saved state for this device */
1312 if (!ignore_changes) {
1313 maybe_display_saved_state ();
1318 EngineControl::input_device_changed ()
1320 DEBUG_ECONTROL ("input_device_changed");
1325 EngineControl::output_device_changed ()
1327 DEBUG_ECONTROL ("output_device_changed");
1332 EngineControl::bufsize_as_string (uint32_t sz)
1334 /* Translators: "samples" is always plural here, so no
1335 need for plural+singular forms.
1338 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1343 EngineControl::sample_rate_changed ()
1345 DEBUG_ECONTROL ("sample_rate_changed");
1346 /* reset the strings for buffer size to show the correct msec value
1347 (reflecting the new sample rate).
1350 show_buffer_duration ();
1355 EngineControl::buffer_size_changed ()
1357 DEBUG_ECONTROL ("buffer_size_changed");
1358 show_buffer_duration ();
1362 EngineControl::show_buffer_duration ()
1364 DEBUG_ECONTROL ("show_buffer_duration");
1365 /* buffer sizes - convert from just samples to samples + msecs for
1366 * the displayed string
1369 string bs_text = buffer_size_combo.get_active_text ();
1370 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1371 uint32_t rate = get_rate();
1373 /* Developers: note the hard-coding of a double buffered model
1374 in the (2 * samples) computation of latency. we always start
1375 the audiobackend in this configuration.
1377 /* note to jack1 developers: ardour also always starts the engine
1378 * in async mode (no jack2 --sync option) which adds an extra cycle
1379 * of latency with jack2 (and *3 would be correct)
1380 * The value can also be wrong if jackd is started externally..
1382 * At the time of writing the ALSA backend always uses double-buffering *2,
1383 * The Dummy backend *1, and who knows what ASIO really does :)
1385 * So just display the period size, that's also what
1386 * ARDOUR_UI::update_sample_rate() does for the status bar.
1387 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1388 * but still, that's the buffer period, not [round-trip] latency)
1391 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1392 buffer_size_duration_label.set_text (buf);
1396 EngineControl::midi_option_changed ()
1398 DEBUG_ECONTROL ("midi_option_changed");
1399 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1402 backend->set_midi_option (get_midi_option());
1404 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1406 //_midi_devices.clear(); // TODO merge with state-saved settings..
1407 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1408 std::vector<MidiDeviceSettings> new_devices;
1410 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1411 MidiDeviceSettings mds = find_midi_device (i->name);
1412 if (i->available && !mds) {
1413 uint32_t input_latency = 0;
1414 uint32_t output_latency = 0;
1415 if (_can_set_midi_latencies) {
1416 input_latency = backend->systemic_midi_input_latency (i->name);
1417 output_latency = backend->systemic_midi_output_latency (i->name);
1419 bool enabled = backend->midi_device_enabled (i->name);
1420 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1421 new_devices.push_back (ptr);
1422 } else if (i->available) {
1423 new_devices.push_back (mds);
1426 _midi_devices = new_devices;
1428 if (_midi_devices.empty()) {
1429 midi_devices_button.set_sensitive (false);
1431 midi_devices_button.set_sensitive (true);
1436 EngineControl::parameter_changed ()
1440 EngineControl::State
1441 EngineControl::get_matching_state (
1442 const string& backend,
1443 const string& driver,
1444 const string& device)
1446 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1447 if ((*i)->backend == backend &&
1448 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1456 EngineControl::State
1457 EngineControl::get_matching_state (
1458 const string& backend,
1459 const string& driver,
1460 const string& input_device,
1461 const string& output_device)
1463 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1464 if ((*i)->backend == backend &&
1465 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1473 EngineControl::State
1474 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1476 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1479 if (backend->use_separate_input_and_output_devices ()) {
1480 return get_matching_state (backend_combo.get_active_text(),
1481 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1482 input_device_combo.get_active_text(),
1483 output_device_combo.get_active_text());
1485 return get_matching_state (backend_combo.get_active_text(),
1486 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1487 device_combo.get_active_text());
1491 return get_matching_state (backend_combo.get_active_text(),
1493 device_combo.get_active_text());
1496 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1497 const EngineControl::State& state2)
1499 if (state1->backend == state2->backend &&
1500 state1->driver == state2->driver &&
1501 state1->device == state2->device &&
1502 state1->input_device == state2->input_device &&
1503 state1->output_device == state2->output_device) {
1509 EngineControl::State
1510 EngineControl::save_state ()
1514 if (!_have_control) {
1515 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1519 state.reset(new StateStruct);
1520 state->backend = get_backend ();
1522 state.reset(new StateStruct);
1523 store_state (state);
1526 for (StateList::iterator i = states.begin(); i != states.end();) {
1527 if (equivalent_states (*i, state)) {
1528 i = states.erase(i);
1534 states.push_back (state);
1540 EngineControl::store_state (State state)
1542 state->backend = get_backend ();
1543 state->driver = get_driver ();
1544 state->device = get_device_name ();
1545 state->input_device = get_input_device_name ();
1546 state->output_device = get_output_device_name ();
1547 state->sample_rate = get_rate ();
1548 state->buffer_size = get_buffer_size ();
1549 state->input_latency = get_input_latency ();
1550 state->output_latency = get_output_latency ();
1551 state->input_channels = get_input_channels ();
1552 state->output_channels = get_output_channels ();
1553 state->midi_option = get_midi_option ();
1554 state->midi_devices = _midi_devices;
1558 EngineControl::maybe_display_saved_state ()
1560 if (!_have_control) {
1564 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1567 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1569 if (!_desired_sample_rate) {
1570 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1572 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1573 /* call this explicitly because we're ignoring changes to
1574 the controls at this point.
1576 show_buffer_duration ();
1577 input_latency.set_value (state->input_latency);
1578 output_latency.set_value (state->output_latency);
1580 if (!state->midi_option.empty()) {
1581 midi_option_combo.set_active_text (state->midi_option);
1582 _midi_devices = state->midi_devices;
1588 EngineControl::get_state ()
1590 LocaleGuard lg (X_("C"));
1592 XMLNode* root = new XMLNode ("AudioMIDISetup");
1595 if (!states.empty()) {
1596 XMLNode* state_nodes = new XMLNode ("EngineStates");
1598 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1600 XMLNode* node = new XMLNode ("State");
1602 node->add_property ("backend", (*i)->backend);
1603 node->add_property ("driver", (*i)->driver);
1604 node->add_property ("device", (*i)->device);
1605 node->add_property ("input-device", (*i)->input_device);
1606 node->add_property ("output-device", (*i)->output_device);
1607 node->add_property ("sample-rate", (*i)->sample_rate);
1608 node->add_property ("buffer-size", (*i)->buffer_size);
1609 node->add_property ("input-latency", (*i)->input_latency);
1610 node->add_property ("output-latency", (*i)->output_latency);
1611 node->add_property ("input-channels", (*i)->input_channels);
1612 node->add_property ("output-channels", (*i)->output_channels);
1613 node->add_property ("active", (*i)->active ? "yes" : "no");
1614 node->add_property ("midi-option", (*i)->midi_option);
1616 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1617 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1618 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1619 midi_device_stuff->add_property (X_("name"), (*p)->name);
1620 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1621 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1622 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1623 midi_devices->add_child_nocopy (*midi_device_stuff);
1625 node->add_child_nocopy (*midi_devices);
1627 state_nodes->add_child_nocopy (*node);
1630 root->add_child_nocopy (*state_nodes);
1637 EngineControl::set_state (const XMLNode& root)
1639 XMLNodeList clist, cclist;
1640 XMLNodeConstIterator citer, cciter;
1642 XMLNode* grandchild;
1643 XMLProperty* prop = NULL;
1645 fprintf (stderr, "EngineControl::set_state\n");
1647 if (root.name() != "AudioMIDISetup") {
1651 clist = root.children();
1655 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1659 if (child->name() != "EngineStates") {
1663 cclist = child->children();
1665 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1666 State state (new StateStruct);
1668 grandchild = *cciter;
1670 if (grandchild->name() != "State") {
1674 if ((prop = grandchild->property ("backend")) == 0) {
1677 state->backend = prop->value ();
1679 if ((prop = grandchild->property ("driver")) == 0) {
1682 state->driver = prop->value ();
1684 if ((prop = grandchild->property ("device")) == 0) {
1687 state->device = prop->value ();
1689 if ((prop = grandchild->property ("input-device")) == 0) {
1692 state->input_device = prop->value ();
1694 if ((prop = grandchild->property ("output-device")) == 0) {
1697 state->output_device = prop->value ();
1699 if ((prop = grandchild->property ("sample-rate")) == 0) {
1702 state->sample_rate = atof (prop->value ());
1704 if ((prop = grandchild->property ("buffer-size")) == 0) {
1707 state->buffer_size = atoi (prop->value ());
1709 if ((prop = grandchild->property ("input-latency")) == 0) {
1712 state->input_latency = atoi (prop->value ());
1714 if ((prop = grandchild->property ("output-latency")) == 0) {
1717 state->output_latency = atoi (prop->value ());
1719 if ((prop = grandchild->property ("input-channels")) == 0) {
1722 state->input_channels = atoi (prop->value ());
1724 if ((prop = grandchild->property ("output-channels")) == 0) {
1727 state->output_channels = atoi (prop->value ());
1729 if ((prop = grandchild->property ("active")) == 0) {
1732 state->active = string_is_affirmative (prop->value ());
1734 if ((prop = grandchild->property ("midi-option")) == 0) {
1737 state->midi_option = prop->value ();
1739 state->midi_devices.clear();
1741 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1742 const XMLNodeList mnc = midinode->children();
1743 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1744 if ((*n)->property (X_("name")) == 0
1745 || (*n)->property (X_("enabled")) == 0
1746 || (*n)->property (X_("input-latency")) == 0
1747 || (*n)->property (X_("output-latency")) == 0
1752 MidiDeviceSettings ptr (new MidiDeviceSetting(
1753 (*n)->property (X_("name"))->value (),
1754 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1755 atoi ((*n)->property (X_("input-latency"))->value ()),
1756 atoi ((*n)->property (X_("output-latency"))->value ())
1758 state->midi_devices.push_back (ptr);
1763 /* remove accumulated duplicates (due to bug in ealier version)
1764 * this can be removed again before release
1766 for (StateList::iterator i = states.begin(); i != states.end();) {
1767 if ((*i)->backend == state->backend &&
1768 (*i)->driver == state->driver &&
1769 (*i)->device == state->device) {
1770 i = states.erase(i);
1777 states.push_back (state);
1781 /* now see if there was an active state and switch the setup to it */
1783 // purge states of backend that are not available in this built
1784 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1785 vector<std::string> backend_names;
1787 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1788 backend_names.push_back((*i)->name);
1790 for (StateList::iterator i = states.begin(); i != states.end();) {
1791 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1792 i = states.erase(i);
1798 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1801 set_current_state (*i);
1808 EngineControl::set_current_state (const State& state)
1810 DEBUG_ECONTROL ("set_current_state");
1811 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1812 backend_combo.set_active_text (state->backend);
1813 driver_combo.set_active_text (state->driver);
1816 device_combo.set_active_text (state->device);
1817 input_device_combo.set_active_text (state->input_device);
1818 output_device_combo.set_active_text (state->output_device);
1819 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1820 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1821 input_latency.set_value (state->input_latency);
1822 output_latency.set_value (state->output_latency);
1823 midi_option_combo.set_active_text (state->midi_option);
1827 EngineControl::push_state_to_backend (bool start)
1829 DEBUG_ECONTROL ("push_state_to_backend");
1830 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1836 /* figure out what is going to change */
1838 bool restart_required = false;
1839 bool was_running = ARDOUR::AudioEngine::instance()->running();
1840 bool change_driver = false;
1841 bool change_device = false;
1842 bool change_rate = false;
1843 bool change_bufsize = false;
1844 bool change_latency = false;
1845 bool change_channels = false;
1846 bool change_midi = false;
1848 uint32_t ochan = get_output_channels ();
1849 uint32_t ichan = get_input_channels ();
1851 if (_have_control) {
1853 if (started_at_least_once) {
1855 /* we can control the backend */
1857 if (backend->requires_driver_selection()) {
1858 if (get_driver() != backend->driver_name()) {
1859 change_driver = true;
1863 if (backend->use_separate_input_and_output_devices()) {
1864 if (get_input_device_name() != backend->input_device_name()) {
1865 change_device = true;
1867 if (get_output_device_name() != backend->output_device_name()) {
1868 change_device = true;
1871 if (get_device_name() != backend->device_name()) {
1872 change_device = true;
1876 if (queue_device_changed) {
1877 change_device = true;
1880 if (get_rate() != backend->sample_rate()) {
1884 if (get_buffer_size() != backend->buffer_size()) {
1885 change_bufsize = true;
1888 if (get_midi_option() != backend->midi_option()) {
1892 /* zero-requested channels means "all available" */
1895 ichan = backend->input_channels();
1899 ochan = backend->output_channels();
1902 if (ichan != backend->input_channels()) {
1903 change_channels = true;
1906 if (ochan != backend->output_channels()) {
1907 change_channels = true;
1910 if (get_input_latency() != backend->systemic_input_latency() ||
1911 get_output_latency() != backend->systemic_output_latency()) {
1912 change_latency = true;
1915 /* backend never started, so we have to force a group
1918 change_device = true;
1919 if (backend->requires_driver_selection()) {
1920 change_driver = true;
1923 change_bufsize = true;
1924 change_channels = true;
1925 change_latency = true;
1931 /* we have no control over the backend, meaning that we can
1932 * only possibly change sample rate and buffer size.
1936 if (get_rate() != backend->sample_rate()) {
1937 change_bufsize = true;
1940 if (get_buffer_size() != backend->buffer_size()) {
1941 change_bufsize = true;
1945 queue_device_changed = false;
1947 if (!_have_control) {
1949 /* We do not have control over the backend, so the best we can
1950 * do is try to change the sample rate and/or bufsize and get
1954 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1958 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1963 backend->set_sample_rate (get_rate());
1966 if (change_bufsize) {
1967 backend->set_buffer_size (get_buffer_size());
1971 if (ARDOUR::AudioEngine::instance()->start ()) {
1972 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1982 /* determine if we need to stop the backend before changing parameters */
1984 if (change_driver || change_device || change_channels || change_latency ||
1985 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1987 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1988 restart_required = true;
1990 restart_required = false;
1995 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1996 /* no changes in any parameters that absolutely require a
1997 * restart, so check those that might be changeable without a
2001 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2002 /* can't do this while running ... */
2003 restart_required = true;
2006 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2007 /* can't do this while running ... */
2008 restart_required = true;
2014 if (restart_required) {
2015 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2022 if (change_driver && backend->set_driver (get_driver())) {
2023 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2026 if (backend->use_separate_input_and_output_devices()) {
2027 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2028 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2031 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2032 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2036 if (change_device && backend->set_device_name (get_device_name())) {
2037 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2041 if (change_rate && backend->set_sample_rate (get_rate())) {
2042 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2045 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2046 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2050 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2051 if (backend->set_input_channels (get_input_channels())) {
2052 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2055 if (backend->set_output_channels (get_output_channels())) {
2056 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2060 if (change_latency) {
2061 if (backend->set_systemic_input_latency (get_input_latency())) {
2062 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2065 if (backend->set_systemic_output_latency (get_output_latency())) {
2066 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2072 backend->set_midi_option (get_midi_option());
2076 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2077 if (_measure_midi) {
2078 if (*p == _measure_midi) {
2079 backend->set_midi_device_enabled ((*p)->name, true);
2081 backend->set_midi_device_enabled ((*p)->name, false);
2085 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2086 if (backend->can_set_systemic_midi_latencies()) {
2087 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2088 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2093 if (start || (was_running && restart_required)) {
2094 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2105 EngineControl::post_push ()
2107 /* get a pointer to the current state object, creating one if
2111 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2114 state = save_state ();
2122 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2123 (*i)->active = false;
2126 /* mark this one active (to be used next time the dialog is
2130 state->active = true;
2132 if (_have_control) { // XXX
2133 manage_control_app_sensitivity ();
2136 /* schedule a redisplay of MIDI ports */
2137 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2142 EngineControl::get_rate () const
2144 float r = atof (sample_rate_combo.get_active_text ());
2145 /* the string may have been translated with an abbreviation for
2146 * thousands, so use a crude heuristic to fix this.
2156 EngineControl::get_buffer_size () const
2158 string txt = buffer_size_combo.get_active_text ();
2161 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2162 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2163 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2171 EngineControl::get_midi_option () const
2173 return midi_option_combo.get_active_text();
2177 EngineControl::get_input_channels() const
2179 if (ARDOUR::Profile->get_mixbus()) {
2180 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2181 if (!backend) return 0;
2182 return backend->input_channels();
2184 return (uint32_t) input_channels_adjustment.get_value();
2188 EngineControl::get_output_channels() const
2190 if (ARDOUR::Profile->get_mixbus()) {
2191 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2192 if (!backend) return 0;
2193 return backend->input_channels();
2195 return (uint32_t) output_channels_adjustment.get_value();
2199 EngineControl::get_input_latency() const
2201 return (uint32_t) input_latency_adjustment.get_value();
2205 EngineControl::get_output_latency() const
2207 return (uint32_t) output_latency_adjustment.get_value();
2211 EngineControl::get_backend () const
2213 return backend_combo.get_active_text ();
2217 EngineControl::get_driver () const
2219 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2220 return driver_combo.get_active_text ();
2227 EngineControl::get_device_name () const
2229 return device_combo.get_active_text ();
2233 EngineControl::get_input_device_name () const
2235 return input_device_combo.get_active_text ();
2239 EngineControl::get_output_device_name () const
2241 return output_device_combo.get_active_text ();
2245 EngineControl::control_app_button_clicked ()
2247 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2253 backend->launch_control_app ();
2257 EngineControl::manage_control_app_sensitivity ()
2259 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2265 string appname = backend->control_app_name();
2267 if (appname.empty()) {
2268 control_app_button.set_sensitive (false);
2270 control_app_button.set_sensitive (true);
2275 EngineControl::set_desired_sample_rate (uint32_t sr)
2277 _desired_sample_rate = sr;
2282 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2284 if (page_num == 0) {
2285 cancel_button->set_sensitive (true);
2286 ok_button->set_sensitive (true);
2287 apply_button->set_sensitive (true);
2288 _measure_midi.reset();
2290 cancel_button->set_sensitive (false);
2291 ok_button->set_sensitive (false);
2292 apply_button->set_sensitive (false);
2295 if (page_num == midi_tab) {
2297 refresh_midi_display ();
2300 if (page_num == latency_tab) {
2303 if (ARDOUR::AudioEngine::instance()->running()) {
2304 // TODO - mark as 'stopped for latency
2305 ARDOUR_UI::instance()->disconnect_from_engine ();
2309 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2311 /* save any existing latency values */
2313 uint32_t il = (uint32_t) input_latency.get_value ();
2314 uint32_t ol = (uint32_t) input_latency.get_value ();
2316 /* reset to zero so that our new test instance
2317 will be clean of any existing latency measures.
2319 NB. this should really be done by the backend
2320 when stated for latency measurement.
2323 input_latency.set_value (0);
2324 output_latency.set_value (0);
2326 push_state_to_backend (false);
2330 input_latency.set_value (il);
2331 output_latency.set_value (ol);
2334 // This should be done in push_state_to_backend()
2335 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2336 disable_latency_tab ();
2339 enable_latency_tab ();
2343 end_latency_detection ();
2344 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2349 /* latency measurement */
2352 EngineControl::check_audio_latency_measurement ()
2354 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2356 if (mtdm->resolve () < 0) {
2357 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2361 if (mtdm->err () > 0.3) {
2367 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2369 if (sample_rate == 0) {
2370 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2371 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2375 int frames_total = mtdm->del();
2376 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2378 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2379 _("Detected roundtrip latency: "),
2380 frames_total, frames_total * 1000.0f/sample_rate,
2381 _("Systemic latency: "),
2382 extra, extra * 1000.0f/sample_rate);
2386 if (mtdm->err () > 0.2) {
2388 strcat (buf, _("(signal detection error)"));
2394 strcat (buf, _("(inverted - bad wiring)"));
2398 lm_results.set_markup (string_compose (results_markup, buf));
2401 have_lm_results = true;
2402 end_latency_detection ();
2403 lm_use_button.set_sensitive (true);
2411 EngineControl::check_midi_latency_measurement ()
2413 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2415 if (!mididm->have_signal () || mididm->latency () == 0) {
2416 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2421 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2423 if (sample_rate == 0) {
2424 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2425 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2429 ARDOUR::framecnt_t frames_total = mididm->latency();
2430 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2431 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2432 _("Detected roundtrip latency: "),
2433 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2434 _("Systemic latency: "),
2435 extra, extra * 1000.0f / sample_rate);
2439 if (!mididm->ok ()) {
2441 strcat (buf, _("(averaging)"));
2445 if (mididm->deviation () > 50.0) {
2447 strcat (buf, _("(too large jitter)"));
2449 } else if (mididm->deviation () > 10.0) {
2451 strcat (buf, _("(large jitter)"));
2455 have_lm_results = true;
2456 end_latency_detection ();
2457 lm_use_button.set_sensitive (true);
2458 lm_results.set_markup (string_compose (results_markup, buf));
2460 } else if (mididm->processed () > 400) {
2461 have_lm_results = false;
2462 end_latency_detection ();
2463 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2467 lm_results.set_markup (string_compose (results_markup, buf));
2473 EngineControl::start_latency_detection ()
2475 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2476 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2478 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2479 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2480 if (_measure_midi) {
2481 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2483 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2485 lm_measure_label.set_text (_("Cancel"));
2486 have_lm_results = false;
2487 lm_use_button.set_sensitive (false);
2488 lm_input_channel_combo.set_sensitive (false);
2489 lm_output_channel_combo.set_sensitive (false);
2495 EngineControl::end_latency_detection ()
2497 latency_timeout.disconnect ();
2498 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2499 lm_measure_label.set_text (_("Measure"));
2500 if (!have_lm_results) {
2501 lm_use_button.set_sensitive (false);
2503 lm_input_channel_combo.set_sensitive (true);
2504 lm_output_channel_combo.set_sensitive (true);
2509 EngineControl::latency_button_clicked ()
2512 start_latency_detection ();
2514 end_latency_detection ();
2519 EngineControl::use_latency_button_clicked ()
2521 if (_measure_midi) {
2522 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2526 ARDOUR::framecnt_t frames_total = mididm->latency();
2527 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2528 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2529 _measure_midi->input_latency = one_way;
2530 _measure_midi->output_latency = one_way;
2531 notebook.set_current_page (midi_tab);
2533 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2539 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2540 one_way = std::max (0., one_way);
2542 input_latency_adjustment.set_value (one_way);
2543 output_latency_adjustment.set_value (one_way);
2545 /* back to settings page */
2546 notebook.set_current_page (0);
2552 EngineControl::on_delete_event (GdkEventAny* ev)
2554 if (notebook.get_current_page() == 2) {
2555 /* currently on latency tab - be sure to clean up */
2556 end_latency_detection ();
2558 return ArdourDialog::on_delete_event (ev);
2562 EngineControl::engine_running ()
2564 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2567 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2568 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2570 buffer_size_combo.set_sensitive (true);
2571 sample_rate_combo.set_sensitive (true);
2573 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2574 connect_disconnect_button.show();
2576 started_at_least_once = true;
2577 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2581 EngineControl::engine_stopped ()
2583 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2586 buffer_size_combo.set_sensitive (false);
2587 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2588 connect_disconnect_button.show();
2590 sample_rate_combo.set_sensitive (true);
2591 buffer_size_combo.set_sensitive (true);
2592 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2596 EngineControl::device_list_changed ()
2598 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2600 midi_option_changed();
2604 EngineControl::connect_disconnect_click()
2606 if (ARDOUR::AudioEngine::instance()->running()) {
2607 ARDOUR_UI::instance()->disconnect_from_engine ();
2609 ARDOUR_UI::instance()->reconnect_to_engine ();
2614 EngineControl::calibrate_audio_latency ()
2616 _measure_midi.reset ();
2617 have_lm_results = false;
2618 lm_use_button.set_sensitive (false);
2619 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2620 notebook.set_current_page (latency_tab);
2624 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2627 have_lm_results = false;
2628 lm_use_button.set_sensitive (false);
2629 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2630 notebook.set_current_page (latency_tab);
2634 EngineControl::configure_midi_devices ()
2636 notebook.set_current_page (midi_tab);