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 if (!set_state (*audio_setup)) {
287 set_default_state ();
290 set_default_state ();
293 connect_changed_signals ();
295 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
297 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
298 connect_disconnect_button.set_no_show_all();
303 EngineControl::connect_changed_signals ()
305 backend_combo_connection = backend_combo.signal_changed ().connect (
306 sigc::mem_fun (*this, &EngineControl::backend_changed));
307 driver_combo_connection = driver_combo.signal_changed ().connect (
308 sigc::mem_fun (*this, &EngineControl::driver_changed));
309 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
310 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
311 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
312 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
313 device_combo_connection = device_combo.signal_changed ().connect (
314 sigc::mem_fun (*this, &EngineControl::device_changed));
315 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
316 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
318 input_device_combo_connection = input_device_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::input_device_changed));
320 output_device_combo_connection = output_device_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::output_device_changed));
323 input_latency_connection = input_latency.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::parameter_changed));
325 output_latency_connection = output_latency.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::parameter_changed));
327 input_channels_connection = input_channels.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::parameter_changed));
329 output_channels_connection = output_channels.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::parameter_changed));
334 EngineControl::block_changed_signals ()
336 if (block_signals++ == 0) {
337 DEBUG_ECONTROL ("Blocking changed signals");
338 backend_combo_connection.block ();
339 driver_combo_connection.block ();
340 sample_rate_combo_connection.block ();
341 buffer_size_combo_connection.block ();
342 device_combo_connection.block ();
343 input_device_combo_connection.block ();
344 output_device_combo_connection.block ();
345 midi_option_combo_connection.block ();
346 input_latency_connection.block ();
347 output_latency_connection.block ();
348 input_channels_connection.block ();
349 output_channels_connection.block ();
354 EngineControl::unblock_changed_signals ()
356 if (--block_signals == 0) {
357 DEBUG_ECONTROL ("Unblocking changed signals");
358 backend_combo_connection.unblock ();
359 driver_combo_connection.unblock ();
360 sample_rate_combo_connection.unblock ();
361 buffer_size_combo_connection.unblock ();
362 device_combo_connection.unblock ();
363 input_device_combo_connection.unblock ();
364 output_device_combo_connection.unblock ();
365 midi_option_combo_connection.unblock ();
366 input_latency_connection.unblock ();
367 output_latency_connection.unblock ();
368 input_channels_connection.unblock ();
369 output_channels_connection.unblock ();
373 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
374 const std::string& reason)
375 : ec (engine_control)
378 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
379 ec.block_changed_signals ();
382 EngineControl::SignalBlocker::~SignalBlocker ()
384 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
385 ec.unblock_changed_signals ();
389 EngineControl::on_show ()
391 ArdourDialog::on_show ();
392 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
393 // re-check _have_control (jackd running) see #6041
397 ok_button->grab_focus();
401 EngineControl::on_response (int response_id)
403 ArdourDialog::on_response (response_id);
405 switch (response_id) {
407 push_state_to_backend (true);
410 #ifdef PLATFORM_WINDOWS
411 // For some reason we don't understand, 'hide()'
412 // needs to get called first in Windows
415 // But if there's no session open, this can produce
416 // a long gap when nothing appears to be happening.
417 // Let's show the splash image while we're waiting.
418 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
419 if ( ARDOUR_UI::instance() ) {
420 if ( !ARDOUR_UI::instance()->session_loaded ) {
421 ARDOUR_UI::instance()->show_splash();
425 push_state_to_backend (true);
428 push_state_to_backend (true);
432 case RESPONSE_DELETE_EVENT:
435 ev.type = GDK_BUTTON_PRESS;
437 on_delete_event ((GdkEventAny*) &ev);
446 EngineControl::build_notebook ()
449 AttachOptions xopt = AttachOptions (FILL|EXPAND);
451 /* clear the table */
453 Gtkmm2ext::container_clear (basic_vbox);
454 Gtkmm2ext::container_clear (basic_packer);
456 if (control_app_button.get_parent()) {
457 control_app_button.get_parent()->remove (control_app_button);
460 label = manage (left_aligned_label (_("Audio System:")));
461 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
462 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
464 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
465 lm_button_audio.set_name ("generic button");
466 lm_button_audio.set_can_focus(true);
469 build_full_control_notebook ();
471 build_no_control_notebook ();
474 basic_vbox.pack_start (basic_hbox, false, false);
477 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
478 basic_vbox.show_all ();
483 EngineControl::build_full_control_notebook ()
485 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
488 using namespace Notebook_Helpers;
490 vector<string> strings;
491 AttachOptions xopt = AttachOptions (FILL|EXPAND);
492 int row = 1; // row zero == backend combo
494 /* start packing it up */
496 if (backend->requires_driver_selection()) {
497 label = manage (left_aligned_label (_("Driver:")));
498 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
499 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
503 if (backend->use_separate_input_and_output_devices()) {
504 label = manage (left_aligned_label (_("Input Device:")));
505 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
506 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
508 label = manage (left_aligned_label (_("Output Device:")));
509 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
510 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
512 // reset so it isn't used in state comparisons
513 device_combo.set_active_text ("");
515 label = manage (left_aligned_label (_("Device:")));
516 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
517 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
519 // reset these so they don't get used in state comparisons
520 input_device_combo.set_active_text ("");
521 output_device_combo.set_active_text ("");
524 label = manage (left_aligned_label (_("Sample rate:")));
525 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
526 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
530 label = manage (left_aligned_label (_("Buffer size:")));
531 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
532 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
533 buffer_size_duration_label.set_alignment (0.0); /* left-align */
534 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
536 /* button spans 2 rows */
538 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
541 input_channels.set_name ("InputChannels");
542 input_channels.set_flags (Gtk::CAN_FOCUS);
543 input_channels.set_digits (0);
544 input_channels.set_wrap (false);
545 output_channels.set_editable (true);
547 if (!ARDOUR::Profile->get_mixbus()) {
548 label = manage (left_aligned_label (_("Input Channels:")));
549 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
550 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
554 output_channels.set_name ("OutputChannels");
555 output_channels.set_flags (Gtk::CAN_FOCUS);
556 output_channels.set_digits (0);
557 output_channels.set_wrap (false);
558 output_channels.set_editable (true);
560 if (!ARDOUR::Profile->get_mixbus()) {
561 label = manage (left_aligned_label (_("Output Channels:")));
562 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
563 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
567 input_latency.set_name ("InputLatency");
568 input_latency.set_flags (Gtk::CAN_FOCUS);
569 input_latency.set_digits (0);
570 input_latency.set_wrap (false);
571 input_latency.set_editable (true);
573 label = manage (left_aligned_label (_("Hardware input latency:")));
574 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
575 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
576 label = manage (left_aligned_label (_("samples")));
577 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
580 output_latency.set_name ("OutputLatency");
581 output_latency.set_flags (Gtk::CAN_FOCUS);
582 output_latency.set_digits (0);
583 output_latency.set_wrap (false);
584 output_latency.set_editable (true);
586 label = manage (left_aligned_label (_("Hardware output latency:")));
587 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
588 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
589 label = manage (left_aligned_label (_("samples")));
590 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
592 /* button spans 2 rows */
594 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
597 label = manage (left_aligned_label (_("MIDI System:")));
598 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
599 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
600 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
605 EngineControl::build_no_control_notebook ()
607 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
610 using namespace Notebook_Helpers;
612 vector<string> strings;
613 AttachOptions xopt = AttachOptions (FILL|EXPAND);
614 int row = 1; // row zero == backend combo
615 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
617 label = manage (new Label);
618 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
619 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
622 if (backend->can_change_sample_rate_when_running()) {
623 label = manage (left_aligned_label (_("Sample rate:")));
624 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
625 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
629 if (backend->can_change_buffer_size_when_running()) {
630 label = manage (left_aligned_label (_("Buffer size:")));
631 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
632 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
633 buffer_size_duration_label.set_alignment (0.0); /* left-align */
634 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
638 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
642 EngineControl::~EngineControl ()
644 ignore_changes = true;
648 EngineControl::disable_latency_tab ()
650 vector<string> empty;
651 set_popdown_strings (lm_output_channel_combo, empty);
652 set_popdown_strings (lm_input_channel_combo, empty);
653 lm_measure_button.set_sensitive (false);
654 lm_use_button.set_sensitive (false);
658 EngineControl::enable_latency_tab ()
660 vector<string> outputs;
661 vector<string> inputs;
663 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
664 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
665 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
667 if (!ARDOUR::AudioEngine::instance()->running()) {
668 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
669 notebook.set_current_page (0);
673 else if (inputs.empty() || outputs.empty()) {
674 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
675 notebook.set_current_page (0);
680 lm_back_button_signal.disconnect();
682 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
685 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
689 set_popdown_strings (lm_output_channel_combo, outputs);
690 lm_output_channel_combo.set_active_text (outputs.front());
691 lm_output_channel_combo.set_sensitive (true);
693 set_popdown_strings (lm_input_channel_combo, inputs);
694 lm_input_channel_combo.set_active_text (inputs.front());
695 lm_input_channel_combo.set_sensitive (true);
697 lm_measure_button.set_sensitive (true);
701 EngineControl::setup_midi_tab_for_backend ()
703 string backend = backend_combo.get_active_text ();
705 Gtkmm2ext::container_clear (midi_vbox);
707 midi_vbox.set_border_width (12);
708 midi_device_table.set_border_width (12);
710 if (backend == "JACK") {
711 setup_midi_tab_for_jack ();
714 midi_vbox.pack_start (midi_device_table, true, true);
715 midi_vbox.pack_start (midi_back_button, false, false);
716 midi_vbox.show_all ();
720 EngineControl::setup_midi_tab_for_jack ()
725 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
727 device->input_latency = a->get_value();
729 device->output_latency = a->get_value();
734 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
735 b->set_active (!b->get_active());
736 device->enabled = b->get_active();
737 refresh_midi_display(device->name);
741 EngineControl::refresh_midi_display (std::string focus)
743 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
747 AttachOptions xopt = AttachOptions (FILL|EXPAND);
750 Gtkmm2ext::container_clear (midi_device_table);
752 midi_device_table.set_spacings (6);
754 l = manage (new Label);
755 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
756 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
757 l->set_alignment (0.5, 0.5);
761 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
762 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
763 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
764 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
766 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
767 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
768 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
769 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
772 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
777 bool enabled = (*p)->enabled;
779 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
780 m->set_name ("midi device");
781 m->set_can_focus (Gtk::CAN_FOCUS);
782 m->add_events (Gdk::BUTTON_RELEASE_MASK);
783 m->set_active (enabled);
784 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
785 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
786 if ((*p)->name == focus) {
790 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
791 s = manage (new Gtk::SpinButton (*a));
792 a->set_value ((*p)->input_latency);
793 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
794 s->set_sensitive (_can_set_midi_latencies && enabled);
795 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
797 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
798 s = manage (new Gtk::SpinButton (*a));
799 a->set_value ((*p)->output_latency);
800 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
801 s->set_sensitive (_can_set_midi_latencies && enabled);
802 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
804 b = manage (new Button (_("Calibrate")));
805 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
806 b->set_sensitive (_can_set_midi_latencies && enabled);
807 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
814 EngineControl::backend_changed ()
816 SignalBlocker blocker (*this, "backend_changed");
817 string backend_name = backend_combo.get_active_text();
818 boost::shared_ptr<ARDOUR::AudioBackend> backend;
820 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
821 /* eh? setting the backend failed... how ? */
822 /* A: stale config contains a backend that does not exist in current build */
826 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
828 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
831 setup_midi_tab_for_backend ();
832 _midi_devices.clear();
834 if (backend->requires_driver_selection()) {
835 if (set_driver_popdown_strings ()) {
836 driver_combo.set_sensitive (true);
841 driver_combo.set_sensitive (false);
842 /* this will change the device text which will cause a call to
843 * device changed which will set up parameters
848 update_midi_options ();
850 connect_disconnect_button.hide();
852 midi_option_changed();
854 started_at_least_once = false;
856 if (!ignore_changes) {
857 maybe_display_saved_state ();
862 EngineControl::update_midi_options ()
864 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
865 vector<string> midi_options = backend->enumerate_midi_options();
867 if (midi_options.size() == 1) {
868 /* only contains the "none" option */
869 midi_option_combo.set_sensitive (false);
872 set_popdown_strings (midi_option_combo, midi_options);
873 midi_option_combo.set_active_text (midi_options.front());
874 midi_option_combo.set_sensitive (true);
876 midi_option_combo.set_sensitive (false);
882 EngineControl::print_channel_count (Gtk::SpinButton* sb)
884 if (ARDOUR::Profile->get_mixbus()) {
888 uint32_t cnt = (uint32_t) sb->get_value();
890 sb->set_text (_("all available channels"));
893 snprintf (buf, sizeof (buf), "%d", cnt);
899 // @return true if there are drivers available
901 EngineControl::set_driver_popdown_strings ()
903 DEBUG_ECONTROL ("set_driver_popdown_strings");
904 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
905 vector<string> drivers = backend->enumerate_drivers();
907 if (drivers.empty ()) {
908 // This is an error...?
912 string current_driver = backend->driver_name ();
914 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
916 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
919 current_driver = drivers.front ();
922 set_popdown_strings (driver_combo, drivers);
924 string_compose ("driver_combo.set_active_text: %1", current_driver));
925 driver_combo.set_active_text (current_driver);
929 // @return true if there are devices available
931 EngineControl::set_device_popdown_strings ()
933 DEBUG_ECONTROL ("set_device_popdown_strings");
934 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
935 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
937 /* NOTE: Ardour currently does not display the "available" field of the
940 * Doing so would require a different GUI widget than the combo
941 * box/popdown that we currently use, since it has no way to list
942 * items that are not selectable. Something more like a popup menu,
943 * which could have unselectable items, would be appropriate.
946 vector<string> available_devices;
948 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
949 available_devices.push_back (i->name);
952 if (available_devices.empty ()) {
956 string current_device = backend->device_name ();
958 // Make sure that backend->device_name () is a valid
959 // device, the backend may not return a valid device if it hasn't
961 if (std::find (available_devices.begin (),
962 available_devices.end (),
963 current_device) == available_devices.end ()) {
965 current_device = available_devices.front ();
968 set_popdown_strings (device_combo, available_devices);
970 string_compose ("set device_combo active text: %1", current_device));
972 device_combo.set_active_text (current_device);
976 // @return true if there are input devices available
978 EngineControl::set_input_device_popdown_strings ()
980 DEBUG_ECONTROL ("set_input_device_popdown_strings");
981 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
982 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
984 vector<string> available_devices;
986 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
987 available_devices.push_back (i->name);
990 if (available_devices.empty()) {
994 string current_device = backend->input_device_name ();
996 // Make sure that backend->input_device_name () is a valid
997 // device, the backend may not return a valid device if it hasn't
999 if (std::find (available_devices.begin (),
1000 available_devices.end (),
1001 current_device) == available_devices.end ()) {
1003 current_device = available_devices.front ();
1006 set_popdown_strings (input_device_combo, available_devices);
1009 string_compose ("set input_device_combo active text: %1", current_device));
1010 input_device_combo.set_active_text (current_device);
1014 // @return true if there are output devices available
1016 EngineControl::set_output_device_popdown_strings ()
1018 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1019 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1020 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1022 vector<string> available_devices;
1024 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1025 available_devices.push_back (i->name);
1028 if (available_devices.empty()) {
1032 string current_device = backend->output_device_name ();
1034 // Make sure that backend->output_device_name () is a valid
1035 // device, the backend may not return a valid device if it hasn't
1037 if (std::find (available_devices.begin (),
1038 available_devices.end (),
1039 current_device) == available_devices.end ()) {
1041 current_device = available_devices.front ();
1044 set_popdown_strings (output_device_combo, available_devices);
1047 string_compose ("set output_device_combo active text: %1", current_device));
1048 output_device_combo.set_active_text (current_device);
1053 EngineControl::list_devices ()
1055 DEBUG_ECONTROL ("list_devices");
1056 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1059 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1061 bool devices_available = false;
1063 if (backend->use_separate_input_and_output_devices ()) {
1064 bool input_devices_available = set_input_device_popdown_strings ();
1065 bool output_devices_available = set_output_device_popdown_strings ();
1066 devices_available = input_devices_available || output_devices_available;
1068 devices_available = set_device_popdown_strings ();
1071 if (devices_available) {
1074 input_latency.set_sensitive (true);
1075 output_latency.set_sensitive (true);
1076 input_channels.set_sensitive (true);
1077 output_channels.set_sensitive (true);
1079 ok_button->set_sensitive (true);
1080 apply_button->set_sensitive (true);
1083 device_combo.clear();
1084 input_device_combo.clear();
1085 output_device_combo.clear();
1086 sample_rate_combo.set_sensitive (false);
1087 buffer_size_combo.set_sensitive (false);
1088 input_latency.set_sensitive (false);
1089 output_latency.set_sensitive (false);
1090 input_channels.set_sensitive (false);
1091 output_channels.set_sensitive (false);
1092 if (_have_control) {
1093 ok_button->set_sensitive (false);
1094 apply_button->set_sensitive (false);
1096 ok_button->set_sensitive (true);
1097 apply_button->set_sensitive (true);
1098 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1099 sample_rate_combo.set_sensitive (true);
1101 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1102 buffer_size_combo.set_sensitive (true);
1110 EngineControl::driver_changed ()
1112 SignalBlocker blocker (*this, "driver_changed");
1113 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1116 backend->set_driver (driver_combo.get_active_text());
1119 if (!ignore_changes) {
1120 maybe_display_saved_state ();
1125 EngineControl::get_sample_rates_for_all_devices ()
1127 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1128 ARDOUR::AudioEngine::instance ()->current_backend ();
1129 vector<float> input_rates;
1130 vector<float> output_rates;
1131 vector<float> all_rates;
1133 if (backend->use_separate_input_and_output_devices ()) {
1134 input_rates = backend->available_sample_rates (get_input_device_name ());
1135 output_rates = backend->available_sample_rates (get_output_device_name ());
1137 std::set_union (input_rates.begin (),
1139 output_rates.begin (),
1140 output_rates.end (),
1141 std::back_inserter (all_rates));
1143 all_rates = backend->available_sample_rates (get_device_name ());
1149 EngineControl::set_samplerate_popdown_strings ()
1151 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1152 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1157 if (_have_control) {
1159 sr = get_sample_rates_for_all_devices ();
1163 sr.push_back (8000.0f);
1164 sr.push_back (16000.0f);
1165 sr.push_back (32000.0f);
1166 sr.push_back (44100.0f);
1167 sr.push_back (48000.0f);
1168 sr.push_back (88200.0f);
1169 sr.push_back (96000.0f);
1170 sr.push_back (192000.0f);
1171 sr.push_back (384000.0f);
1174 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1175 s.push_back (rate_as_string (*x));
1176 if (*x == _desired_sample_rate) {
1182 sample_rate_combo.set_sensitive (true);
1183 set_popdown_strings (sample_rate_combo, s);
1185 if (desired.empty ()) {
1186 float new_active_sr = backend->default_sample_rate ();
1188 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1189 new_active_sr = sr.front ();
1192 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1194 sample_rate_combo.set_active_text (desired);
1198 sample_rate_combo.set_sensitive (false);
1203 EngineControl::get_buffer_sizes_for_all_devices ()
1205 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1206 ARDOUR::AudioEngine::instance ()->current_backend ();
1207 vector<uint32_t> input_sizes;
1208 vector<uint32_t> output_sizes;
1209 vector<uint32_t> all_sizes;
1211 if (backend->use_separate_input_and_output_devices ()) {
1212 input_sizes = backend->available_buffer_sizes (get_input_device_name ());
1213 output_sizes = backend->available_buffer_sizes (get_output_device_name ());
1215 std::set_union (input_sizes.begin (),
1217 output_sizes.begin (),
1218 output_sizes.end (),
1219 std::back_inserter (all_sizes));
1221 all_sizes = backend->available_buffer_sizes (get_device_name ());
1227 EngineControl::set_buffersize_popdown_strings ()
1229 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1230 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1231 vector<uint32_t> bs;
1235 if (_have_control) {
1236 bs = get_buffer_sizes_for_all_devices ();
1237 } else if (backend->can_change_buffer_size_when_running()) {
1245 bs.push_back (1024);
1246 bs.push_back (2048);
1247 bs.push_back (4096);
1248 bs.push_back (8192);
1251 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1252 s.push_back (bufsize_as_string (*x));
1255 if (backend->use_separate_input_and_output_devices ()) {
1256 device_name = get_input_device_name ();
1258 device_name = get_device_name ();
1262 buffer_size_combo.set_sensitive (true);
1263 set_popdown_strings (buffer_size_combo, s);
1264 buffer_size_combo.set_active_text (s.front());
1266 uint32_t period = backend->buffer_size();
1268 period = backend->default_buffer_size(device_name);
1270 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1271 show_buffer_duration ();
1273 buffer_size_combo.set_sensitive (false);
1278 EngineControl::device_changed ()
1280 SignalBlocker blocker (*this, "device_changed");
1281 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1284 string device_name_in;
1285 string device_name_out; // only used if backend support separate I/O devices
1287 if (backend->use_separate_input_and_output_devices()) {
1288 device_name_in = get_input_device_name ();
1289 device_name_out = get_output_device_name ();
1291 device_name_in = get_device_name ();
1294 /* we set the backend-device to query various device related intormation.
1295 * This has the side effect that backend->device_name() will match
1296 * the device_name and 'change_device' will never be true.
1297 * so work around this by setting...
1299 if (backend->use_separate_input_and_output_devices()) {
1300 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1301 queue_device_changed = true;
1304 if (device_name_in != backend->device_name()) {
1305 queue_device_changed = true;
1309 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1310 if (backend->use_separate_input_and_output_devices()) {
1311 backend->set_input_device_name (device_name_in);
1312 backend->set_output_device_name (device_name_out);
1314 backend->set_device_name(device_name_in);
1318 /* don't allow programmatic change to combos to cause a
1319 recursive call to this method.
1321 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1323 /* backends that support separate devices, need to ignore
1324 * the device-name - and use the devies set above
1326 set_samplerate_popdown_strings ();
1327 set_buffersize_popdown_strings ();
1328 /* XXX theoretically need to set min + max channel counts here
1331 manage_control_app_sensitivity ();
1334 /* pick up any saved state for this device */
1336 if (!ignore_changes) {
1337 maybe_display_saved_state ();
1342 EngineControl::input_device_changed ()
1344 DEBUG_ECONTROL ("input_device_changed");
1349 EngineControl::output_device_changed ()
1351 DEBUG_ECONTROL ("output_device_changed");
1356 EngineControl::bufsize_as_string (uint32_t sz)
1358 /* Translators: "samples" is always plural here, so no
1359 need for plural+singular forms.
1362 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1367 EngineControl::sample_rate_changed ()
1369 DEBUG_ECONTROL ("sample_rate_changed");
1370 /* reset the strings for buffer size to show the correct msec value
1371 (reflecting the new sample rate).
1374 show_buffer_duration ();
1379 EngineControl::buffer_size_changed ()
1381 DEBUG_ECONTROL ("buffer_size_changed");
1382 show_buffer_duration ();
1386 EngineControl::show_buffer_duration ()
1388 DEBUG_ECONTROL ("show_buffer_duration");
1389 /* buffer sizes - convert from just samples to samples + msecs for
1390 * the displayed string
1393 string bs_text = buffer_size_combo.get_active_text ();
1394 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1395 uint32_t rate = get_rate();
1397 /* Developers: note the hard-coding of a double buffered model
1398 in the (2 * samples) computation of latency. we always start
1399 the audiobackend in this configuration.
1401 /* note to jack1 developers: ardour also always starts the engine
1402 * in async mode (no jack2 --sync option) which adds an extra cycle
1403 * of latency with jack2 (and *3 would be correct)
1404 * The value can also be wrong if jackd is started externally..
1406 * At the time of writing the ALSA backend always uses double-buffering *2,
1407 * The Dummy backend *1, and who knows what ASIO really does :)
1409 * So just display the period size, that's also what
1410 * ARDOUR_UI::update_sample_rate() does for the status bar.
1411 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1412 * but still, that's the buffer period, not [round-trip] latency)
1415 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1416 buffer_size_duration_label.set_text (buf);
1420 EngineControl::midi_option_changed ()
1422 DEBUG_ECONTROL ("midi_option_changed");
1423 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1426 backend->set_midi_option (get_midi_option());
1428 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1430 //_midi_devices.clear(); // TODO merge with state-saved settings..
1431 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1432 std::vector<MidiDeviceSettings> new_devices;
1434 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1435 MidiDeviceSettings mds = find_midi_device (i->name);
1436 if (i->available && !mds) {
1437 uint32_t input_latency = 0;
1438 uint32_t output_latency = 0;
1439 if (_can_set_midi_latencies) {
1440 input_latency = backend->systemic_midi_input_latency (i->name);
1441 output_latency = backend->systemic_midi_output_latency (i->name);
1443 bool enabled = backend->midi_device_enabled (i->name);
1444 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1445 new_devices.push_back (ptr);
1446 } else if (i->available) {
1447 new_devices.push_back (mds);
1450 _midi_devices = new_devices;
1452 if (_midi_devices.empty()) {
1453 midi_devices_button.set_sensitive (false);
1455 midi_devices_button.set_sensitive (true);
1460 EngineControl::parameter_changed ()
1464 EngineControl::State
1465 EngineControl::get_matching_state (
1466 const string& backend,
1467 const string& driver,
1468 const string& device)
1470 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1471 if ((*i)->backend == backend &&
1472 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1480 EngineControl::State
1481 EngineControl::get_matching_state (
1482 const string& backend,
1483 const string& driver,
1484 const string& input_device,
1485 const string& output_device)
1487 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1488 if ((*i)->backend == backend &&
1489 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1497 EngineControl::State
1498 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1500 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1503 if (backend->use_separate_input_and_output_devices ()) {
1504 return get_matching_state (backend_combo.get_active_text(),
1505 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1506 input_device_combo.get_active_text(),
1507 output_device_combo.get_active_text());
1509 return get_matching_state (backend_combo.get_active_text(),
1510 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1511 device_combo.get_active_text());
1515 return get_matching_state (backend_combo.get_active_text(),
1517 device_combo.get_active_text());
1520 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1521 const EngineControl::State& state2)
1523 if (state1->backend == state2->backend &&
1524 state1->driver == state2->driver &&
1525 state1->device == state2->device &&
1526 state1->input_device == state2->input_device &&
1527 state1->output_device == state2->output_device) {
1533 EngineControl::State
1534 EngineControl::save_state ()
1538 if (!_have_control) {
1539 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1543 state.reset(new StateStruct);
1544 state->backend = get_backend ();
1546 state.reset(new StateStruct);
1547 store_state (state);
1550 for (StateList::iterator i = states.begin(); i != states.end();) {
1551 if (equivalent_states (*i, state)) {
1552 i = states.erase(i);
1558 states.push_back (state);
1564 EngineControl::store_state (State state)
1566 state->backend = get_backend ();
1567 state->driver = get_driver ();
1568 state->device = get_device_name ();
1569 state->input_device = get_input_device_name ();
1570 state->output_device = get_output_device_name ();
1571 state->sample_rate = get_rate ();
1572 state->buffer_size = get_buffer_size ();
1573 state->input_latency = get_input_latency ();
1574 state->output_latency = get_output_latency ();
1575 state->input_channels = get_input_channels ();
1576 state->output_channels = get_output_channels ();
1577 state->midi_option = get_midi_option ();
1578 state->midi_devices = _midi_devices;
1582 EngineControl::maybe_display_saved_state ()
1584 if (!_have_control) {
1588 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1591 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1593 if (!_desired_sample_rate) {
1594 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1596 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1597 /* call this explicitly because we're ignoring changes to
1598 the controls at this point.
1600 show_buffer_duration ();
1601 input_latency.set_value (state->input_latency);
1602 output_latency.set_value (state->output_latency);
1604 if (!state->midi_option.empty()) {
1605 midi_option_combo.set_active_text (state->midi_option);
1606 _midi_devices = state->midi_devices;
1612 EngineControl::get_state ()
1614 LocaleGuard lg (X_("C"));
1616 XMLNode* root = new XMLNode ("AudioMIDISetup");
1619 if (!states.empty()) {
1620 XMLNode* state_nodes = new XMLNode ("EngineStates");
1622 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1624 XMLNode* node = new XMLNode ("State");
1626 node->add_property ("backend", (*i)->backend);
1627 node->add_property ("driver", (*i)->driver);
1628 node->add_property ("device", (*i)->device);
1629 node->add_property ("input-device", (*i)->input_device);
1630 node->add_property ("output-device", (*i)->output_device);
1631 node->add_property ("sample-rate", (*i)->sample_rate);
1632 node->add_property ("buffer-size", (*i)->buffer_size);
1633 node->add_property ("input-latency", (*i)->input_latency);
1634 node->add_property ("output-latency", (*i)->output_latency);
1635 node->add_property ("input-channels", (*i)->input_channels);
1636 node->add_property ("output-channels", (*i)->output_channels);
1637 node->add_property ("active", (*i)->active ? "yes" : "no");
1638 node->add_property ("midi-option", (*i)->midi_option);
1640 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1641 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1642 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1643 midi_device_stuff->add_property (X_("name"), (*p)->name);
1644 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1645 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1646 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1647 midi_devices->add_child_nocopy (*midi_device_stuff);
1649 node->add_child_nocopy (*midi_devices);
1651 state_nodes->add_child_nocopy (*node);
1654 root->add_child_nocopy (*state_nodes);
1661 EngineControl::set_default_state ()
1663 vector<string> backend_names;
1664 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1666 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1667 backend_names.push_back ((*b)->name);
1669 backend_combo.set_active_text (backend_names.front());
1671 // We could set default backends per platform etc here
1677 EngineControl::set_state (const XMLNode& root)
1679 XMLNodeList clist, cclist;
1680 XMLNodeConstIterator citer, cciter;
1682 XMLNode* grandchild;
1683 XMLProperty* prop = NULL;
1685 fprintf (stderr, "EngineControl::set_state\n");
1687 if (root.name() != "AudioMIDISetup") {
1691 clist = root.children();
1695 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1699 if (child->name() != "EngineStates") {
1703 cclist = child->children();
1705 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1706 State state (new StateStruct);
1708 grandchild = *cciter;
1710 if (grandchild->name() != "State") {
1714 if ((prop = grandchild->property ("backend")) == 0) {
1717 state->backend = prop->value ();
1719 if ((prop = grandchild->property ("driver")) == 0) {
1722 state->driver = prop->value ();
1724 if ((prop = grandchild->property ("device")) == 0) {
1727 state->device = prop->value ();
1729 if ((prop = grandchild->property ("input-device")) == 0) {
1732 state->input_device = prop->value ();
1734 if ((prop = grandchild->property ("output-device")) == 0) {
1737 state->output_device = prop->value ();
1739 if ((prop = grandchild->property ("sample-rate")) == 0) {
1742 state->sample_rate = atof (prop->value ());
1744 if ((prop = grandchild->property ("buffer-size")) == 0) {
1747 state->buffer_size = atoi (prop->value ());
1749 if ((prop = grandchild->property ("input-latency")) == 0) {
1752 state->input_latency = atoi (prop->value ());
1754 if ((prop = grandchild->property ("output-latency")) == 0) {
1757 state->output_latency = atoi (prop->value ());
1759 if ((prop = grandchild->property ("input-channels")) == 0) {
1762 state->input_channels = atoi (prop->value ());
1764 if ((prop = grandchild->property ("output-channels")) == 0) {
1767 state->output_channels = atoi (prop->value ());
1769 if ((prop = grandchild->property ("active")) == 0) {
1772 state->active = string_is_affirmative (prop->value ());
1774 if ((prop = grandchild->property ("midi-option")) == 0) {
1777 state->midi_option = prop->value ();
1779 state->midi_devices.clear();
1781 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1782 const XMLNodeList mnc = midinode->children();
1783 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1784 if ((*n)->property (X_("name")) == 0
1785 || (*n)->property (X_("enabled")) == 0
1786 || (*n)->property (X_("input-latency")) == 0
1787 || (*n)->property (X_("output-latency")) == 0
1792 MidiDeviceSettings ptr (new MidiDeviceSetting(
1793 (*n)->property (X_("name"))->value (),
1794 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1795 atoi ((*n)->property (X_("input-latency"))->value ()),
1796 atoi ((*n)->property (X_("output-latency"))->value ())
1798 state->midi_devices.push_back (ptr);
1803 /* remove accumulated duplicates (due to bug in ealier version)
1804 * this can be removed again before release
1806 for (StateList::iterator i = states.begin(); i != states.end();) {
1807 if ((*i)->backend == state->backend &&
1808 (*i)->driver == state->driver &&
1809 (*i)->device == state->device) {
1810 i = states.erase(i);
1817 states.push_back (state);
1821 /* now see if there was an active state and switch the setup to it */
1823 // purge states of backend that are not available in this built
1824 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1825 vector<std::string> backend_names;
1827 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1828 backend_names.push_back((*i)->name);
1830 for (StateList::iterator i = states.begin(); i != states.end();) {
1831 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1832 i = states.erase(i);
1838 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1841 return set_current_state (*i);
1848 EngineControl::set_current_state (const State& state)
1850 DEBUG_ECONTROL ("set_current_state");
1852 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1854 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1855 state->backend, "ardour", ""))) {
1856 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1857 // this shouldn't happen as the invalid backend names should have been
1858 // removed from the list of states.
1862 // now reflect the change in the backend in the GUI so backend_changed will
1863 // do the right thing
1864 backend_combo.set_active_text (state->backend);
1866 if (!state->driver.empty ()) {
1867 if (!backend->requires_driver_selection ()) {
1868 DEBUG_ECONTROL ("Backend should require driver selection");
1869 // A backend has changed from having driver selection to not having
1870 // it or someone has been manually editing a config file and messed
1875 if (backend->set_driver (state->driver) != 0) {
1876 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1877 // Driver names for a backend have changed and the name in the
1878 // config file is now invalid or support for driver is no longer
1879 // included in the backend
1882 // no need to set the driver_combo as backend_changed will use
1883 // backend->driver_name to set the active driver
1886 if (!state->device.empty ()) {
1887 if (backend->set_device_name (state->device) != 0) {
1889 string_compose ("Unable to set device name %1", state->device));
1890 // device is no longer available on the system
1893 // no need to set active device as it will be picked up in
1894 // via backend_changed ()/set_device_popdown_strings
1897 // backend supports separate input/output devices
1898 if (backend->set_input_device_name (state->input_device) != 0) {
1899 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1900 state->input_device));
1901 // input device is no longer available on the system
1905 if (backend->set_output_device_name (state->output_device) != 0) {
1906 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1907 state->input_device));
1908 // output device is no longer available on the system
1911 // no need to set active devices as it will be picked up in via
1912 // backend_changed ()/set_*_device_popdown_strings
1917 // Now restore the state of the rest of the controls
1919 // We don't use a SignalBlocker as set_current_state is currently only
1920 // called from set_state before any signals are connected. If at some point
1921 // a more general named state mechanism is implemented and
1922 // set_current_state is called while signals are connected then a
1923 // SignalBlocker will need to be instantiated before setting these.
1925 device_combo.set_active_text (state->device);
1926 input_device_combo.set_active_text (state->input_device);
1927 output_device_combo.set_active_text (state->output_device);
1928 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1929 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1930 input_latency.set_value (state->input_latency);
1931 output_latency.set_value (state->output_latency);
1932 midi_option_combo.set_active_text (state->midi_option);
1937 EngineControl::push_state_to_backend (bool start)
1939 DEBUG_ECONTROL ("push_state_to_backend");
1940 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1946 /* figure out what is going to change */
1948 bool restart_required = false;
1949 bool was_running = ARDOUR::AudioEngine::instance()->running();
1950 bool change_driver = false;
1951 bool change_device = false;
1952 bool change_rate = false;
1953 bool change_bufsize = false;
1954 bool change_latency = false;
1955 bool change_channels = false;
1956 bool change_midi = false;
1958 uint32_t ochan = get_output_channels ();
1959 uint32_t ichan = get_input_channels ();
1961 if (_have_control) {
1963 if (started_at_least_once) {
1965 /* we can control the backend */
1967 if (backend->requires_driver_selection()) {
1968 if (get_driver() != backend->driver_name()) {
1969 change_driver = true;
1973 if (backend->use_separate_input_and_output_devices()) {
1974 if (get_input_device_name() != backend->input_device_name()) {
1975 change_device = true;
1977 if (get_output_device_name() != backend->output_device_name()) {
1978 change_device = true;
1981 if (get_device_name() != backend->device_name()) {
1982 change_device = true;
1986 if (queue_device_changed) {
1987 change_device = true;
1990 if (get_rate() != backend->sample_rate()) {
1994 if (get_buffer_size() != backend->buffer_size()) {
1995 change_bufsize = true;
1998 if (get_midi_option() != backend->midi_option()) {
2002 /* zero-requested channels means "all available" */
2005 ichan = backend->input_channels();
2009 ochan = backend->output_channels();
2012 if (ichan != backend->input_channels()) {
2013 change_channels = true;
2016 if (ochan != backend->output_channels()) {
2017 change_channels = true;
2020 if (get_input_latency() != backend->systemic_input_latency() ||
2021 get_output_latency() != backend->systemic_output_latency()) {
2022 change_latency = true;
2025 /* backend never started, so we have to force a group
2028 change_device = true;
2029 if (backend->requires_driver_selection()) {
2030 change_driver = true;
2033 change_bufsize = true;
2034 change_channels = true;
2035 change_latency = true;
2041 /* we have no control over the backend, meaning that we can
2042 * only possibly change sample rate and buffer size.
2046 if (get_rate() != backend->sample_rate()) {
2047 change_bufsize = true;
2050 if (get_buffer_size() != backend->buffer_size()) {
2051 change_bufsize = true;
2055 queue_device_changed = false;
2057 if (!_have_control) {
2059 /* We do not have control over the backend, so the best we can
2060 * do is try to change the sample rate and/or bufsize and get
2064 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2068 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2073 backend->set_sample_rate (get_rate());
2076 if (change_bufsize) {
2077 backend->set_buffer_size (get_buffer_size());
2081 if (ARDOUR::AudioEngine::instance()->start ()) {
2082 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2092 /* determine if we need to stop the backend before changing parameters */
2094 if (change_driver || change_device || change_channels || change_latency ||
2095 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2097 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2098 restart_required = true;
2100 restart_required = false;
2105 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2106 /* no changes in any parameters that absolutely require a
2107 * restart, so check those that might be changeable without a
2111 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2112 /* can't do this while running ... */
2113 restart_required = true;
2116 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2117 /* can't do this while running ... */
2118 restart_required = true;
2124 if (restart_required) {
2125 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2132 if (change_driver && backend->set_driver (get_driver())) {
2133 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2136 if (backend->use_separate_input_and_output_devices()) {
2137 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2138 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2141 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2142 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2146 if (change_device && backend->set_device_name (get_device_name())) {
2147 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2151 if (change_rate && backend->set_sample_rate (get_rate())) {
2152 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2155 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2156 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2160 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2161 if (backend->set_input_channels (get_input_channels())) {
2162 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2165 if (backend->set_output_channels (get_output_channels())) {
2166 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2170 if (change_latency) {
2171 if (backend->set_systemic_input_latency (get_input_latency())) {
2172 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2175 if (backend->set_systemic_output_latency (get_output_latency())) {
2176 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2182 backend->set_midi_option (get_midi_option());
2186 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2187 if (_measure_midi) {
2188 if (*p == _measure_midi) {
2189 backend->set_midi_device_enabled ((*p)->name, true);
2191 backend->set_midi_device_enabled ((*p)->name, false);
2195 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2196 if (backend->can_set_systemic_midi_latencies()) {
2197 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2198 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2203 if (start || (was_running && restart_required)) {
2204 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2215 EngineControl::post_push ()
2217 /* get a pointer to the current state object, creating one if
2221 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2224 state = save_state ();
2232 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2233 (*i)->active = false;
2236 /* mark this one active (to be used next time the dialog is
2240 state->active = true;
2242 if (_have_control) { // XXX
2243 manage_control_app_sensitivity ();
2246 /* schedule a redisplay of MIDI ports */
2247 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2252 EngineControl::get_rate () const
2254 float r = atof (sample_rate_combo.get_active_text ());
2255 /* the string may have been translated with an abbreviation for
2256 * thousands, so use a crude heuristic to fix this.
2266 EngineControl::get_buffer_size () const
2268 string txt = buffer_size_combo.get_active_text ();
2271 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2272 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2273 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2281 EngineControl::get_midi_option () const
2283 return midi_option_combo.get_active_text();
2287 EngineControl::get_input_channels() const
2289 if (ARDOUR::Profile->get_mixbus()) {
2290 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2291 if (!backend) return 0;
2292 return backend->input_channels();
2294 return (uint32_t) input_channels_adjustment.get_value();
2298 EngineControl::get_output_channels() const
2300 if (ARDOUR::Profile->get_mixbus()) {
2301 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2302 if (!backend) return 0;
2303 return backend->input_channels();
2305 return (uint32_t) output_channels_adjustment.get_value();
2309 EngineControl::get_input_latency() const
2311 return (uint32_t) input_latency_adjustment.get_value();
2315 EngineControl::get_output_latency() const
2317 return (uint32_t) output_latency_adjustment.get_value();
2321 EngineControl::get_backend () const
2323 return backend_combo.get_active_text ();
2327 EngineControl::get_driver () const
2329 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2330 return driver_combo.get_active_text ();
2337 EngineControl::get_device_name () const
2339 return device_combo.get_active_text ();
2343 EngineControl::get_input_device_name () const
2345 return input_device_combo.get_active_text ();
2349 EngineControl::get_output_device_name () const
2351 return output_device_combo.get_active_text ();
2355 EngineControl::control_app_button_clicked ()
2357 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2363 backend->launch_control_app ();
2367 EngineControl::manage_control_app_sensitivity ()
2369 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2375 string appname = backend->control_app_name();
2377 if (appname.empty()) {
2378 control_app_button.set_sensitive (false);
2380 control_app_button.set_sensitive (true);
2385 EngineControl::set_desired_sample_rate (uint32_t sr)
2387 _desired_sample_rate = sr;
2392 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2394 if (page_num == 0) {
2395 cancel_button->set_sensitive (true);
2396 ok_button->set_sensitive (true);
2397 apply_button->set_sensitive (true);
2398 _measure_midi.reset();
2400 cancel_button->set_sensitive (false);
2401 ok_button->set_sensitive (false);
2402 apply_button->set_sensitive (false);
2405 if (page_num == midi_tab) {
2407 refresh_midi_display ();
2410 if (page_num == latency_tab) {
2413 if (ARDOUR::AudioEngine::instance()->running()) {
2414 // TODO - mark as 'stopped for latency
2415 ARDOUR_UI::instance()->disconnect_from_engine ();
2419 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2421 /* save any existing latency values */
2423 uint32_t il = (uint32_t) input_latency.get_value ();
2424 uint32_t ol = (uint32_t) input_latency.get_value ();
2426 /* reset to zero so that our new test instance
2427 will be clean of any existing latency measures.
2429 NB. this should really be done by the backend
2430 when stated for latency measurement.
2433 input_latency.set_value (0);
2434 output_latency.set_value (0);
2436 push_state_to_backend (false);
2440 input_latency.set_value (il);
2441 output_latency.set_value (ol);
2444 // This should be done in push_state_to_backend()
2445 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2446 disable_latency_tab ();
2449 enable_latency_tab ();
2453 end_latency_detection ();
2454 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2459 /* latency measurement */
2462 EngineControl::check_audio_latency_measurement ()
2464 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2466 if (mtdm->resolve () < 0) {
2467 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2471 if (mtdm->err () > 0.3) {
2477 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2479 if (sample_rate == 0) {
2480 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2481 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2485 int frames_total = mtdm->del();
2486 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2488 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2489 _("Detected roundtrip latency: "),
2490 frames_total, frames_total * 1000.0f/sample_rate,
2491 _("Systemic latency: "),
2492 extra, extra * 1000.0f/sample_rate);
2496 if (mtdm->err () > 0.2) {
2498 strcat (buf, _("(signal detection error)"));
2504 strcat (buf, _("(inverted - bad wiring)"));
2508 lm_results.set_markup (string_compose (results_markup, buf));
2511 have_lm_results = true;
2512 end_latency_detection ();
2513 lm_use_button.set_sensitive (true);
2521 EngineControl::check_midi_latency_measurement ()
2523 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2525 if (!mididm->have_signal () || mididm->latency () == 0) {
2526 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2531 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2533 if (sample_rate == 0) {
2534 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2535 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2539 ARDOUR::framecnt_t frames_total = mididm->latency();
2540 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2541 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2542 _("Detected roundtrip latency: "),
2543 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2544 _("Systemic latency: "),
2545 extra, extra * 1000.0f / sample_rate);
2549 if (!mididm->ok ()) {
2551 strcat (buf, _("(averaging)"));
2555 if (mididm->deviation () > 50.0) {
2557 strcat (buf, _("(too large jitter)"));
2559 } else if (mididm->deviation () > 10.0) {
2561 strcat (buf, _("(large jitter)"));
2565 have_lm_results = true;
2566 end_latency_detection ();
2567 lm_use_button.set_sensitive (true);
2568 lm_results.set_markup (string_compose (results_markup, buf));
2570 } else if (mididm->processed () > 400) {
2571 have_lm_results = false;
2572 end_latency_detection ();
2573 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2577 lm_results.set_markup (string_compose (results_markup, buf));
2583 EngineControl::start_latency_detection ()
2585 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2586 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2588 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2589 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2590 if (_measure_midi) {
2591 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2593 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2595 lm_measure_label.set_text (_("Cancel"));
2596 have_lm_results = false;
2597 lm_use_button.set_sensitive (false);
2598 lm_input_channel_combo.set_sensitive (false);
2599 lm_output_channel_combo.set_sensitive (false);
2605 EngineControl::end_latency_detection ()
2607 latency_timeout.disconnect ();
2608 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2609 lm_measure_label.set_text (_("Measure"));
2610 if (!have_lm_results) {
2611 lm_use_button.set_sensitive (false);
2613 lm_input_channel_combo.set_sensitive (true);
2614 lm_output_channel_combo.set_sensitive (true);
2619 EngineControl::latency_button_clicked ()
2622 start_latency_detection ();
2624 end_latency_detection ();
2629 EngineControl::use_latency_button_clicked ()
2631 if (_measure_midi) {
2632 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2636 ARDOUR::framecnt_t frames_total = mididm->latency();
2637 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2638 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2639 _measure_midi->input_latency = one_way;
2640 _measure_midi->output_latency = one_way;
2641 notebook.set_current_page (midi_tab);
2643 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2649 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2650 one_way = std::max (0., one_way);
2652 input_latency_adjustment.set_value (one_way);
2653 output_latency_adjustment.set_value (one_way);
2655 /* back to settings page */
2656 notebook.set_current_page (0);
2662 EngineControl::on_delete_event (GdkEventAny* ev)
2664 if (notebook.get_current_page() == 2) {
2665 /* currently on latency tab - be sure to clean up */
2666 end_latency_detection ();
2668 return ArdourDialog::on_delete_event (ev);
2672 EngineControl::engine_running ()
2674 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2677 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2678 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2680 buffer_size_combo.set_sensitive (true);
2681 sample_rate_combo.set_sensitive (true);
2683 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2684 connect_disconnect_button.show();
2686 started_at_least_once = true;
2687 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2691 EngineControl::engine_stopped ()
2693 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2696 buffer_size_combo.set_sensitive (false);
2697 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2698 connect_disconnect_button.show();
2700 sample_rate_combo.set_sensitive (true);
2701 buffer_size_combo.set_sensitive (true);
2702 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2706 EngineControl::device_list_changed ()
2708 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2710 midi_option_changed();
2714 EngineControl::connect_disconnect_click()
2716 if (ARDOUR::AudioEngine::instance()->running()) {
2717 ARDOUR_UI::instance()->disconnect_from_engine ();
2719 ARDOUR_UI::instance()->reconnect_to_engine ();
2724 EngineControl::calibrate_audio_latency ()
2726 _measure_midi.reset ();
2727 have_lm_results = false;
2728 lm_use_button.set_sensitive (false);
2729 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2730 notebook.set_current_page (latency_tab);
2734 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2737 have_lm_results = false;
2738 lm_use_button.set_sensitive (false);
2739 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2740 notebook.set_current_page (latency_tab);
2744 EngineControl::configure_midi_devices ()
2746 notebook.set_current_page (midi_tab);