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 DEBUG_ECONTROL ("backend_changed");
829 string backend_name = backend_combo.get_active_text();
830 boost::shared_ptr<ARDOUR::AudioBackend> backend;
832 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
833 /* eh? setting the backend failed... how ? */
834 /* A: stale config contains a backend that does not exist in current build */
838 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
840 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
843 setup_midi_tab_for_backend ();
844 _midi_devices.clear();
846 if (backend->requires_driver_selection()) {
847 vector<string> drivers = backend->enumerate_drivers();
848 driver_combo.set_sensitive (true);
850 if (!drivers.empty()) {
852 string current_driver;
853 current_driver = backend->driver_name ();
855 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
857 // driver might not have been set yet
858 if (current_driver == "") {
859 current_driver = driver_combo.get_active_text ();
860 if (current_driver == "")
861 // driver has never been set, make sure it's not blank
862 current_driver = drivers.front ();
865 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
866 set_popdown_strings (driver_combo, drivers);
868 string_compose ("driver_combo.set_active_text: %1", current_driver));
869 driver_combo.set_active_text (current_driver);
876 driver_combo.set_sensitive (false);
877 /* this will change the device text which will cause a call to
878 * device changed which will set up parameters
883 vector<string> midi_options = backend->enumerate_midi_options();
885 if (midi_options.size() == 1) {
886 /* only contains the "none" option */
887 midi_option_combo.set_sensitive (false);
890 set_popdown_strings (midi_option_combo, midi_options);
891 midi_option_combo.set_active_text (midi_options.front());
892 midi_option_combo.set_sensitive (true);
894 midi_option_combo.set_sensitive (false);
898 connect_disconnect_button.hide();
900 midi_option_changed();
902 started_at_least_once = false;
904 if (!ignore_changes) {
905 maybe_display_saved_state ();
910 EngineControl::print_channel_count (Gtk::SpinButton* sb)
912 if (ARDOUR::Profile->get_mixbus()) {
916 uint32_t cnt = (uint32_t) sb->get_value();
918 sb->set_text (_("all available channels"));
921 snprintf (buf, sizeof (buf), "%d", cnt);
928 EngineControl::set_driver_popdown_strings ()
930 DEBUG_ECONTROL ("set_driver_popdown_strings");
931 string backend_name = backend_combo.get_active_text();
932 boost::shared_ptr<ARDOUR::AudioBackend> backend;
934 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
935 /* eh? setting the backend failed... how ? */
936 /* A: stale config contains a backend that does not exist in current build */
940 vector<string> drivers = backend->enumerate_drivers();
941 set_popdown_strings (driver_combo, drivers);
945 // @return true if there are devices available
947 EngineControl::set_device_popdown_strings ()
949 DEBUG_ECONTROL ("set_device_popdown_strings");
950 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
951 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
953 /* NOTE: Ardour currently does not display the "available" field of the
956 * Doing so would require a different GUI widget than the combo
957 * box/popdown that we currently use, since it has no way to list
958 * items that are not selectable. Something more like a popup menu,
959 * which could have unselectable items, would be appropriate.
962 vector<string> available_devices;
964 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
965 available_devices.push_back (i->name);
969 if (!available_devices.empty()) {
972 string current_device, found_device;
973 current_device = device_combo.get_active_text ();
974 if (current_device == "") {
975 current_device = backend->device_name ();
978 // Make sure that the active text is still relevant for this
979 // device (it might only be relevant to the previous device!!)
980 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
981 if (*i == current_device)
982 found_device = current_device;
984 if (found_device == "")
985 // device has never been set (or was not relevant
986 // for this backend) Let's make sure it's not blank
987 current_device = available_devices.front ();
989 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
990 set_popdown_strings (device_combo, available_devices);
991 DEBUG_ECONTROL (string_compose ("set device_combo active text: %1", current_device));
993 device_combo.set_active_text (current_device);
1000 // @return true if there are input devices available
1002 EngineControl::set_input_device_popdown_strings ()
1004 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1005 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1006 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1008 vector<string> available_devices;
1010 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1011 available_devices.push_back (i->name);
1014 if (!available_devices.empty()) {
1017 string current_device, found_device;
1018 current_device = input_device_combo.get_active_text ();
1019 if (current_device == "") {
1020 current_device = backend->input_device_name ();
1023 // Make sure that the active text is still relevant for this
1024 // device (it might only be relevant to the previous device!!)
1025 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1026 if (*i == current_device)
1027 found_device = current_device;
1029 if (found_device == "")
1030 // device has never been set (or was not relevant
1031 // for this backend) Let's make sure it's not blank
1032 current_device = available_devices.front ();
1034 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1035 set_popdown_strings (input_device_combo, available_devices);
1037 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1038 input_device_combo.set_active_text (current_device);
1046 // @return true if there are output devices available
1048 EngineControl::set_output_device_popdown_strings ()
1050 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1051 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1052 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1054 vector<string> available_devices;
1056 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1057 available_devices.push_back (i->name);
1060 if (!available_devices.empty()) {
1063 string current_device, found_device;
1064 current_device = output_device_combo.get_active_text ();
1065 if (current_device == "") {
1066 current_device = backend->output_device_name ();
1069 // Make sure that the active text is still relevant for this
1070 // device (it might only be relevant to the previous device!!)
1071 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1072 if (*i == current_device)
1073 found_device = current_device;
1075 if (found_device == "")
1076 // device has never been set (or was not relevant
1077 // for this backend) Let's make sure it's not blank
1078 current_device = available_devices.front ();
1080 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1081 set_popdown_strings (output_device_combo, available_devices);
1083 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1084 output_device_combo.set_active_text (current_device);
1093 EngineControl::list_devices ()
1095 DEBUG_ECONTROL ("list_devices");
1096 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1099 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1101 bool devices_available = false;
1103 if (backend->use_separate_input_and_output_devices ()) {
1104 bool input_devices_available = set_input_device_popdown_strings ();
1105 bool output_devices_available = set_output_device_popdown_strings ();
1106 devices_available = input_devices_available || output_devices_available;
1108 devices_available = set_device_popdown_strings ();
1111 if (devices_available) {
1114 input_latency.set_sensitive (true);
1115 output_latency.set_sensitive (true);
1116 input_channels.set_sensitive (true);
1117 output_channels.set_sensitive (true);
1119 ok_button->set_sensitive (true);
1120 apply_button->set_sensitive (true);
1123 device_combo.clear();
1124 input_device_combo.clear();
1125 output_device_combo.clear();
1126 sample_rate_combo.set_sensitive (false);
1127 buffer_size_combo.set_sensitive (false);
1128 input_latency.set_sensitive (false);
1129 output_latency.set_sensitive (false);
1130 input_channels.set_sensitive (false);
1131 output_channels.set_sensitive (false);
1132 if (_have_control) {
1133 ok_button->set_sensitive (false);
1134 apply_button->set_sensitive (false);
1136 ok_button->set_sensitive (true);
1137 apply_button->set_sensitive (true);
1138 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1139 sample_rate_combo.set_sensitive (true);
1141 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1142 buffer_size_combo.set_sensitive (true);
1150 EngineControl::driver_changed ()
1152 DEBUG_ECONTROL ("driver_changed");
1153 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1156 backend->set_driver (driver_combo.get_active_text());
1159 if (!ignore_changes) {
1160 maybe_display_saved_state ();
1165 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1167 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1168 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1173 if (_have_control) {
1174 sr = backend->available_sample_rates (device_name);
1177 sr.push_back (8000.0f);
1178 sr.push_back (16000.0f);
1179 sr.push_back (32000.0f);
1180 sr.push_back (44100.0f);
1181 sr.push_back (48000.0f);
1182 sr.push_back (88200.0f);
1183 sr.push_back (96000.0f);
1184 sr.push_back (192000.0f);
1185 sr.push_back (384000.0f);
1188 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1189 s.push_back (rate_as_string (*x));
1190 if (*x == _desired_sample_rate) {
1196 sample_rate_combo.set_sensitive (true);
1197 set_popdown_strings (sample_rate_combo, s);
1199 if (desired.empty()) {
1200 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1202 sample_rate_combo.set_active_text (desired);
1206 sample_rate_combo.set_sensitive (false);
1211 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1213 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1214 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1215 vector<uint32_t> bs;
1218 if (_have_control) {
1219 bs = backend->available_buffer_sizes (device_name);
1220 } else if (backend->can_change_buffer_size_when_running()) {
1228 bs.push_back (1024);
1229 bs.push_back (2048);
1230 bs.push_back (4096);
1231 bs.push_back (8192);
1234 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1235 s.push_back (bufsize_as_string (*x));
1239 buffer_size_combo.set_sensitive (true);
1240 set_popdown_strings (buffer_size_combo, s);
1241 buffer_size_combo.set_active_text (s.front());
1243 uint32_t period = backend->buffer_size();
1245 period = backend->default_buffer_size(device_name);
1247 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1248 show_buffer_duration ();
1250 buffer_size_combo.set_sensitive (false);
1255 EngineControl::device_changed ()
1257 DEBUG_ECONTROL ("device_changed");
1258 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1261 string device_name_in;
1262 string device_name_out; // only used if backend support separate I/O devices
1264 if (backend->use_separate_input_and_output_devices()) {
1265 device_name_in = get_input_device_name ();
1266 device_name_out = get_output_device_name ();
1268 device_name_in = get_device_name ();
1271 /* we set the backend-device to query various device related intormation.
1272 * This has the side effect that backend->device_name() will match
1273 * the device_name and 'change_device' will never be true.
1274 * so work around this by setting...
1276 if (backend->use_separate_input_and_output_devices()) {
1277 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1278 queue_device_changed = true;
1281 if (device_name_in != backend->device_name()) {
1282 queue_device_changed = true;
1286 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1287 if (backend->use_separate_input_and_output_devices()) {
1288 backend->set_input_device_name (device_name_in);
1289 backend->set_output_device_name (device_name_out);
1291 backend->set_device_name(device_name_in);
1295 /* don't allow programmatic change to combos to cause a
1296 recursive call to this method.
1298 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1300 /* backends that support separate devices, need to ignore
1301 * the device-name - and use the devies set above
1303 set_samplerate_popdown_strings (device_name_in);
1304 set_buffersize_popdown_strings (device_name_in);
1305 /* XXX theoretically need to set min + max channel counts here
1308 manage_control_app_sensitivity ();
1311 /* pick up any saved state for this device */
1313 if (!ignore_changes) {
1314 maybe_display_saved_state ();
1319 EngineControl::input_device_changed ()
1321 DEBUG_ECONTROL ("input_device_changed");
1326 EngineControl::output_device_changed ()
1328 DEBUG_ECONTROL ("output_device_changed");
1333 EngineControl::bufsize_as_string (uint32_t sz)
1335 /* Translators: "samples" is always plural here, so no
1336 need for plural+singular forms.
1339 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1344 EngineControl::sample_rate_changed ()
1346 DEBUG_ECONTROL ("sample_rate_changed");
1347 /* reset the strings for buffer size to show the correct msec value
1348 (reflecting the new sample rate).
1351 show_buffer_duration ();
1356 EngineControl::buffer_size_changed ()
1358 DEBUG_ECONTROL ("buffer_size_changed");
1359 show_buffer_duration ();
1363 EngineControl::show_buffer_duration ()
1365 DEBUG_ECONTROL ("show_buffer_duration");
1366 /* buffer sizes - convert from just samples to samples + msecs for
1367 * the displayed string
1370 string bs_text = buffer_size_combo.get_active_text ();
1371 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1372 uint32_t rate = get_rate();
1374 /* Developers: note the hard-coding of a double buffered model
1375 in the (2 * samples) computation of latency. we always start
1376 the audiobackend in this configuration.
1378 /* note to jack1 developers: ardour also always starts the engine
1379 * in async mode (no jack2 --sync option) which adds an extra cycle
1380 * of latency with jack2 (and *3 would be correct)
1381 * The value can also be wrong if jackd is started externally..
1383 * At the time of writing the ALSA backend always uses double-buffering *2,
1384 * The Dummy backend *1, and who knows what ASIO really does :)
1386 * So just display the period size, that's also what
1387 * ARDOUR_UI::update_sample_rate() does for the status bar.
1388 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1389 * but still, that's the buffer period, not [round-trip] latency)
1392 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1393 buffer_size_duration_label.set_text (buf);
1397 EngineControl::midi_option_changed ()
1399 DEBUG_ECONTROL ("midi_option_changed");
1400 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1403 backend->set_midi_option (get_midi_option());
1405 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1407 //_midi_devices.clear(); // TODO merge with state-saved settings..
1408 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1409 std::vector<MidiDeviceSettings> new_devices;
1411 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1412 MidiDeviceSettings mds = find_midi_device (i->name);
1413 if (i->available && !mds) {
1414 uint32_t input_latency = 0;
1415 uint32_t output_latency = 0;
1416 if (_can_set_midi_latencies) {
1417 input_latency = backend->systemic_midi_input_latency (i->name);
1418 output_latency = backend->systemic_midi_output_latency (i->name);
1420 bool enabled = backend->midi_device_enabled (i->name);
1421 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1422 new_devices.push_back (ptr);
1423 } else if (i->available) {
1424 new_devices.push_back (mds);
1427 _midi_devices = new_devices;
1429 if (_midi_devices.empty()) {
1430 midi_devices_button.set_sensitive (false);
1432 midi_devices_button.set_sensitive (true);
1437 EngineControl::parameter_changed ()
1441 EngineControl::State
1442 EngineControl::get_matching_state (
1443 const string& backend,
1444 const string& driver,
1445 const string& device)
1447 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1448 if ((*i)->backend == backend &&
1449 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1457 EngineControl::State
1458 EngineControl::get_matching_state (
1459 const string& backend,
1460 const string& driver,
1461 const string& input_device,
1462 const string& output_device)
1464 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1465 if ((*i)->backend == backend &&
1466 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1474 EngineControl::State
1475 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1477 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1480 if (backend->use_separate_input_and_output_devices ()) {
1481 return get_matching_state (backend_combo.get_active_text(),
1482 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1483 input_device_combo.get_active_text(),
1484 output_device_combo.get_active_text());
1486 return get_matching_state (backend_combo.get_active_text(),
1487 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1488 device_combo.get_active_text());
1492 return get_matching_state (backend_combo.get_active_text(),
1494 device_combo.get_active_text());
1497 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1498 const EngineControl::State& state2)
1500 if (state1->backend == state2->backend &&
1501 state1->driver == state2->driver &&
1502 state1->device == state2->device &&
1503 state1->input_device == state2->input_device &&
1504 state1->output_device == state2->output_device) {
1510 EngineControl::State
1511 EngineControl::save_state ()
1515 if (!_have_control) {
1516 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1520 state.reset(new StateStruct);
1521 state->backend = get_backend ();
1523 state.reset(new StateStruct);
1524 store_state (state);
1527 for (StateList::iterator i = states.begin(); i != states.end();) {
1528 if (equivalent_states (*i, state)) {
1529 i = states.erase(i);
1535 states.push_back (state);
1541 EngineControl::store_state (State state)
1543 state->backend = get_backend ();
1544 state->driver = get_driver ();
1545 state->device = get_device_name ();
1546 state->input_device = get_input_device_name ();
1547 state->output_device = get_output_device_name ();
1548 state->sample_rate = get_rate ();
1549 state->buffer_size = get_buffer_size ();
1550 state->input_latency = get_input_latency ();
1551 state->output_latency = get_output_latency ();
1552 state->input_channels = get_input_channels ();
1553 state->output_channels = get_output_channels ();
1554 state->midi_option = get_midi_option ();
1555 state->midi_devices = _midi_devices;
1559 EngineControl::maybe_display_saved_state ()
1561 if (!_have_control) {
1565 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1568 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1570 if (!_desired_sample_rate) {
1571 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1573 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1574 /* call this explicitly because we're ignoring changes to
1575 the controls at this point.
1577 show_buffer_duration ();
1578 input_latency.set_value (state->input_latency);
1579 output_latency.set_value (state->output_latency);
1581 if (!state->midi_option.empty()) {
1582 midi_option_combo.set_active_text (state->midi_option);
1583 _midi_devices = state->midi_devices;
1589 EngineControl::get_state ()
1591 LocaleGuard lg (X_("C"));
1593 XMLNode* root = new XMLNode ("AudioMIDISetup");
1596 if (!states.empty()) {
1597 XMLNode* state_nodes = new XMLNode ("EngineStates");
1599 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1601 XMLNode* node = new XMLNode ("State");
1603 node->add_property ("backend", (*i)->backend);
1604 node->add_property ("driver", (*i)->driver);
1605 node->add_property ("device", (*i)->device);
1606 node->add_property ("input-device", (*i)->input_device);
1607 node->add_property ("output-device", (*i)->output_device);
1608 node->add_property ("sample-rate", (*i)->sample_rate);
1609 node->add_property ("buffer-size", (*i)->buffer_size);
1610 node->add_property ("input-latency", (*i)->input_latency);
1611 node->add_property ("output-latency", (*i)->output_latency);
1612 node->add_property ("input-channels", (*i)->input_channels);
1613 node->add_property ("output-channels", (*i)->output_channels);
1614 node->add_property ("active", (*i)->active ? "yes" : "no");
1615 node->add_property ("midi-option", (*i)->midi_option);
1617 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1618 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1619 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1620 midi_device_stuff->add_property (X_("name"), (*p)->name);
1621 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1622 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1623 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1624 midi_devices->add_child_nocopy (*midi_device_stuff);
1626 node->add_child_nocopy (*midi_devices);
1628 state_nodes->add_child_nocopy (*node);
1631 root->add_child_nocopy (*state_nodes);
1638 EngineControl::set_state (const XMLNode& root)
1640 XMLNodeList clist, cclist;
1641 XMLNodeConstIterator citer, cciter;
1643 XMLNode* grandchild;
1644 XMLProperty* prop = NULL;
1646 fprintf (stderr, "EngineControl::set_state\n");
1648 if (root.name() != "AudioMIDISetup") {
1652 clist = root.children();
1656 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1660 if (child->name() != "EngineStates") {
1664 cclist = child->children();
1666 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1667 State state (new StateStruct);
1669 grandchild = *cciter;
1671 if (grandchild->name() != "State") {
1675 if ((prop = grandchild->property ("backend")) == 0) {
1678 state->backend = prop->value ();
1680 if ((prop = grandchild->property ("driver")) == 0) {
1683 state->driver = prop->value ();
1685 if ((prop = grandchild->property ("device")) == 0) {
1688 state->device = prop->value ();
1690 if ((prop = grandchild->property ("input-device")) == 0) {
1693 state->input_device = prop->value ();
1695 if ((prop = grandchild->property ("output-device")) == 0) {
1698 state->output_device = prop->value ();
1700 if ((prop = grandchild->property ("sample-rate")) == 0) {
1703 state->sample_rate = atof (prop->value ());
1705 if ((prop = grandchild->property ("buffer-size")) == 0) {
1708 state->buffer_size = atoi (prop->value ());
1710 if ((prop = grandchild->property ("input-latency")) == 0) {
1713 state->input_latency = atoi (prop->value ());
1715 if ((prop = grandchild->property ("output-latency")) == 0) {
1718 state->output_latency = atoi (prop->value ());
1720 if ((prop = grandchild->property ("input-channels")) == 0) {
1723 state->input_channels = atoi (prop->value ());
1725 if ((prop = grandchild->property ("output-channels")) == 0) {
1728 state->output_channels = atoi (prop->value ());
1730 if ((prop = grandchild->property ("active")) == 0) {
1733 state->active = string_is_affirmative (prop->value ());
1735 if ((prop = grandchild->property ("midi-option")) == 0) {
1738 state->midi_option = prop->value ();
1740 state->midi_devices.clear();
1742 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1743 const XMLNodeList mnc = midinode->children();
1744 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1745 if ((*n)->property (X_("name")) == 0
1746 || (*n)->property (X_("enabled")) == 0
1747 || (*n)->property (X_("input-latency")) == 0
1748 || (*n)->property (X_("output-latency")) == 0
1753 MidiDeviceSettings ptr (new MidiDeviceSetting(
1754 (*n)->property (X_("name"))->value (),
1755 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1756 atoi ((*n)->property (X_("input-latency"))->value ()),
1757 atoi ((*n)->property (X_("output-latency"))->value ())
1759 state->midi_devices.push_back (ptr);
1764 /* remove accumulated duplicates (due to bug in ealier version)
1765 * this can be removed again before release
1767 for (StateList::iterator i = states.begin(); i != states.end();) {
1768 if ((*i)->backend == state->backend &&
1769 (*i)->driver == state->driver &&
1770 (*i)->device == state->device) {
1771 i = states.erase(i);
1778 states.push_back (state);
1782 /* now see if there was an active state and switch the setup to it */
1784 // purge states of backend that are not available in this built
1785 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1786 vector<std::string> backend_names;
1788 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1789 backend_names.push_back((*i)->name);
1791 for (StateList::iterator i = states.begin(); i != states.end();) {
1792 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1793 i = states.erase(i);
1799 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1802 set_current_state (*i);
1809 EngineControl::set_current_state (const State& state)
1811 DEBUG_ECONTROL ("set_current_state");
1812 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1813 backend_combo.set_active_text (state->backend);
1815 /* The driver popdown strings need to be populated now so that
1816 * set_active_text will actually set a valid entry. Then
1817 * backend_changed() will populate all the other combo's so they
1818 * can also be set to valid entries and the state will be restored
1821 if (!state->driver.empty()) {
1822 set_driver_popdown_strings ();
1824 driver_combo.set_active_text (state->driver);
1827 device_combo.set_active_text (state->device);
1828 input_device_combo.set_active_text (state->input_device);
1829 output_device_combo.set_active_text (state->output_device);
1830 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1831 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1832 input_latency.set_value (state->input_latency);
1833 output_latency.set_value (state->output_latency);
1834 midi_option_combo.set_active_text (state->midi_option);
1838 EngineControl::push_state_to_backend (bool start)
1840 DEBUG_ECONTROL ("push_state_to_backend");
1841 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1847 /* figure out what is going to change */
1849 bool restart_required = false;
1850 bool was_running = ARDOUR::AudioEngine::instance()->running();
1851 bool change_driver = false;
1852 bool change_device = false;
1853 bool change_rate = false;
1854 bool change_bufsize = false;
1855 bool change_latency = false;
1856 bool change_channels = false;
1857 bool change_midi = false;
1859 uint32_t ochan = get_output_channels ();
1860 uint32_t ichan = get_input_channels ();
1862 if (_have_control) {
1864 if (started_at_least_once) {
1866 /* we can control the backend */
1868 if (backend->requires_driver_selection()) {
1869 if (get_driver() != backend->driver_name()) {
1870 change_driver = true;
1874 if (backend->use_separate_input_and_output_devices()) {
1875 if (get_input_device_name() != backend->input_device_name()) {
1876 change_device = true;
1878 if (get_output_device_name() != backend->output_device_name()) {
1879 change_device = true;
1882 if (get_device_name() != backend->device_name()) {
1883 change_device = true;
1887 if (queue_device_changed) {
1888 change_device = true;
1891 if (get_rate() != backend->sample_rate()) {
1895 if (get_buffer_size() != backend->buffer_size()) {
1896 change_bufsize = true;
1899 if (get_midi_option() != backend->midi_option()) {
1903 /* zero-requested channels means "all available" */
1906 ichan = backend->input_channels();
1910 ochan = backend->output_channels();
1913 if (ichan != backend->input_channels()) {
1914 change_channels = true;
1917 if (ochan != backend->output_channels()) {
1918 change_channels = true;
1921 if (get_input_latency() != backend->systemic_input_latency() ||
1922 get_output_latency() != backend->systemic_output_latency()) {
1923 change_latency = true;
1926 /* backend never started, so we have to force a group
1929 change_device = true;
1930 if (backend->requires_driver_selection()) {
1931 change_driver = true;
1934 change_bufsize = true;
1935 change_channels = true;
1936 change_latency = true;
1942 /* we have no control over the backend, meaning that we can
1943 * only possibly change sample rate and buffer size.
1947 if (get_rate() != backend->sample_rate()) {
1948 change_bufsize = true;
1951 if (get_buffer_size() != backend->buffer_size()) {
1952 change_bufsize = true;
1956 queue_device_changed = false;
1958 if (!_have_control) {
1960 /* We do not have control over the backend, so the best we can
1961 * do is try to change the sample rate and/or bufsize and get
1965 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1969 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1974 backend->set_sample_rate (get_rate());
1977 if (change_bufsize) {
1978 backend->set_buffer_size (get_buffer_size());
1982 if (ARDOUR::AudioEngine::instance()->start ()) {
1983 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1993 /* determine if we need to stop the backend before changing parameters */
1995 if (change_driver || change_device || change_channels || change_latency ||
1996 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1998 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1999 restart_required = true;
2001 restart_required = false;
2006 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2007 /* no changes in any parameters that absolutely require a
2008 * restart, so check those that might be changeable without a
2012 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2013 /* can't do this while running ... */
2014 restart_required = true;
2017 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2018 /* can't do this while running ... */
2019 restart_required = true;
2025 if (restart_required) {
2026 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2033 if (change_driver && backend->set_driver (get_driver())) {
2034 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2037 if (backend->use_separate_input_and_output_devices()) {
2038 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2039 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2042 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2043 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2047 if (change_device && backend->set_device_name (get_device_name())) {
2048 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2052 if (change_rate && backend->set_sample_rate (get_rate())) {
2053 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2056 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2057 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2061 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2062 if (backend->set_input_channels (get_input_channels())) {
2063 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2066 if (backend->set_output_channels (get_output_channels())) {
2067 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2071 if (change_latency) {
2072 if (backend->set_systemic_input_latency (get_input_latency())) {
2073 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2076 if (backend->set_systemic_output_latency (get_output_latency())) {
2077 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2083 backend->set_midi_option (get_midi_option());
2087 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2088 if (_measure_midi) {
2089 if (*p == _measure_midi) {
2090 backend->set_midi_device_enabled ((*p)->name, true);
2092 backend->set_midi_device_enabled ((*p)->name, false);
2096 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2097 if (backend->can_set_systemic_midi_latencies()) {
2098 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2099 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2104 if (start || (was_running && restart_required)) {
2105 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2116 EngineControl::post_push ()
2118 /* get a pointer to the current state object, creating one if
2122 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2125 state = save_state ();
2133 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2134 (*i)->active = false;
2137 /* mark this one active (to be used next time the dialog is
2141 state->active = true;
2143 if (_have_control) { // XXX
2144 manage_control_app_sensitivity ();
2147 /* schedule a redisplay of MIDI ports */
2148 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2153 EngineControl::get_rate () const
2155 float r = atof (sample_rate_combo.get_active_text ());
2156 /* the string may have been translated with an abbreviation for
2157 * thousands, so use a crude heuristic to fix this.
2167 EngineControl::get_buffer_size () const
2169 string txt = buffer_size_combo.get_active_text ();
2172 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2173 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2174 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2182 EngineControl::get_midi_option () const
2184 return midi_option_combo.get_active_text();
2188 EngineControl::get_input_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) input_channels_adjustment.get_value();
2199 EngineControl::get_output_channels() const
2201 if (ARDOUR::Profile->get_mixbus()) {
2202 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2203 if (!backend) return 0;
2204 return backend->input_channels();
2206 return (uint32_t) output_channels_adjustment.get_value();
2210 EngineControl::get_input_latency() const
2212 return (uint32_t) input_latency_adjustment.get_value();
2216 EngineControl::get_output_latency() const
2218 return (uint32_t) output_latency_adjustment.get_value();
2222 EngineControl::get_backend () const
2224 return backend_combo.get_active_text ();
2228 EngineControl::get_driver () const
2230 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2231 return driver_combo.get_active_text ();
2238 EngineControl::get_device_name () const
2240 return device_combo.get_active_text ();
2244 EngineControl::get_input_device_name () const
2246 return input_device_combo.get_active_text ();
2250 EngineControl::get_output_device_name () const
2252 return output_device_combo.get_active_text ();
2256 EngineControl::control_app_button_clicked ()
2258 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2264 backend->launch_control_app ();
2268 EngineControl::manage_control_app_sensitivity ()
2270 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2276 string appname = backend->control_app_name();
2278 if (appname.empty()) {
2279 control_app_button.set_sensitive (false);
2281 control_app_button.set_sensitive (true);
2286 EngineControl::set_desired_sample_rate (uint32_t sr)
2288 _desired_sample_rate = sr;
2293 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2295 if (page_num == 0) {
2296 cancel_button->set_sensitive (true);
2297 ok_button->set_sensitive (true);
2298 apply_button->set_sensitive (true);
2299 _measure_midi.reset();
2301 cancel_button->set_sensitive (false);
2302 ok_button->set_sensitive (false);
2303 apply_button->set_sensitive (false);
2306 if (page_num == midi_tab) {
2308 refresh_midi_display ();
2311 if (page_num == latency_tab) {
2314 if (ARDOUR::AudioEngine::instance()->running()) {
2315 // TODO - mark as 'stopped for latency
2316 ARDOUR_UI::instance()->disconnect_from_engine ();
2320 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2322 /* save any existing latency values */
2324 uint32_t il = (uint32_t) input_latency.get_value ();
2325 uint32_t ol = (uint32_t) input_latency.get_value ();
2327 /* reset to zero so that our new test instance
2328 will be clean of any existing latency measures.
2330 NB. this should really be done by the backend
2331 when stated for latency measurement.
2334 input_latency.set_value (0);
2335 output_latency.set_value (0);
2337 push_state_to_backend (false);
2341 input_latency.set_value (il);
2342 output_latency.set_value (ol);
2345 // This should be done in push_state_to_backend()
2346 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2347 disable_latency_tab ();
2350 enable_latency_tab ();
2354 end_latency_detection ();
2355 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2360 /* latency measurement */
2363 EngineControl::check_audio_latency_measurement ()
2365 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2367 if (mtdm->resolve () < 0) {
2368 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2372 if (mtdm->err () > 0.3) {
2378 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2380 if (sample_rate == 0) {
2381 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2382 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2386 int frames_total = mtdm->del();
2387 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2389 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2390 _("Detected roundtrip latency: "),
2391 frames_total, frames_total * 1000.0f/sample_rate,
2392 _("Systemic latency: "),
2393 extra, extra * 1000.0f/sample_rate);
2397 if (mtdm->err () > 0.2) {
2399 strcat (buf, _("(signal detection error)"));
2405 strcat (buf, _("(inverted - bad wiring)"));
2409 lm_results.set_markup (string_compose (results_markup, buf));
2412 have_lm_results = true;
2413 end_latency_detection ();
2414 lm_use_button.set_sensitive (true);
2422 EngineControl::check_midi_latency_measurement ()
2424 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2426 if (!mididm->have_signal () || mididm->latency () == 0) {
2427 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2432 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2434 if (sample_rate == 0) {
2435 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2436 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2440 ARDOUR::framecnt_t frames_total = mididm->latency();
2441 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2442 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2443 _("Detected roundtrip latency: "),
2444 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2445 _("Systemic latency: "),
2446 extra, extra * 1000.0f / sample_rate);
2450 if (!mididm->ok ()) {
2452 strcat (buf, _("(averaging)"));
2456 if (mididm->deviation () > 50.0) {
2458 strcat (buf, _("(too large jitter)"));
2460 } else if (mididm->deviation () > 10.0) {
2462 strcat (buf, _("(large jitter)"));
2466 have_lm_results = true;
2467 end_latency_detection ();
2468 lm_use_button.set_sensitive (true);
2469 lm_results.set_markup (string_compose (results_markup, buf));
2471 } else if (mididm->processed () > 400) {
2472 have_lm_results = false;
2473 end_latency_detection ();
2474 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2478 lm_results.set_markup (string_compose (results_markup, buf));
2484 EngineControl::start_latency_detection ()
2486 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2487 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2489 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2490 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2491 if (_measure_midi) {
2492 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2494 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2496 lm_measure_label.set_text (_("Cancel"));
2497 have_lm_results = false;
2498 lm_use_button.set_sensitive (false);
2499 lm_input_channel_combo.set_sensitive (false);
2500 lm_output_channel_combo.set_sensitive (false);
2506 EngineControl::end_latency_detection ()
2508 latency_timeout.disconnect ();
2509 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2510 lm_measure_label.set_text (_("Measure"));
2511 if (!have_lm_results) {
2512 lm_use_button.set_sensitive (false);
2514 lm_input_channel_combo.set_sensitive (true);
2515 lm_output_channel_combo.set_sensitive (true);
2520 EngineControl::latency_button_clicked ()
2523 start_latency_detection ();
2525 end_latency_detection ();
2530 EngineControl::use_latency_button_clicked ()
2532 if (_measure_midi) {
2533 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2537 ARDOUR::framecnt_t frames_total = mididm->latency();
2538 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2539 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2540 _measure_midi->input_latency = one_way;
2541 _measure_midi->output_latency = one_way;
2542 notebook.set_current_page (midi_tab);
2544 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2550 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2551 one_way = std::max (0., one_way);
2553 input_latency_adjustment.set_value (one_way);
2554 output_latency_adjustment.set_value (one_way);
2556 /* back to settings page */
2557 notebook.set_current_page (0);
2563 EngineControl::on_delete_event (GdkEventAny* ev)
2565 if (notebook.get_current_page() == 2) {
2566 /* currently on latency tab - be sure to clean up */
2567 end_latency_detection ();
2569 return ArdourDialog::on_delete_event (ev);
2573 EngineControl::engine_running ()
2575 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2578 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2579 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2581 buffer_size_combo.set_sensitive (true);
2582 sample_rate_combo.set_sensitive (true);
2584 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2585 connect_disconnect_button.show();
2587 started_at_least_once = true;
2588 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2592 EngineControl::engine_stopped ()
2594 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2597 buffer_size_combo.set_sensitive (false);
2598 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2599 connect_disconnect_button.show();
2601 sample_rate_combo.set_sensitive (true);
2602 buffer_size_combo.set_sensitive (true);
2603 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2607 EngineControl::device_list_changed ()
2609 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2611 midi_option_changed();
2615 EngineControl::connect_disconnect_click()
2617 if (ARDOUR::AudioEngine::instance()->running()) {
2618 ARDOUR_UI::instance()->disconnect_from_engine ();
2620 ARDOUR_UI::instance()->reconnect_to_engine ();
2625 EngineControl::calibrate_audio_latency ()
2627 _measure_midi.reset ();
2628 have_lm_results = false;
2629 lm_use_button.set_sensitive (false);
2630 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2631 notebook.set_current_page (latency_tab);
2635 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2638 have_lm_results = false;
2639 lm_use_button.set_sensitive (false);
2640 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2641 notebook.set_current_page (latency_tab);
2645 EngineControl::configure_midi_devices ()
2647 notebook.set_current_page (midi_tab);