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 update_midi_options ();
885 connect_disconnect_button.hide();
887 midi_option_changed();
889 started_at_least_once = false;
891 if (!ignore_changes) {
892 maybe_display_saved_state ();
897 EngineControl::update_midi_options ()
899 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
900 vector<string> midi_options = backend->enumerate_midi_options();
902 if (midi_options.size() == 1) {
903 /* only contains the "none" option */
904 midi_option_combo.set_sensitive (false);
907 set_popdown_strings (midi_option_combo, midi_options);
908 midi_option_combo.set_active_text (midi_options.front());
909 midi_option_combo.set_sensitive (true);
911 midi_option_combo.set_sensitive (false);
917 EngineControl::print_channel_count (Gtk::SpinButton* sb)
919 if (ARDOUR::Profile->get_mixbus()) {
923 uint32_t cnt = (uint32_t) sb->get_value();
925 sb->set_text (_("all available channels"));
928 snprintf (buf, sizeof (buf), "%d", cnt);
935 EngineControl::set_driver_popdown_strings ()
937 DEBUG_ECONTROL ("set_driver_popdown_strings");
938 string backend_name = backend_combo.get_active_text();
939 boost::shared_ptr<ARDOUR::AudioBackend> backend;
941 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
942 /* eh? setting the backend failed... how ? */
943 /* A: stale config contains a backend that does not exist in current build */
947 vector<string> drivers = backend->enumerate_drivers();
948 set_popdown_strings (driver_combo, drivers);
952 // @return true if there are devices available
954 EngineControl::set_device_popdown_strings ()
956 DEBUG_ECONTROL ("set_device_popdown_strings");
957 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
958 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
960 /* NOTE: Ardour currently does not display the "available" field of the
963 * Doing so would require a different GUI widget than the combo
964 * box/popdown that we currently use, since it has no way to list
965 * items that are not selectable. Something more like a popup menu,
966 * which could have unselectable items, would be appropriate.
969 vector<string> available_devices;
971 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
972 available_devices.push_back (i->name);
976 if (!available_devices.empty()) {
979 string current_device, found_device;
980 current_device = device_combo.get_active_text ();
981 if (current_device == "") {
982 current_device = backend->device_name ();
985 // Make sure that the active text is still relevant for this
986 // device (it might only be relevant to the previous device!!)
987 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
988 if (*i == current_device)
989 found_device = current_device;
991 if (found_device == "")
992 // device has never been set (or was not relevant
993 // for this backend) Let's make sure it's not blank
994 current_device = available_devices.front ();
996 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
997 set_popdown_strings (device_combo, available_devices);
998 DEBUG_ECONTROL (string_compose ("set device_combo active text: %1", current_device));
1000 device_combo.set_active_text (current_device);
1007 // @return true if there are input devices available
1009 EngineControl::set_input_device_popdown_strings ()
1011 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1012 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1013 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1015 vector<string> available_devices;
1017 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1018 available_devices.push_back (i->name);
1021 if (!available_devices.empty()) {
1024 string current_device, found_device;
1025 current_device = input_device_combo.get_active_text ();
1026 if (current_device == "") {
1027 current_device = backend->input_device_name ();
1030 // Make sure that the active text is still relevant for this
1031 // device (it might only be relevant to the previous device!!)
1032 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1033 if (*i == current_device)
1034 found_device = current_device;
1036 if (found_device == "")
1037 // device has never been set (or was not relevant
1038 // for this backend) Let's make sure it's not blank
1039 current_device = available_devices.front ();
1041 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1042 set_popdown_strings (input_device_combo, available_devices);
1044 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1045 input_device_combo.set_active_text (current_device);
1053 // @return true if there are output devices available
1055 EngineControl::set_output_device_popdown_strings ()
1057 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1058 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1059 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1061 vector<string> available_devices;
1063 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1064 available_devices.push_back (i->name);
1067 if (!available_devices.empty()) {
1070 string current_device, found_device;
1071 current_device = output_device_combo.get_active_text ();
1072 if (current_device == "") {
1073 current_device = backend->output_device_name ();
1076 // Make sure that the active text is still relevant for this
1077 // device (it might only be relevant to the previous device!!)
1078 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1079 if (*i == current_device)
1080 found_device = current_device;
1082 if (found_device == "")
1083 // device has never been set (or was not relevant
1084 // for this backend) Let's make sure it's not blank
1085 current_device = available_devices.front ();
1087 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1088 set_popdown_strings (output_device_combo, available_devices);
1090 DEBUG_ECONTROL (string_compose ("set input_device_combo active text: %1", current_device));
1091 output_device_combo.set_active_text (current_device);
1100 EngineControl::list_devices ()
1102 DEBUG_ECONTROL ("list_devices");
1103 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1106 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1108 bool devices_available = false;
1110 if (backend->use_separate_input_and_output_devices ()) {
1111 bool input_devices_available = set_input_device_popdown_strings ();
1112 bool output_devices_available = set_output_device_popdown_strings ();
1113 devices_available = input_devices_available || output_devices_available;
1115 devices_available = set_device_popdown_strings ();
1118 if (devices_available) {
1121 input_latency.set_sensitive (true);
1122 output_latency.set_sensitive (true);
1123 input_channels.set_sensitive (true);
1124 output_channels.set_sensitive (true);
1126 ok_button->set_sensitive (true);
1127 apply_button->set_sensitive (true);
1130 device_combo.clear();
1131 input_device_combo.clear();
1132 output_device_combo.clear();
1133 sample_rate_combo.set_sensitive (false);
1134 buffer_size_combo.set_sensitive (false);
1135 input_latency.set_sensitive (false);
1136 output_latency.set_sensitive (false);
1137 input_channels.set_sensitive (false);
1138 output_channels.set_sensitive (false);
1139 if (_have_control) {
1140 ok_button->set_sensitive (false);
1141 apply_button->set_sensitive (false);
1143 ok_button->set_sensitive (true);
1144 apply_button->set_sensitive (true);
1145 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1146 sample_rate_combo.set_sensitive (true);
1148 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1149 buffer_size_combo.set_sensitive (true);
1157 EngineControl::driver_changed ()
1159 DEBUG_ECONTROL ("driver_changed");
1160 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1163 backend->set_driver (driver_combo.get_active_text());
1166 if (!ignore_changes) {
1167 maybe_display_saved_state ();
1172 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1174 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1175 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1180 if (_have_control) {
1181 sr = backend->available_sample_rates (device_name);
1184 sr.push_back (8000.0f);
1185 sr.push_back (16000.0f);
1186 sr.push_back (32000.0f);
1187 sr.push_back (44100.0f);
1188 sr.push_back (48000.0f);
1189 sr.push_back (88200.0f);
1190 sr.push_back (96000.0f);
1191 sr.push_back (192000.0f);
1192 sr.push_back (384000.0f);
1195 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1196 s.push_back (rate_as_string (*x));
1197 if (*x == _desired_sample_rate) {
1203 sample_rate_combo.set_sensitive (true);
1204 set_popdown_strings (sample_rate_combo, s);
1206 if (desired.empty()) {
1207 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1209 sample_rate_combo.set_active_text (desired);
1213 sample_rate_combo.set_sensitive (false);
1218 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1220 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1221 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1222 vector<uint32_t> bs;
1225 if (_have_control) {
1226 bs = backend->available_buffer_sizes (device_name);
1227 } else if (backend->can_change_buffer_size_when_running()) {
1235 bs.push_back (1024);
1236 bs.push_back (2048);
1237 bs.push_back (4096);
1238 bs.push_back (8192);
1241 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1242 s.push_back (bufsize_as_string (*x));
1246 buffer_size_combo.set_sensitive (true);
1247 set_popdown_strings (buffer_size_combo, s);
1248 buffer_size_combo.set_active_text (s.front());
1250 uint32_t period = backend->buffer_size();
1252 period = backend->default_buffer_size(device_name);
1254 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1255 show_buffer_duration ();
1257 buffer_size_combo.set_sensitive (false);
1262 EngineControl::device_changed ()
1264 DEBUG_ECONTROL ("device_changed");
1265 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1268 string device_name_in;
1269 string device_name_out; // only used if backend support separate I/O devices
1271 if (backend->use_separate_input_and_output_devices()) {
1272 device_name_in = get_input_device_name ();
1273 device_name_out = get_output_device_name ();
1275 device_name_in = get_device_name ();
1278 /* we set the backend-device to query various device related intormation.
1279 * This has the side effect that backend->device_name() will match
1280 * the device_name and 'change_device' will never be true.
1281 * so work around this by setting...
1283 if (backend->use_separate_input_and_output_devices()) {
1284 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1285 queue_device_changed = true;
1288 if (device_name_in != backend->device_name()) {
1289 queue_device_changed = true;
1293 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1294 if (backend->use_separate_input_and_output_devices()) {
1295 backend->set_input_device_name (device_name_in);
1296 backend->set_output_device_name (device_name_out);
1298 backend->set_device_name(device_name_in);
1302 /* don't allow programmatic change to combos to cause a
1303 recursive call to this method.
1305 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1307 /* backends that support separate devices, need to ignore
1308 * the device-name - and use the devies set above
1310 set_samplerate_popdown_strings (device_name_in);
1311 set_buffersize_popdown_strings (device_name_in);
1312 /* XXX theoretically need to set min + max channel counts here
1315 manage_control_app_sensitivity ();
1318 /* pick up any saved state for this device */
1320 if (!ignore_changes) {
1321 maybe_display_saved_state ();
1326 EngineControl::input_device_changed ()
1328 DEBUG_ECONTROL ("input_device_changed");
1333 EngineControl::output_device_changed ()
1335 DEBUG_ECONTROL ("output_device_changed");
1340 EngineControl::bufsize_as_string (uint32_t sz)
1342 /* Translators: "samples" is always plural here, so no
1343 need for plural+singular forms.
1346 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1351 EngineControl::sample_rate_changed ()
1353 DEBUG_ECONTROL ("sample_rate_changed");
1354 /* reset the strings for buffer size to show the correct msec value
1355 (reflecting the new sample rate).
1358 show_buffer_duration ();
1363 EngineControl::buffer_size_changed ()
1365 DEBUG_ECONTROL ("buffer_size_changed");
1366 show_buffer_duration ();
1370 EngineControl::show_buffer_duration ()
1372 DEBUG_ECONTROL ("show_buffer_duration");
1373 /* buffer sizes - convert from just samples to samples + msecs for
1374 * the displayed string
1377 string bs_text = buffer_size_combo.get_active_text ();
1378 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1379 uint32_t rate = get_rate();
1381 /* Developers: note the hard-coding of a double buffered model
1382 in the (2 * samples) computation of latency. we always start
1383 the audiobackend in this configuration.
1385 /* note to jack1 developers: ardour also always starts the engine
1386 * in async mode (no jack2 --sync option) which adds an extra cycle
1387 * of latency with jack2 (and *3 would be correct)
1388 * The value can also be wrong if jackd is started externally..
1390 * At the time of writing the ALSA backend always uses double-buffering *2,
1391 * The Dummy backend *1, and who knows what ASIO really does :)
1393 * So just display the period size, that's also what
1394 * ARDOUR_UI::update_sample_rate() does for the status bar.
1395 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1396 * but still, that's the buffer period, not [round-trip] latency)
1399 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1400 buffer_size_duration_label.set_text (buf);
1404 EngineControl::midi_option_changed ()
1406 DEBUG_ECONTROL ("midi_option_changed");
1407 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1410 backend->set_midi_option (get_midi_option());
1412 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1414 //_midi_devices.clear(); // TODO merge with state-saved settings..
1415 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1416 std::vector<MidiDeviceSettings> new_devices;
1418 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1419 MidiDeviceSettings mds = find_midi_device (i->name);
1420 if (i->available && !mds) {
1421 uint32_t input_latency = 0;
1422 uint32_t output_latency = 0;
1423 if (_can_set_midi_latencies) {
1424 input_latency = backend->systemic_midi_input_latency (i->name);
1425 output_latency = backend->systemic_midi_output_latency (i->name);
1427 bool enabled = backend->midi_device_enabled (i->name);
1428 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1429 new_devices.push_back (ptr);
1430 } else if (i->available) {
1431 new_devices.push_back (mds);
1434 _midi_devices = new_devices;
1436 if (_midi_devices.empty()) {
1437 midi_devices_button.set_sensitive (false);
1439 midi_devices_button.set_sensitive (true);
1444 EngineControl::parameter_changed ()
1448 EngineControl::State
1449 EngineControl::get_matching_state (
1450 const string& backend,
1451 const string& driver,
1452 const string& device)
1454 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1455 if ((*i)->backend == backend &&
1456 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1464 EngineControl::State
1465 EngineControl::get_matching_state (
1466 const string& backend,
1467 const string& driver,
1468 const string& input_device,
1469 const string& output_device)
1471 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1472 if ((*i)->backend == backend &&
1473 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1481 EngineControl::State
1482 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1484 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1487 if (backend->use_separate_input_and_output_devices ()) {
1488 return get_matching_state (backend_combo.get_active_text(),
1489 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1490 input_device_combo.get_active_text(),
1491 output_device_combo.get_active_text());
1493 return get_matching_state (backend_combo.get_active_text(),
1494 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1495 device_combo.get_active_text());
1499 return get_matching_state (backend_combo.get_active_text(),
1501 device_combo.get_active_text());
1504 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1505 const EngineControl::State& state2)
1507 if (state1->backend == state2->backend &&
1508 state1->driver == state2->driver &&
1509 state1->device == state2->device &&
1510 state1->input_device == state2->input_device &&
1511 state1->output_device == state2->output_device) {
1517 EngineControl::State
1518 EngineControl::save_state ()
1522 if (!_have_control) {
1523 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1527 state.reset(new StateStruct);
1528 state->backend = get_backend ();
1530 state.reset(new StateStruct);
1531 store_state (state);
1534 for (StateList::iterator i = states.begin(); i != states.end();) {
1535 if (equivalent_states (*i, state)) {
1536 i = states.erase(i);
1542 states.push_back (state);
1548 EngineControl::store_state (State state)
1550 state->backend = get_backend ();
1551 state->driver = get_driver ();
1552 state->device = get_device_name ();
1553 state->input_device = get_input_device_name ();
1554 state->output_device = get_output_device_name ();
1555 state->sample_rate = get_rate ();
1556 state->buffer_size = get_buffer_size ();
1557 state->input_latency = get_input_latency ();
1558 state->output_latency = get_output_latency ();
1559 state->input_channels = get_input_channels ();
1560 state->output_channels = get_output_channels ();
1561 state->midi_option = get_midi_option ();
1562 state->midi_devices = _midi_devices;
1566 EngineControl::maybe_display_saved_state ()
1568 if (!_have_control) {
1572 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1575 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1577 if (!_desired_sample_rate) {
1578 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1580 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1581 /* call this explicitly because we're ignoring changes to
1582 the controls at this point.
1584 show_buffer_duration ();
1585 input_latency.set_value (state->input_latency);
1586 output_latency.set_value (state->output_latency);
1588 if (!state->midi_option.empty()) {
1589 midi_option_combo.set_active_text (state->midi_option);
1590 _midi_devices = state->midi_devices;
1596 EngineControl::get_state ()
1598 LocaleGuard lg (X_("C"));
1600 XMLNode* root = new XMLNode ("AudioMIDISetup");
1603 if (!states.empty()) {
1604 XMLNode* state_nodes = new XMLNode ("EngineStates");
1606 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1608 XMLNode* node = new XMLNode ("State");
1610 node->add_property ("backend", (*i)->backend);
1611 node->add_property ("driver", (*i)->driver);
1612 node->add_property ("device", (*i)->device);
1613 node->add_property ("input-device", (*i)->input_device);
1614 node->add_property ("output-device", (*i)->output_device);
1615 node->add_property ("sample-rate", (*i)->sample_rate);
1616 node->add_property ("buffer-size", (*i)->buffer_size);
1617 node->add_property ("input-latency", (*i)->input_latency);
1618 node->add_property ("output-latency", (*i)->output_latency);
1619 node->add_property ("input-channels", (*i)->input_channels);
1620 node->add_property ("output-channels", (*i)->output_channels);
1621 node->add_property ("active", (*i)->active ? "yes" : "no");
1622 node->add_property ("midi-option", (*i)->midi_option);
1624 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1625 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1626 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1627 midi_device_stuff->add_property (X_("name"), (*p)->name);
1628 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1629 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1630 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1631 midi_devices->add_child_nocopy (*midi_device_stuff);
1633 node->add_child_nocopy (*midi_devices);
1635 state_nodes->add_child_nocopy (*node);
1638 root->add_child_nocopy (*state_nodes);
1645 EngineControl::set_state (const XMLNode& root)
1647 XMLNodeList clist, cclist;
1648 XMLNodeConstIterator citer, cciter;
1650 XMLNode* grandchild;
1651 XMLProperty* prop = NULL;
1653 fprintf (stderr, "EngineControl::set_state\n");
1655 if (root.name() != "AudioMIDISetup") {
1659 clist = root.children();
1663 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1667 if (child->name() != "EngineStates") {
1671 cclist = child->children();
1673 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1674 State state (new StateStruct);
1676 grandchild = *cciter;
1678 if (grandchild->name() != "State") {
1682 if ((prop = grandchild->property ("backend")) == 0) {
1685 state->backend = prop->value ();
1687 if ((prop = grandchild->property ("driver")) == 0) {
1690 state->driver = prop->value ();
1692 if ((prop = grandchild->property ("device")) == 0) {
1695 state->device = prop->value ();
1697 if ((prop = grandchild->property ("input-device")) == 0) {
1700 state->input_device = prop->value ();
1702 if ((prop = grandchild->property ("output-device")) == 0) {
1705 state->output_device = prop->value ();
1707 if ((prop = grandchild->property ("sample-rate")) == 0) {
1710 state->sample_rate = atof (prop->value ());
1712 if ((prop = grandchild->property ("buffer-size")) == 0) {
1715 state->buffer_size = atoi (prop->value ());
1717 if ((prop = grandchild->property ("input-latency")) == 0) {
1720 state->input_latency = atoi (prop->value ());
1722 if ((prop = grandchild->property ("output-latency")) == 0) {
1725 state->output_latency = atoi (prop->value ());
1727 if ((prop = grandchild->property ("input-channels")) == 0) {
1730 state->input_channels = atoi (prop->value ());
1732 if ((prop = grandchild->property ("output-channels")) == 0) {
1735 state->output_channels = atoi (prop->value ());
1737 if ((prop = grandchild->property ("active")) == 0) {
1740 state->active = string_is_affirmative (prop->value ());
1742 if ((prop = grandchild->property ("midi-option")) == 0) {
1745 state->midi_option = prop->value ();
1747 state->midi_devices.clear();
1749 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1750 const XMLNodeList mnc = midinode->children();
1751 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1752 if ((*n)->property (X_("name")) == 0
1753 || (*n)->property (X_("enabled")) == 0
1754 || (*n)->property (X_("input-latency")) == 0
1755 || (*n)->property (X_("output-latency")) == 0
1760 MidiDeviceSettings ptr (new MidiDeviceSetting(
1761 (*n)->property (X_("name"))->value (),
1762 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1763 atoi ((*n)->property (X_("input-latency"))->value ()),
1764 atoi ((*n)->property (X_("output-latency"))->value ())
1766 state->midi_devices.push_back (ptr);
1771 /* remove accumulated duplicates (due to bug in ealier version)
1772 * this can be removed again before release
1774 for (StateList::iterator i = states.begin(); i != states.end();) {
1775 if ((*i)->backend == state->backend &&
1776 (*i)->driver == state->driver &&
1777 (*i)->device == state->device) {
1778 i = states.erase(i);
1785 states.push_back (state);
1789 /* now see if there was an active state and switch the setup to it */
1791 // purge states of backend that are not available in this built
1792 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1793 vector<std::string> backend_names;
1795 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1796 backend_names.push_back((*i)->name);
1798 for (StateList::iterator i = states.begin(); i != states.end();) {
1799 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1800 i = states.erase(i);
1806 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1809 set_current_state (*i);
1816 EngineControl::set_current_state (const State& state)
1818 DEBUG_ECONTROL ("set_current_state");
1819 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1820 backend_combo.set_active_text (state->backend);
1822 /* The driver popdown strings need to be populated now so that
1823 * set_active_text will actually set a valid entry. Then
1824 * backend_changed() will populate all the other combo's so they
1825 * can also be set to valid entries and the state will be restored
1828 if (!state->driver.empty()) {
1829 set_driver_popdown_strings ();
1831 driver_combo.set_active_text (state->driver);
1834 device_combo.set_active_text (state->device);
1835 input_device_combo.set_active_text (state->input_device);
1836 output_device_combo.set_active_text (state->output_device);
1837 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1838 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1839 input_latency.set_value (state->input_latency);
1840 output_latency.set_value (state->output_latency);
1841 midi_option_combo.set_active_text (state->midi_option);
1845 EngineControl::push_state_to_backend (bool start)
1847 DEBUG_ECONTROL ("push_state_to_backend");
1848 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1854 /* figure out what is going to change */
1856 bool restart_required = false;
1857 bool was_running = ARDOUR::AudioEngine::instance()->running();
1858 bool change_driver = false;
1859 bool change_device = false;
1860 bool change_rate = false;
1861 bool change_bufsize = false;
1862 bool change_latency = false;
1863 bool change_channels = false;
1864 bool change_midi = false;
1866 uint32_t ochan = get_output_channels ();
1867 uint32_t ichan = get_input_channels ();
1869 if (_have_control) {
1871 if (started_at_least_once) {
1873 /* we can control the backend */
1875 if (backend->requires_driver_selection()) {
1876 if (get_driver() != backend->driver_name()) {
1877 change_driver = true;
1881 if (backend->use_separate_input_and_output_devices()) {
1882 if (get_input_device_name() != backend->input_device_name()) {
1883 change_device = true;
1885 if (get_output_device_name() != backend->output_device_name()) {
1886 change_device = true;
1889 if (get_device_name() != backend->device_name()) {
1890 change_device = true;
1894 if (queue_device_changed) {
1895 change_device = true;
1898 if (get_rate() != backend->sample_rate()) {
1902 if (get_buffer_size() != backend->buffer_size()) {
1903 change_bufsize = true;
1906 if (get_midi_option() != backend->midi_option()) {
1910 /* zero-requested channels means "all available" */
1913 ichan = backend->input_channels();
1917 ochan = backend->output_channels();
1920 if (ichan != backend->input_channels()) {
1921 change_channels = true;
1924 if (ochan != backend->output_channels()) {
1925 change_channels = true;
1928 if (get_input_latency() != backend->systemic_input_latency() ||
1929 get_output_latency() != backend->systemic_output_latency()) {
1930 change_latency = true;
1933 /* backend never started, so we have to force a group
1936 change_device = true;
1937 if (backend->requires_driver_selection()) {
1938 change_driver = true;
1941 change_bufsize = true;
1942 change_channels = true;
1943 change_latency = true;
1949 /* we have no control over the backend, meaning that we can
1950 * only possibly change sample rate and buffer size.
1954 if (get_rate() != backend->sample_rate()) {
1955 change_bufsize = true;
1958 if (get_buffer_size() != backend->buffer_size()) {
1959 change_bufsize = true;
1963 queue_device_changed = false;
1965 if (!_have_control) {
1967 /* We do not have control over the backend, so the best we can
1968 * do is try to change the sample rate and/or bufsize and get
1972 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1976 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1981 backend->set_sample_rate (get_rate());
1984 if (change_bufsize) {
1985 backend->set_buffer_size (get_buffer_size());
1989 if (ARDOUR::AudioEngine::instance()->start ()) {
1990 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2000 /* determine if we need to stop the backend before changing parameters */
2002 if (change_driver || change_device || change_channels || change_latency ||
2003 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2005 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2006 restart_required = true;
2008 restart_required = false;
2013 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2014 /* no changes in any parameters that absolutely require a
2015 * restart, so check those that might be changeable without a
2019 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2020 /* can't do this while running ... */
2021 restart_required = true;
2024 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2025 /* can't do this while running ... */
2026 restart_required = true;
2032 if (restart_required) {
2033 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2040 if (change_driver && backend->set_driver (get_driver())) {
2041 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2044 if (backend->use_separate_input_and_output_devices()) {
2045 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2046 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2049 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2050 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2054 if (change_device && backend->set_device_name (get_device_name())) {
2055 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2059 if (change_rate && backend->set_sample_rate (get_rate())) {
2060 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2063 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2064 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2068 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2069 if (backend->set_input_channels (get_input_channels())) {
2070 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2073 if (backend->set_output_channels (get_output_channels())) {
2074 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2078 if (change_latency) {
2079 if (backend->set_systemic_input_latency (get_input_latency())) {
2080 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2083 if (backend->set_systemic_output_latency (get_output_latency())) {
2084 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2090 backend->set_midi_option (get_midi_option());
2094 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2095 if (_measure_midi) {
2096 if (*p == _measure_midi) {
2097 backend->set_midi_device_enabled ((*p)->name, true);
2099 backend->set_midi_device_enabled ((*p)->name, false);
2103 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2104 if (backend->can_set_systemic_midi_latencies()) {
2105 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2106 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2111 if (start || (was_running && restart_required)) {
2112 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2123 EngineControl::post_push ()
2125 /* get a pointer to the current state object, creating one if
2129 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2132 state = save_state ();
2140 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2141 (*i)->active = false;
2144 /* mark this one active (to be used next time the dialog is
2148 state->active = true;
2150 if (_have_control) { // XXX
2151 manage_control_app_sensitivity ();
2154 /* schedule a redisplay of MIDI ports */
2155 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2160 EngineControl::get_rate () const
2162 float r = atof (sample_rate_combo.get_active_text ());
2163 /* the string may have been translated with an abbreviation for
2164 * thousands, so use a crude heuristic to fix this.
2174 EngineControl::get_buffer_size () const
2176 string txt = buffer_size_combo.get_active_text ();
2179 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2180 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2181 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2189 EngineControl::get_midi_option () const
2191 return midi_option_combo.get_active_text();
2195 EngineControl::get_input_channels() const
2197 if (ARDOUR::Profile->get_mixbus()) {
2198 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2199 if (!backend) return 0;
2200 return backend->input_channels();
2202 return (uint32_t) input_channels_adjustment.get_value();
2206 EngineControl::get_output_channels() const
2208 if (ARDOUR::Profile->get_mixbus()) {
2209 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2210 if (!backend) return 0;
2211 return backend->input_channels();
2213 return (uint32_t) output_channels_adjustment.get_value();
2217 EngineControl::get_input_latency() const
2219 return (uint32_t) input_latency_adjustment.get_value();
2223 EngineControl::get_output_latency() const
2225 return (uint32_t) output_latency_adjustment.get_value();
2229 EngineControl::get_backend () const
2231 return backend_combo.get_active_text ();
2235 EngineControl::get_driver () const
2237 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2238 return driver_combo.get_active_text ();
2245 EngineControl::get_device_name () const
2247 return device_combo.get_active_text ();
2251 EngineControl::get_input_device_name () const
2253 return input_device_combo.get_active_text ();
2257 EngineControl::get_output_device_name () const
2259 return output_device_combo.get_active_text ();
2263 EngineControl::control_app_button_clicked ()
2265 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2271 backend->launch_control_app ();
2275 EngineControl::manage_control_app_sensitivity ()
2277 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2283 string appname = backend->control_app_name();
2285 if (appname.empty()) {
2286 control_app_button.set_sensitive (false);
2288 control_app_button.set_sensitive (true);
2293 EngineControl::set_desired_sample_rate (uint32_t sr)
2295 _desired_sample_rate = sr;
2300 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2302 if (page_num == 0) {
2303 cancel_button->set_sensitive (true);
2304 ok_button->set_sensitive (true);
2305 apply_button->set_sensitive (true);
2306 _measure_midi.reset();
2308 cancel_button->set_sensitive (false);
2309 ok_button->set_sensitive (false);
2310 apply_button->set_sensitive (false);
2313 if (page_num == midi_tab) {
2315 refresh_midi_display ();
2318 if (page_num == latency_tab) {
2321 if (ARDOUR::AudioEngine::instance()->running()) {
2322 // TODO - mark as 'stopped for latency
2323 ARDOUR_UI::instance()->disconnect_from_engine ();
2327 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2329 /* save any existing latency values */
2331 uint32_t il = (uint32_t) input_latency.get_value ();
2332 uint32_t ol = (uint32_t) input_latency.get_value ();
2334 /* reset to zero so that our new test instance
2335 will be clean of any existing latency measures.
2337 NB. this should really be done by the backend
2338 when stated for latency measurement.
2341 input_latency.set_value (0);
2342 output_latency.set_value (0);
2344 push_state_to_backend (false);
2348 input_latency.set_value (il);
2349 output_latency.set_value (ol);
2352 // This should be done in push_state_to_backend()
2353 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2354 disable_latency_tab ();
2357 enable_latency_tab ();
2361 end_latency_detection ();
2362 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2367 /* latency measurement */
2370 EngineControl::check_audio_latency_measurement ()
2372 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2374 if (mtdm->resolve () < 0) {
2375 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2379 if (mtdm->err () > 0.3) {
2385 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2387 if (sample_rate == 0) {
2388 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2389 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2393 int frames_total = mtdm->del();
2394 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2396 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2397 _("Detected roundtrip latency: "),
2398 frames_total, frames_total * 1000.0f/sample_rate,
2399 _("Systemic latency: "),
2400 extra, extra * 1000.0f/sample_rate);
2404 if (mtdm->err () > 0.2) {
2406 strcat (buf, _("(signal detection error)"));
2412 strcat (buf, _("(inverted - bad wiring)"));
2416 lm_results.set_markup (string_compose (results_markup, buf));
2419 have_lm_results = true;
2420 end_latency_detection ();
2421 lm_use_button.set_sensitive (true);
2429 EngineControl::check_midi_latency_measurement ()
2431 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2433 if (!mididm->have_signal () || mididm->latency () == 0) {
2434 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2439 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2441 if (sample_rate == 0) {
2442 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2443 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2447 ARDOUR::framecnt_t frames_total = mididm->latency();
2448 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2449 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2450 _("Detected roundtrip latency: "),
2451 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2452 _("Systemic latency: "),
2453 extra, extra * 1000.0f / sample_rate);
2457 if (!mididm->ok ()) {
2459 strcat (buf, _("(averaging)"));
2463 if (mididm->deviation () > 50.0) {
2465 strcat (buf, _("(too large jitter)"));
2467 } else if (mididm->deviation () > 10.0) {
2469 strcat (buf, _("(large jitter)"));
2473 have_lm_results = true;
2474 end_latency_detection ();
2475 lm_use_button.set_sensitive (true);
2476 lm_results.set_markup (string_compose (results_markup, buf));
2478 } else if (mididm->processed () > 400) {
2479 have_lm_results = false;
2480 end_latency_detection ();
2481 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2485 lm_results.set_markup (string_compose (results_markup, buf));
2491 EngineControl::start_latency_detection ()
2493 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2494 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2496 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2497 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2498 if (_measure_midi) {
2499 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2501 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2503 lm_measure_label.set_text (_("Cancel"));
2504 have_lm_results = false;
2505 lm_use_button.set_sensitive (false);
2506 lm_input_channel_combo.set_sensitive (false);
2507 lm_output_channel_combo.set_sensitive (false);
2513 EngineControl::end_latency_detection ()
2515 latency_timeout.disconnect ();
2516 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2517 lm_measure_label.set_text (_("Measure"));
2518 if (!have_lm_results) {
2519 lm_use_button.set_sensitive (false);
2521 lm_input_channel_combo.set_sensitive (true);
2522 lm_output_channel_combo.set_sensitive (true);
2527 EngineControl::latency_button_clicked ()
2530 start_latency_detection ();
2532 end_latency_detection ();
2537 EngineControl::use_latency_button_clicked ()
2539 if (_measure_midi) {
2540 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2544 ARDOUR::framecnt_t frames_total = mididm->latency();
2545 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2546 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2547 _measure_midi->input_latency = one_way;
2548 _measure_midi->output_latency = one_way;
2549 notebook.set_current_page (midi_tab);
2551 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2557 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2558 one_way = std::max (0., one_way);
2560 input_latency_adjustment.set_value (one_way);
2561 output_latency_adjustment.set_value (one_way);
2563 /* back to settings page */
2564 notebook.set_current_page (0);
2570 EngineControl::on_delete_event (GdkEventAny* ev)
2572 if (notebook.get_current_page() == 2) {
2573 /* currently on latency tab - be sure to clean up */
2574 end_latency_detection ();
2576 return ArdourDialog::on_delete_event (ev);
2580 EngineControl::engine_running ()
2582 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2585 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2586 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2588 buffer_size_combo.set_sensitive (true);
2589 sample_rate_combo.set_sensitive (true);
2591 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2592 connect_disconnect_button.show();
2594 started_at_least_once = true;
2595 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2599 EngineControl::engine_stopped ()
2601 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2604 buffer_size_combo.set_sensitive (false);
2605 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2606 connect_disconnect_button.show();
2608 sample_rate_combo.set_sensitive (true);
2609 buffer_size_combo.set_sensitive (true);
2610 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2614 EngineControl::device_list_changed ()
2616 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2618 midi_option_changed();
2622 EngineControl::connect_disconnect_click()
2624 if (ARDOUR::AudioEngine::instance()->running()) {
2625 ARDOUR_UI::instance()->disconnect_from_engine ();
2627 ARDOUR_UI::instance()->reconnect_to_engine ();
2632 EngineControl::calibrate_audio_latency ()
2634 _measure_midi.reset ();
2635 have_lm_results = false;
2636 lm_use_button.set_sensitive (false);
2637 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2638 notebook.set_current_page (latency_tab);
2642 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2645 have_lm_results = false;
2646 lm_use_button.set_sensitive (false);
2647 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2648 notebook.set_current_page (latency_tab);
2652 EngineControl::configure_midi_devices ()
2654 notebook.set_current_page (midi_tab);