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);
1002 // @return true if there are input devices available
1004 EngineControl::set_input_device_popdown_strings ()
1006 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1007 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1008 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1010 vector<string> available_devices;
1012 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1013 available_devices.push_back (i->name);
1016 if (!available_devices.empty()) {
1019 string current_device, found_device;
1020 current_device = input_device_combo.get_active_text ();
1021 if (current_device == "") {
1022 current_device = backend->input_device_name ();
1025 // Make sure that the active text is still relevant for this
1026 // device (it might only be relevant to the previous device!!)
1027 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1028 if (*i == current_device)
1029 found_device = current_device;
1031 if (found_device == "")
1032 // device has never been set (or was not relevant
1033 // for this backend) Let's make sure it's not blank
1034 current_device = available_devices.front ();
1036 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1037 set_popdown_strings (input_device_combo, available_devices);
1039 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1040 input_device_combo.set_active_text (current_device);
1050 // @return true if there are output devices available
1052 EngineControl::set_output_device_popdown_strings ()
1054 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1055 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1056 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1058 vector<string> available_devices;
1060 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1061 available_devices.push_back (i->name);
1064 if (!available_devices.empty()) {
1067 string current_device, found_device;
1068 current_device = output_device_combo.get_active_text ();
1069 if (current_device == "") {
1070 current_device = backend->output_device_name ();
1073 // Make sure that the active text is still relevant for this
1074 // device (it might only be relevant to the previous device!!)
1075 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1076 if (*i == current_device)
1077 found_device = current_device;
1079 if (found_device == "")
1080 // device has never been set (or was not relevant
1081 // for this backend) Let's make sure it's not blank
1082 current_device = available_devices.front ();
1084 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1085 set_popdown_strings (output_device_combo, available_devices);
1087 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1088 output_device_combo.set_active_text (current_device);
1099 EngineControl::list_devices ()
1101 DEBUG_ECONTROL ("list_devices");
1102 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1105 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1107 bool devices_available = false;
1109 if (backend->use_separate_input_and_output_devices ()) {
1110 bool input_devices_available = set_input_device_popdown_strings ();
1111 bool output_devices_available = set_output_device_popdown_strings ();
1112 devices_available = input_devices_available || output_devices_available;
1114 devices_available = set_device_popdown_strings ();
1117 if (devices_available) {
1118 input_latency.set_sensitive (true);
1119 output_latency.set_sensitive (true);
1120 input_channels.set_sensitive (true);
1121 output_channels.set_sensitive (true);
1123 ok_button->set_sensitive (true);
1124 apply_button->set_sensitive (true);
1127 device_combo.clear();
1128 input_device_combo.clear();
1129 output_device_combo.clear();
1130 sample_rate_combo.set_sensitive (false);
1131 buffer_size_combo.set_sensitive (false);
1132 input_latency.set_sensitive (false);
1133 output_latency.set_sensitive (false);
1134 input_channels.set_sensitive (false);
1135 output_channels.set_sensitive (false);
1136 if (_have_control) {
1137 ok_button->set_sensitive (false);
1138 apply_button->set_sensitive (false);
1140 ok_button->set_sensitive (true);
1141 apply_button->set_sensitive (true);
1142 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1143 sample_rate_combo.set_sensitive (true);
1145 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1146 buffer_size_combo.set_sensitive (true);
1154 EngineControl::driver_changed ()
1156 DEBUG_ECONTROL ("driver_changed");
1157 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1160 backend->set_driver (driver_combo.get_active_text());
1163 if (!ignore_changes) {
1164 maybe_display_saved_state ();
1169 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1171 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1172 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1177 if (_have_control) {
1178 sr = backend->available_sample_rates (device_name);
1181 sr.push_back (8000.0f);
1182 sr.push_back (16000.0f);
1183 sr.push_back (32000.0f);
1184 sr.push_back (44100.0f);
1185 sr.push_back (48000.0f);
1186 sr.push_back (88200.0f);
1187 sr.push_back (96000.0f);
1188 sr.push_back (192000.0f);
1189 sr.push_back (384000.0f);
1192 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1193 s.push_back (rate_as_string (*x));
1194 if (*x == _desired_sample_rate) {
1200 sample_rate_combo.set_sensitive (true);
1201 set_popdown_strings (sample_rate_combo, s);
1203 if (desired.empty()) {
1204 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1206 sample_rate_combo.set_active_text (desired);
1210 sample_rate_combo.set_sensitive (false);
1215 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1217 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1218 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1219 vector<uint32_t> bs;
1222 if (_have_control) {
1223 bs = backend->available_buffer_sizes (device_name);
1224 } else if (backend->can_change_buffer_size_when_running()) {
1232 bs.push_back (1024);
1233 bs.push_back (2048);
1234 bs.push_back (4096);
1235 bs.push_back (8192);
1238 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1239 s.push_back (bufsize_as_string (*x));
1243 buffer_size_combo.set_sensitive (true);
1244 set_popdown_strings (buffer_size_combo, s);
1245 buffer_size_combo.set_active_text (s.front());
1247 uint32_t period = backend->buffer_size();
1249 period = backend->default_buffer_size(device_name);
1251 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1252 show_buffer_duration ();
1254 buffer_size_combo.set_sensitive (false);
1259 EngineControl::device_changed ()
1261 DEBUG_ECONTROL ("device_changed");
1262 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1265 string device_name_in;
1266 string device_name_out; // only used if backend support separate I/O devices
1268 if (backend->use_separate_input_and_output_devices()) {
1269 device_name_in = get_input_device_name ();
1270 device_name_out = get_output_device_name ();
1272 device_name_in = get_device_name ();
1275 /* we set the backend-device to query various device related intormation.
1276 * This has the side effect that backend->device_name() will match
1277 * the device_name and 'change_device' will never be true.
1278 * so work around this by setting...
1280 if (backend->use_separate_input_and_output_devices()) {
1281 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1282 queue_device_changed = true;
1285 if (device_name_in != backend->device_name()) {
1286 queue_device_changed = true;
1290 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1291 if (backend->use_separate_input_and_output_devices()) {
1292 backend->set_input_device_name (device_name_in);
1293 backend->set_output_device_name (device_name_out);
1295 backend->set_device_name(device_name_in);
1299 /* don't allow programmatic change to combos to cause a
1300 recursive call to this method.
1302 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1304 /* backends that support separate devices, need to ignore
1305 * the device-name - and use the devies set above
1307 set_samplerate_popdown_strings (device_name_in);
1308 set_buffersize_popdown_strings (device_name_in);
1309 /* XXX theoretically need to set min + max channel counts here
1312 manage_control_app_sensitivity ();
1315 /* pick up any saved state for this device */
1317 if (!ignore_changes) {
1318 maybe_display_saved_state ();
1323 EngineControl::input_device_changed ()
1325 DEBUG_ECONTROL ("input_device_changed");
1330 EngineControl::output_device_changed ()
1332 DEBUG_ECONTROL ("output_device_changed");
1337 EngineControl::bufsize_as_string (uint32_t sz)
1339 /* Translators: "samples" is always plural here, so no
1340 need for plural+singular forms.
1343 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1348 EngineControl::sample_rate_changed ()
1350 DEBUG_ECONTROL ("sample_rate_changed");
1351 /* reset the strings for buffer size to show the correct msec value
1352 (reflecting the new sample rate).
1355 show_buffer_duration ();
1360 EngineControl::buffer_size_changed ()
1362 DEBUG_ECONTROL ("buffer_size_changed");
1363 show_buffer_duration ();
1367 EngineControl::show_buffer_duration ()
1369 DEBUG_ECONTROL ("show_buffer_duration");
1370 /* buffer sizes - convert from just samples to samples + msecs for
1371 * the displayed string
1374 string bs_text = buffer_size_combo.get_active_text ();
1375 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1376 uint32_t rate = get_rate();
1378 /* Developers: note the hard-coding of a double buffered model
1379 in the (2 * samples) computation of latency. we always start
1380 the audiobackend in this configuration.
1382 /* note to jack1 developers: ardour also always starts the engine
1383 * in async mode (no jack2 --sync option) which adds an extra cycle
1384 * of latency with jack2 (and *3 would be correct)
1385 * The value can also be wrong if jackd is started externally..
1387 * At the time of writing the ALSA backend always uses double-buffering *2,
1388 * The Dummy backend *1, and who knows what ASIO really does :)
1390 * So just display the period size, that's also what
1391 * ARDOUR_UI::update_sample_rate() does for the status bar.
1392 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1393 * but still, that's the buffer period, not [round-trip] latency)
1396 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1397 buffer_size_duration_label.set_text (buf);
1401 EngineControl::midi_option_changed ()
1403 DEBUG_ECONTROL ("midi_option_changed");
1404 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1407 backend->set_midi_option (get_midi_option());
1409 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1411 //_midi_devices.clear(); // TODO merge with state-saved settings..
1412 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1413 std::vector<MidiDeviceSettings> new_devices;
1415 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1416 MidiDeviceSettings mds = find_midi_device (i->name);
1417 if (i->available && !mds) {
1418 uint32_t input_latency = 0;
1419 uint32_t output_latency = 0;
1420 if (_can_set_midi_latencies) {
1421 input_latency = backend->systemic_midi_input_latency (i->name);
1422 output_latency = backend->systemic_midi_output_latency (i->name);
1424 bool enabled = backend->midi_device_enabled (i->name);
1425 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1426 new_devices.push_back (ptr);
1427 } else if (i->available) {
1428 new_devices.push_back (mds);
1431 _midi_devices = new_devices;
1433 if (_midi_devices.empty()) {
1434 midi_devices_button.set_sensitive (false);
1436 midi_devices_button.set_sensitive (true);
1441 EngineControl::parameter_changed ()
1445 EngineControl::State
1446 EngineControl::get_matching_state (
1447 const string& backend,
1448 const string& driver,
1449 const string& device)
1451 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1452 if ((*i)->backend == backend &&
1453 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1461 EngineControl::State
1462 EngineControl::get_matching_state (
1463 const string& backend,
1464 const string& driver,
1465 const string& input_device,
1466 const string& output_device)
1468 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1469 if ((*i)->backend == backend &&
1470 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1478 EngineControl::State
1479 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1481 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1484 if (backend->use_separate_input_and_output_devices ()) {
1485 return get_matching_state (backend_combo.get_active_text(),
1486 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1487 input_device_combo.get_active_text(),
1488 output_device_combo.get_active_text());
1490 return get_matching_state (backend_combo.get_active_text(),
1491 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1492 device_combo.get_active_text());
1496 return get_matching_state (backend_combo.get_active_text(),
1498 device_combo.get_active_text());
1501 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1502 const EngineControl::State& state2)
1504 if (state1->backend == state2->backend &&
1505 state1->driver == state2->driver &&
1506 state1->device == state2->device &&
1507 state1->input_device == state2->input_device &&
1508 state1->output_device == state2->output_device) {
1514 EngineControl::State
1515 EngineControl::save_state ()
1519 if (!_have_control) {
1520 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1524 state.reset(new StateStruct);
1525 state->backend = get_backend ();
1527 state.reset(new StateStruct);
1528 store_state (state);
1531 for (StateList::iterator i = states.begin(); i != states.end();) {
1532 if (equivalent_states (*i, state)) {
1533 i = states.erase(i);
1539 states.push_back (state);
1545 EngineControl::store_state (State state)
1547 state->backend = get_backend ();
1548 state->driver = get_driver ();
1549 state->device = get_device_name ();
1550 state->input_device = get_input_device_name ();
1551 state->output_device = get_output_device_name ();
1552 state->sample_rate = get_rate ();
1553 state->buffer_size = get_buffer_size ();
1554 state->input_latency = get_input_latency ();
1555 state->output_latency = get_output_latency ();
1556 state->input_channels = get_input_channels ();
1557 state->output_channels = get_output_channels ();
1558 state->midi_option = get_midi_option ();
1559 state->midi_devices = _midi_devices;
1563 EngineControl::maybe_display_saved_state ()
1565 if (!_have_control) {
1569 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1572 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1574 if (!_desired_sample_rate) {
1575 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1577 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1578 /* call this explicitly because we're ignoring changes to
1579 the controls at this point.
1581 show_buffer_duration ();
1582 input_latency.set_value (state->input_latency);
1583 output_latency.set_value (state->output_latency);
1585 if (!state->midi_option.empty()) {
1586 midi_option_combo.set_active_text (state->midi_option);
1587 _midi_devices = state->midi_devices;
1593 EngineControl::get_state ()
1595 LocaleGuard lg (X_("C"));
1597 XMLNode* root = new XMLNode ("AudioMIDISetup");
1600 if (!states.empty()) {
1601 XMLNode* state_nodes = new XMLNode ("EngineStates");
1603 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1605 XMLNode* node = new XMLNode ("State");
1607 node->add_property ("backend", (*i)->backend);
1608 node->add_property ("driver", (*i)->driver);
1609 node->add_property ("device", (*i)->device);
1610 node->add_property ("input-device", (*i)->input_device);
1611 node->add_property ("output-device", (*i)->output_device);
1612 node->add_property ("sample-rate", (*i)->sample_rate);
1613 node->add_property ("buffer-size", (*i)->buffer_size);
1614 node->add_property ("input-latency", (*i)->input_latency);
1615 node->add_property ("output-latency", (*i)->output_latency);
1616 node->add_property ("input-channels", (*i)->input_channels);
1617 node->add_property ("output-channels", (*i)->output_channels);
1618 node->add_property ("active", (*i)->active ? "yes" : "no");
1619 node->add_property ("midi-option", (*i)->midi_option);
1621 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1622 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1623 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1624 midi_device_stuff->add_property (X_("name"), (*p)->name);
1625 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1626 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1627 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1628 midi_devices->add_child_nocopy (*midi_device_stuff);
1630 node->add_child_nocopy (*midi_devices);
1632 state_nodes->add_child_nocopy (*node);
1635 root->add_child_nocopy (*state_nodes);
1642 EngineControl::set_state (const XMLNode& root)
1644 XMLNodeList clist, cclist;
1645 XMLNodeConstIterator citer, cciter;
1647 XMLNode* grandchild;
1648 XMLProperty* prop = NULL;
1650 fprintf (stderr, "EngineControl::set_state\n");
1652 if (root.name() != "AudioMIDISetup") {
1656 clist = root.children();
1660 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1664 if (child->name() != "EngineStates") {
1668 cclist = child->children();
1670 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1671 State state (new StateStruct);
1673 grandchild = *cciter;
1675 if (grandchild->name() != "State") {
1679 if ((prop = grandchild->property ("backend")) == 0) {
1682 state->backend = prop->value ();
1684 if ((prop = grandchild->property ("driver")) == 0) {
1687 state->driver = prop->value ();
1689 if ((prop = grandchild->property ("device")) == 0) {
1692 state->device = prop->value ();
1694 if ((prop = grandchild->property ("input-device")) == 0) {
1697 state->input_device = prop->value ();
1699 if ((prop = grandchild->property ("output-device")) == 0) {
1702 state->output_device = prop->value ();
1704 if ((prop = grandchild->property ("sample-rate")) == 0) {
1707 state->sample_rate = atof (prop->value ());
1709 if ((prop = grandchild->property ("buffer-size")) == 0) {
1712 state->buffer_size = atoi (prop->value ());
1714 if ((prop = grandchild->property ("input-latency")) == 0) {
1717 state->input_latency = atoi (prop->value ());
1719 if ((prop = grandchild->property ("output-latency")) == 0) {
1722 state->output_latency = atoi (prop->value ());
1724 if ((prop = grandchild->property ("input-channels")) == 0) {
1727 state->input_channels = atoi (prop->value ());
1729 if ((prop = grandchild->property ("output-channels")) == 0) {
1732 state->output_channels = atoi (prop->value ());
1734 if ((prop = grandchild->property ("active")) == 0) {
1737 state->active = string_is_affirmative (prop->value ());
1739 if ((prop = grandchild->property ("midi-option")) == 0) {
1742 state->midi_option = prop->value ();
1744 state->midi_devices.clear();
1746 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1747 const XMLNodeList mnc = midinode->children();
1748 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1749 if ((*n)->property (X_("name")) == 0
1750 || (*n)->property (X_("enabled")) == 0
1751 || (*n)->property (X_("input-latency")) == 0
1752 || (*n)->property (X_("output-latency")) == 0
1757 MidiDeviceSettings ptr (new MidiDeviceSetting(
1758 (*n)->property (X_("name"))->value (),
1759 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1760 atoi ((*n)->property (X_("input-latency"))->value ()),
1761 atoi ((*n)->property (X_("output-latency"))->value ())
1763 state->midi_devices.push_back (ptr);
1768 /* remove accumulated duplicates (due to bug in ealier version)
1769 * this can be removed again before release
1771 for (StateList::iterator i = states.begin(); i != states.end();) {
1772 if ((*i)->backend == state->backend &&
1773 (*i)->driver == state->driver &&
1774 (*i)->device == state->device) {
1775 i = states.erase(i);
1782 states.push_back (state);
1786 /* now see if there was an active state and switch the setup to it */
1788 // purge states of backend that are not available in this built
1789 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1790 vector<std::string> backend_names;
1792 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1793 backend_names.push_back((*i)->name);
1795 for (StateList::iterator i = states.begin(); i != states.end();) {
1796 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1797 i = states.erase(i);
1803 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1806 set_current_state (*i);
1813 EngineControl::set_current_state (const State& state)
1815 DEBUG_ECONTROL ("set_current_state");
1816 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1817 backend_combo.set_active_text (state->backend);
1819 /* The driver popdown strings need to be populated now so that
1820 * set_active_text will actually set a valid entry. Then
1821 * backend_changed() will populate all the other combo's so they
1822 * can also be set to valid entries and the state will be restored
1825 if (!state->driver.empty()) {
1826 set_driver_popdown_strings ();
1828 driver_combo.set_active_text (state->driver);
1831 device_combo.set_active_text (state->device);
1832 input_device_combo.set_active_text (state->input_device);
1833 output_device_combo.set_active_text (state->output_device);
1834 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1835 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1836 input_latency.set_value (state->input_latency);
1837 output_latency.set_value (state->output_latency);
1838 midi_option_combo.set_active_text (state->midi_option);
1842 EngineControl::push_state_to_backend (bool start)
1844 DEBUG_ECONTROL ("push_state_to_backend");
1845 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1851 /* figure out what is going to change */
1853 bool restart_required = false;
1854 bool was_running = ARDOUR::AudioEngine::instance()->running();
1855 bool change_driver = false;
1856 bool change_device = false;
1857 bool change_rate = false;
1858 bool change_bufsize = false;
1859 bool change_latency = false;
1860 bool change_channels = false;
1861 bool change_midi = false;
1863 uint32_t ochan = get_output_channels ();
1864 uint32_t ichan = get_input_channels ();
1866 if (_have_control) {
1868 if (started_at_least_once) {
1870 /* we can control the backend */
1872 if (backend->requires_driver_selection()) {
1873 if (get_driver() != backend->driver_name()) {
1874 change_driver = true;
1878 if (backend->use_separate_input_and_output_devices()) {
1879 if (get_input_device_name() != backend->input_device_name()) {
1880 change_device = true;
1882 if (get_output_device_name() != backend->output_device_name()) {
1883 change_device = true;
1886 if (get_device_name() != backend->device_name()) {
1887 change_device = true;
1891 if (queue_device_changed) {
1892 change_device = true;
1895 if (get_rate() != backend->sample_rate()) {
1899 if (get_buffer_size() != backend->buffer_size()) {
1900 change_bufsize = true;
1903 if (get_midi_option() != backend->midi_option()) {
1907 /* zero-requested channels means "all available" */
1910 ichan = backend->input_channels();
1914 ochan = backend->output_channels();
1917 if (ichan != backend->input_channels()) {
1918 change_channels = true;
1921 if (ochan != backend->output_channels()) {
1922 change_channels = true;
1925 if (get_input_latency() != backend->systemic_input_latency() ||
1926 get_output_latency() != backend->systemic_output_latency()) {
1927 change_latency = true;
1930 /* backend never started, so we have to force a group
1933 change_device = true;
1934 if (backend->requires_driver_selection()) {
1935 change_driver = true;
1938 change_bufsize = true;
1939 change_channels = true;
1940 change_latency = true;
1946 /* we have no control over the backend, meaning that we can
1947 * only possibly change sample rate and buffer size.
1951 if (get_rate() != backend->sample_rate()) {
1952 change_bufsize = true;
1955 if (get_buffer_size() != backend->buffer_size()) {
1956 change_bufsize = true;
1960 queue_device_changed = false;
1962 if (!_have_control) {
1964 /* We do not have control over the backend, so the best we can
1965 * do is try to change the sample rate and/or bufsize and get
1969 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1973 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1978 backend->set_sample_rate (get_rate());
1981 if (change_bufsize) {
1982 backend->set_buffer_size (get_buffer_size());
1986 if (ARDOUR::AudioEngine::instance()->start ()) {
1987 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1997 /* determine if we need to stop the backend before changing parameters */
1999 if (change_driver || change_device || change_channels || change_latency ||
2000 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2002 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2003 restart_required = true;
2005 restart_required = false;
2010 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2011 /* no changes in any parameters that absolutely require a
2012 * restart, so check those that might be changeable without a
2016 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2017 /* can't do this while running ... */
2018 restart_required = true;
2021 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2022 /* can't do this while running ... */
2023 restart_required = true;
2029 if (restart_required) {
2030 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2037 if (change_driver && backend->set_driver (get_driver())) {
2038 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2041 if (backend->use_separate_input_and_output_devices()) {
2042 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2043 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2046 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2047 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2051 if (change_device && backend->set_device_name (get_device_name())) {
2052 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2056 if (change_rate && backend->set_sample_rate (get_rate())) {
2057 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2060 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2061 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2065 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2066 if (backend->set_input_channels (get_input_channels())) {
2067 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2070 if (backend->set_output_channels (get_output_channels())) {
2071 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2075 if (change_latency) {
2076 if (backend->set_systemic_input_latency (get_input_latency())) {
2077 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2080 if (backend->set_systemic_output_latency (get_output_latency())) {
2081 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2087 backend->set_midi_option (get_midi_option());
2091 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2092 if (_measure_midi) {
2093 if (*p == _measure_midi) {
2094 backend->set_midi_device_enabled ((*p)->name, true);
2096 backend->set_midi_device_enabled ((*p)->name, false);
2100 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2101 if (backend->can_set_systemic_midi_latencies()) {
2102 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2103 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2108 if (start || (was_running && restart_required)) {
2109 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2120 EngineControl::post_push ()
2122 /* get a pointer to the current state object, creating one if
2126 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2129 state = save_state ();
2137 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2138 (*i)->active = false;
2141 /* mark this one active (to be used next time the dialog is
2145 state->active = true;
2147 if (_have_control) { // XXX
2148 manage_control_app_sensitivity ();
2151 /* schedule a redisplay of MIDI ports */
2152 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2157 EngineControl::get_rate () const
2159 float r = atof (sample_rate_combo.get_active_text ());
2160 /* the string may have been translated with an abbreviation for
2161 * thousands, so use a crude heuristic to fix this.
2171 EngineControl::get_buffer_size () const
2173 string txt = buffer_size_combo.get_active_text ();
2176 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2177 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2178 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2186 EngineControl::get_midi_option () const
2188 return midi_option_combo.get_active_text();
2192 EngineControl::get_input_channels() const
2194 if (ARDOUR::Profile->get_mixbus()) {
2195 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2196 if (!backend) return 0;
2197 return backend->input_channels();
2199 return (uint32_t) input_channels_adjustment.get_value();
2203 EngineControl::get_output_channels() const
2205 if (ARDOUR::Profile->get_mixbus()) {
2206 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2207 if (!backend) return 0;
2208 return backend->input_channels();
2210 return (uint32_t) output_channels_adjustment.get_value();
2214 EngineControl::get_input_latency() const
2216 return (uint32_t) input_latency_adjustment.get_value();
2220 EngineControl::get_output_latency() const
2222 return (uint32_t) output_latency_adjustment.get_value();
2226 EngineControl::get_backend () const
2228 return backend_combo.get_active_text ();
2232 EngineControl::get_driver () const
2234 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2235 return driver_combo.get_active_text ();
2242 EngineControl::get_device_name () const
2244 return device_combo.get_active_text ();
2248 EngineControl::get_input_device_name () const
2250 return input_device_combo.get_active_text ();
2254 EngineControl::get_output_device_name () const
2256 return output_device_combo.get_active_text ();
2260 EngineControl::control_app_button_clicked ()
2262 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2268 backend->launch_control_app ();
2272 EngineControl::manage_control_app_sensitivity ()
2274 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2280 string appname = backend->control_app_name();
2282 if (appname.empty()) {
2283 control_app_button.set_sensitive (false);
2285 control_app_button.set_sensitive (true);
2290 EngineControl::set_desired_sample_rate (uint32_t sr)
2292 _desired_sample_rate = sr;
2297 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2299 if (page_num == 0) {
2300 cancel_button->set_sensitive (true);
2301 ok_button->set_sensitive (true);
2302 apply_button->set_sensitive (true);
2303 _measure_midi.reset();
2305 cancel_button->set_sensitive (false);
2306 ok_button->set_sensitive (false);
2307 apply_button->set_sensitive (false);
2310 if (page_num == midi_tab) {
2312 refresh_midi_display ();
2315 if (page_num == latency_tab) {
2318 if (ARDOUR::AudioEngine::instance()->running()) {
2319 // TODO - mark as 'stopped for latency
2320 ARDOUR_UI::instance()->disconnect_from_engine ();
2324 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2326 /* save any existing latency values */
2328 uint32_t il = (uint32_t) input_latency.get_value ();
2329 uint32_t ol = (uint32_t) input_latency.get_value ();
2331 /* reset to zero so that our new test instance
2332 will be clean of any existing latency measures.
2334 NB. this should really be done by the backend
2335 when stated for latency measurement.
2338 input_latency.set_value (0);
2339 output_latency.set_value (0);
2341 push_state_to_backend (false);
2345 input_latency.set_value (il);
2346 output_latency.set_value (ol);
2349 // This should be done in push_state_to_backend()
2350 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2351 disable_latency_tab ();
2354 enable_latency_tab ();
2358 end_latency_detection ();
2359 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2364 /* latency measurement */
2367 EngineControl::check_audio_latency_measurement ()
2369 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2371 if (mtdm->resolve () < 0) {
2372 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2376 if (mtdm->err () > 0.3) {
2382 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2384 if (sample_rate == 0) {
2385 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2386 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2390 int frames_total = mtdm->del();
2391 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2393 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2394 _("Detected roundtrip latency: "),
2395 frames_total, frames_total * 1000.0f/sample_rate,
2396 _("Systemic latency: "),
2397 extra, extra * 1000.0f/sample_rate);
2401 if (mtdm->err () > 0.2) {
2403 strcat (buf, _("(signal detection error)"));
2409 strcat (buf, _("(inverted - bad wiring)"));
2413 lm_results.set_markup (string_compose (results_markup, buf));
2416 have_lm_results = true;
2417 end_latency_detection ();
2418 lm_use_button.set_sensitive (true);
2426 EngineControl::check_midi_latency_measurement ()
2428 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2430 if (!mididm->have_signal () || mididm->latency () == 0) {
2431 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2436 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2438 if (sample_rate == 0) {
2439 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2440 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2444 ARDOUR::framecnt_t frames_total = mididm->latency();
2445 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2446 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2447 _("Detected roundtrip latency: "),
2448 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2449 _("Systemic latency: "),
2450 extra, extra * 1000.0f / sample_rate);
2454 if (!mididm->ok ()) {
2456 strcat (buf, _("(averaging)"));
2460 if (mididm->deviation () > 50.0) {
2462 strcat (buf, _("(too large jitter)"));
2464 } else if (mididm->deviation () > 10.0) {
2466 strcat (buf, _("(large jitter)"));
2470 have_lm_results = true;
2471 end_latency_detection ();
2472 lm_use_button.set_sensitive (true);
2473 lm_results.set_markup (string_compose (results_markup, buf));
2475 } else if (mididm->processed () > 400) {
2476 have_lm_results = false;
2477 end_latency_detection ();
2478 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2482 lm_results.set_markup (string_compose (results_markup, buf));
2488 EngineControl::start_latency_detection ()
2490 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2491 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2493 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2494 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2495 if (_measure_midi) {
2496 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2498 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2500 lm_measure_label.set_text (_("Cancel"));
2501 have_lm_results = false;
2502 lm_use_button.set_sensitive (false);
2503 lm_input_channel_combo.set_sensitive (false);
2504 lm_output_channel_combo.set_sensitive (false);
2510 EngineControl::end_latency_detection ()
2512 latency_timeout.disconnect ();
2513 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2514 lm_measure_label.set_text (_("Measure"));
2515 if (!have_lm_results) {
2516 lm_use_button.set_sensitive (false);
2518 lm_input_channel_combo.set_sensitive (true);
2519 lm_output_channel_combo.set_sensitive (true);
2524 EngineControl::latency_button_clicked ()
2527 start_latency_detection ();
2529 end_latency_detection ();
2534 EngineControl::use_latency_button_clicked ()
2536 if (_measure_midi) {
2537 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2541 ARDOUR::framecnt_t frames_total = mididm->latency();
2542 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2543 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2544 _measure_midi->input_latency = one_way;
2545 _measure_midi->output_latency = one_way;
2546 notebook.set_current_page (midi_tab);
2548 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2554 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2555 one_way = std::max (0., one_way);
2557 input_latency_adjustment.set_value (one_way);
2558 output_latency_adjustment.set_value (one_way);
2560 /* back to settings page */
2561 notebook.set_current_page (0);
2567 EngineControl::on_delete_event (GdkEventAny* ev)
2569 if (notebook.get_current_page() == 2) {
2570 /* currently on latency tab - be sure to clean up */
2571 end_latency_detection ();
2573 return ArdourDialog::on_delete_event (ev);
2577 EngineControl::engine_running ()
2579 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2582 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2583 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2585 buffer_size_combo.set_sensitive (true);
2586 sample_rate_combo.set_sensitive (true);
2588 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2589 connect_disconnect_button.show();
2591 started_at_least_once = true;
2592 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2596 EngineControl::engine_stopped ()
2598 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2601 buffer_size_combo.set_sensitive (false);
2602 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2603 connect_disconnect_button.show();
2605 sample_rate_combo.set_sensitive (true);
2606 buffer_size_combo.set_sensitive (true);
2607 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2611 EngineControl::device_list_changed ()
2613 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2615 midi_option_changed();
2619 EngineControl::connect_disconnect_click()
2621 if (ARDOUR::AudioEngine::instance()->running()) {
2622 ARDOUR_UI::instance()->disconnect_from_engine ();
2624 ARDOUR_UI::instance()->reconnect_to_engine ();
2629 EngineControl::calibrate_audio_latency ()
2631 _measure_midi.reset ();
2632 have_lm_results = false;
2633 lm_use_button.set_sensitive (false);
2634 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2635 notebook.set_current_page (latency_tab);
2639 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2642 have_lm_results = false;
2643 lm_use_button.set_sensitive (false);
2644 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2645 notebook.set_current_page (latency_tab);
2649 EngineControl::configure_midi_devices ()
2651 notebook.set_current_page (midi_tab);