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::get_default_sample_rates ()
1151 vector<float> rates;
1152 rates.push_back (8000.0f);
1153 rates.push_back (16000.0f);
1154 rates.push_back (32000.0f);
1155 rates.push_back (44100.0f);
1156 rates.push_back (48000.0f);
1157 rates.push_back (88200.0f);
1158 rates.push_back (96000.0f);
1159 rates.push_back (192000.0f);
1160 rates.push_back (384000.0f);
1165 EngineControl::set_samplerate_popdown_strings ()
1167 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1168 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1173 if (_have_control) {
1174 sr = get_sample_rates_for_all_devices ();
1175 // currently possible if both devices are set to "None" and the backend
1176 // returns no supported rates for both devices
1178 sr = get_default_sample_rates ();
1181 sr = get_default_sample_rates ();
1184 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1185 s.push_back (rate_as_string (*x));
1186 if (*x == _desired_sample_rate) {
1192 sample_rate_combo.set_sensitive (true);
1193 set_popdown_strings (sample_rate_combo, s);
1195 if (desired.empty ()) {
1196 float new_active_sr = backend->default_sample_rate ();
1198 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1199 new_active_sr = sr.front ();
1202 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1204 sample_rate_combo.set_active_text (desired);
1208 sample_rate_combo.set_sensitive (false);
1213 EngineControl::get_buffer_sizes_for_all_devices ()
1215 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1216 ARDOUR::AudioEngine::instance ()->current_backend ();
1217 vector<uint32_t> input_sizes;
1218 vector<uint32_t> output_sizes;
1219 vector<uint32_t> all_sizes;
1221 if (backend->use_separate_input_and_output_devices ()) {
1222 input_sizes = backend->available_buffer_sizes (get_input_device_name ());
1223 output_sizes = backend->available_buffer_sizes (get_output_device_name ());
1225 std::set_union (input_sizes.begin (),
1227 output_sizes.begin (),
1228 output_sizes.end (),
1229 std::back_inserter (all_sizes));
1231 all_sizes = backend->available_buffer_sizes (get_device_name ());
1237 EngineControl::get_default_buffer_sizes ()
1239 vector<uint32_t> sizes;
1240 sizes.push_back (8);
1241 sizes.push_back (16);
1242 sizes.push_back (32);
1243 sizes.push_back (64);
1244 sizes.push_back (128);
1245 sizes.push_back (256);
1246 sizes.push_back (512);
1247 sizes.push_back (1024);
1248 sizes.push_back (2048);
1249 sizes.push_back (4096);
1250 sizes.push_back (8192);
1255 EngineControl::set_buffersize_popdown_strings ()
1257 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1258 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1259 vector<uint32_t> bs;
1263 if (_have_control) {
1264 bs = get_buffer_sizes_for_all_devices ();
1265 // currently possible if both devices are set to "None" and the backend
1266 // returns no supported sizes for both devices
1268 bs = get_default_buffer_sizes ();
1270 } else if (backend->can_change_buffer_size_when_running()) {
1271 bs = get_default_buffer_sizes ();
1274 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1275 s.push_back (bufsize_as_string (*x));
1278 if (backend->use_separate_input_and_output_devices ()) {
1279 device_name = get_input_device_name ();
1281 device_name = get_device_name ();
1285 buffer_size_combo.set_sensitive (true);
1286 set_popdown_strings (buffer_size_combo, s);
1287 buffer_size_combo.set_active_text (s.front());
1289 uint32_t period = backend->buffer_size();
1291 period = backend->default_buffer_size(device_name);
1293 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1294 show_buffer_duration ();
1296 buffer_size_combo.set_sensitive (false);
1301 EngineControl::device_changed ()
1303 SignalBlocker blocker (*this, "device_changed");
1304 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1307 string device_name_in;
1308 string device_name_out; // only used if backend support separate I/O devices
1310 if (backend->use_separate_input_and_output_devices()) {
1311 device_name_in = get_input_device_name ();
1312 device_name_out = get_output_device_name ();
1314 device_name_in = get_device_name ();
1317 /* we set the backend-device to query various device related intormation.
1318 * This has the side effect that backend->device_name() will match
1319 * the device_name and 'change_device' will never be true.
1320 * so work around this by setting...
1322 if (backend->use_separate_input_and_output_devices()) {
1323 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1324 queue_device_changed = true;
1327 if (device_name_in != backend->device_name()) {
1328 queue_device_changed = true;
1332 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1333 if (backend->use_separate_input_and_output_devices()) {
1334 backend->set_input_device_name (device_name_in);
1335 backend->set_output_device_name (device_name_out);
1337 backend->set_device_name(device_name_in);
1341 /* don't allow programmatic change to combos to cause a
1342 recursive call to this method.
1344 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1346 /* backends that support separate devices, need to ignore
1347 * the device-name - and use the devies set above
1349 set_samplerate_popdown_strings ();
1350 set_buffersize_popdown_strings ();
1351 /* XXX theoretically need to set min + max channel counts here
1354 manage_control_app_sensitivity ();
1357 /* pick up any saved state for this device */
1359 if (!ignore_changes) {
1360 maybe_display_saved_state ();
1365 EngineControl::input_device_changed ()
1367 DEBUG_ECONTROL ("input_device_changed");
1372 EngineControl::output_device_changed ()
1374 DEBUG_ECONTROL ("output_device_changed");
1379 EngineControl::bufsize_as_string (uint32_t sz)
1381 /* Translators: "samples" is always plural here, so no
1382 need for plural+singular forms.
1385 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1390 EngineControl::sample_rate_changed ()
1392 DEBUG_ECONTROL ("sample_rate_changed");
1393 /* reset the strings for buffer size to show the correct msec value
1394 (reflecting the new sample rate).
1397 show_buffer_duration ();
1402 EngineControl::buffer_size_changed ()
1404 DEBUG_ECONTROL ("buffer_size_changed");
1405 show_buffer_duration ();
1409 EngineControl::show_buffer_duration ()
1411 DEBUG_ECONTROL ("show_buffer_duration");
1412 /* buffer sizes - convert from just samples to samples + msecs for
1413 * the displayed string
1416 string bs_text = buffer_size_combo.get_active_text ();
1417 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1418 uint32_t rate = get_rate();
1420 /* Developers: note the hard-coding of a double buffered model
1421 in the (2 * samples) computation of latency. we always start
1422 the audiobackend in this configuration.
1424 /* note to jack1 developers: ardour also always starts the engine
1425 * in async mode (no jack2 --sync option) which adds an extra cycle
1426 * of latency with jack2 (and *3 would be correct)
1427 * The value can also be wrong if jackd is started externally..
1429 * At the time of writing the ALSA backend always uses double-buffering *2,
1430 * The Dummy backend *1, and who knows what ASIO really does :)
1432 * So just display the period size, that's also what
1433 * ARDOUR_UI::update_sample_rate() does for the status bar.
1434 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1435 * but still, that's the buffer period, not [round-trip] latency)
1438 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1439 buffer_size_duration_label.set_text (buf);
1443 EngineControl::midi_option_changed ()
1445 DEBUG_ECONTROL ("midi_option_changed");
1446 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1449 backend->set_midi_option (get_midi_option());
1451 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1453 //_midi_devices.clear(); // TODO merge with state-saved settings..
1454 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1455 std::vector<MidiDeviceSettings> new_devices;
1457 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1458 MidiDeviceSettings mds = find_midi_device (i->name);
1459 if (i->available && !mds) {
1460 uint32_t input_latency = 0;
1461 uint32_t output_latency = 0;
1462 if (_can_set_midi_latencies) {
1463 input_latency = backend->systemic_midi_input_latency (i->name);
1464 output_latency = backend->systemic_midi_output_latency (i->name);
1466 bool enabled = backend->midi_device_enabled (i->name);
1467 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1468 new_devices.push_back (ptr);
1469 } else if (i->available) {
1470 new_devices.push_back (mds);
1473 _midi_devices = new_devices;
1475 if (_midi_devices.empty()) {
1476 midi_devices_button.set_sensitive (false);
1478 midi_devices_button.set_sensitive (true);
1483 EngineControl::parameter_changed ()
1487 EngineControl::State
1488 EngineControl::get_matching_state (
1489 const string& backend,
1490 const string& driver,
1491 const string& device)
1493 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1494 if ((*i)->backend == backend &&
1495 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1503 EngineControl::State
1504 EngineControl::get_matching_state (
1505 const string& backend,
1506 const string& driver,
1507 const string& input_device,
1508 const string& output_device)
1510 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1511 if ((*i)->backend == backend &&
1512 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1520 EngineControl::State
1521 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1523 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1526 if (backend->use_separate_input_and_output_devices ()) {
1527 return get_matching_state (backend_combo.get_active_text(),
1528 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1529 input_device_combo.get_active_text(),
1530 output_device_combo.get_active_text());
1532 return get_matching_state (backend_combo.get_active_text(),
1533 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1534 device_combo.get_active_text());
1538 return get_matching_state (backend_combo.get_active_text(),
1540 device_combo.get_active_text());
1543 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1544 const EngineControl::State& state2)
1546 if (state1->backend == state2->backend &&
1547 state1->driver == state2->driver &&
1548 state1->device == state2->device &&
1549 state1->input_device == state2->input_device &&
1550 state1->output_device == state2->output_device) {
1556 EngineControl::State
1557 EngineControl::save_state ()
1561 if (!_have_control) {
1562 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1566 state.reset(new StateStruct);
1567 state->backend = get_backend ();
1569 state.reset(new StateStruct);
1570 store_state (state);
1573 for (StateList::iterator i = states.begin(); i != states.end();) {
1574 if (equivalent_states (*i, state)) {
1575 i = states.erase(i);
1581 states.push_back (state);
1587 EngineControl::store_state (State state)
1589 state->backend = get_backend ();
1590 state->driver = get_driver ();
1591 state->device = get_device_name ();
1592 state->input_device = get_input_device_name ();
1593 state->output_device = get_output_device_name ();
1594 state->sample_rate = get_rate ();
1595 state->buffer_size = get_buffer_size ();
1596 state->input_latency = get_input_latency ();
1597 state->output_latency = get_output_latency ();
1598 state->input_channels = get_input_channels ();
1599 state->output_channels = get_output_channels ();
1600 state->midi_option = get_midi_option ();
1601 state->midi_devices = _midi_devices;
1605 EngineControl::maybe_display_saved_state ()
1607 if (!_have_control) {
1611 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1614 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1616 if (!_desired_sample_rate) {
1617 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1619 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1620 /* call this explicitly because we're ignoring changes to
1621 the controls at this point.
1623 show_buffer_duration ();
1624 input_latency.set_value (state->input_latency);
1625 output_latency.set_value (state->output_latency);
1627 if (!state->midi_option.empty()) {
1628 midi_option_combo.set_active_text (state->midi_option);
1629 _midi_devices = state->midi_devices;
1635 EngineControl::get_state ()
1637 LocaleGuard lg (X_("C"));
1639 XMLNode* root = new XMLNode ("AudioMIDISetup");
1642 if (!states.empty()) {
1643 XMLNode* state_nodes = new XMLNode ("EngineStates");
1645 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1647 XMLNode* node = new XMLNode ("State");
1649 node->add_property ("backend", (*i)->backend);
1650 node->add_property ("driver", (*i)->driver);
1651 node->add_property ("device", (*i)->device);
1652 node->add_property ("input-device", (*i)->input_device);
1653 node->add_property ("output-device", (*i)->output_device);
1654 node->add_property ("sample-rate", (*i)->sample_rate);
1655 node->add_property ("buffer-size", (*i)->buffer_size);
1656 node->add_property ("input-latency", (*i)->input_latency);
1657 node->add_property ("output-latency", (*i)->output_latency);
1658 node->add_property ("input-channels", (*i)->input_channels);
1659 node->add_property ("output-channels", (*i)->output_channels);
1660 node->add_property ("active", (*i)->active ? "yes" : "no");
1661 node->add_property ("midi-option", (*i)->midi_option);
1663 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1664 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1665 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1666 midi_device_stuff->add_property (X_("name"), (*p)->name);
1667 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1668 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1669 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1670 midi_devices->add_child_nocopy (*midi_device_stuff);
1672 node->add_child_nocopy (*midi_devices);
1674 state_nodes->add_child_nocopy (*node);
1677 root->add_child_nocopy (*state_nodes);
1684 EngineControl::set_default_state ()
1686 vector<string> backend_names;
1687 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1689 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1690 backend_names.push_back ((*b)->name);
1692 backend_combo.set_active_text (backend_names.front());
1694 // We could set default backends per platform etc here
1700 EngineControl::set_state (const XMLNode& root)
1702 XMLNodeList clist, cclist;
1703 XMLNodeConstIterator citer, cciter;
1705 XMLNode* grandchild;
1706 XMLProperty* prop = NULL;
1708 fprintf (stderr, "EngineControl::set_state\n");
1710 if (root.name() != "AudioMIDISetup") {
1714 clist = root.children();
1718 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1722 if (child->name() != "EngineStates") {
1726 cclist = child->children();
1728 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1729 State state (new StateStruct);
1731 grandchild = *cciter;
1733 if (grandchild->name() != "State") {
1737 if ((prop = grandchild->property ("backend")) == 0) {
1740 state->backend = prop->value ();
1742 if ((prop = grandchild->property ("driver")) == 0) {
1745 state->driver = prop->value ();
1747 if ((prop = grandchild->property ("device")) == 0) {
1750 state->device = prop->value ();
1752 if ((prop = grandchild->property ("input-device")) == 0) {
1755 state->input_device = prop->value ();
1757 if ((prop = grandchild->property ("output-device")) == 0) {
1760 state->output_device = prop->value ();
1762 if ((prop = grandchild->property ("sample-rate")) == 0) {
1765 state->sample_rate = atof (prop->value ());
1767 if ((prop = grandchild->property ("buffer-size")) == 0) {
1770 state->buffer_size = atoi (prop->value ());
1772 if ((prop = grandchild->property ("input-latency")) == 0) {
1775 state->input_latency = atoi (prop->value ());
1777 if ((prop = grandchild->property ("output-latency")) == 0) {
1780 state->output_latency = atoi (prop->value ());
1782 if ((prop = grandchild->property ("input-channels")) == 0) {
1785 state->input_channels = atoi (prop->value ());
1787 if ((prop = grandchild->property ("output-channels")) == 0) {
1790 state->output_channels = atoi (prop->value ());
1792 if ((prop = grandchild->property ("active")) == 0) {
1795 state->active = string_is_affirmative (prop->value ());
1797 if ((prop = grandchild->property ("midi-option")) == 0) {
1800 state->midi_option = prop->value ();
1802 state->midi_devices.clear();
1804 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1805 const XMLNodeList mnc = midinode->children();
1806 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1807 if ((*n)->property (X_("name")) == 0
1808 || (*n)->property (X_("enabled")) == 0
1809 || (*n)->property (X_("input-latency")) == 0
1810 || (*n)->property (X_("output-latency")) == 0
1815 MidiDeviceSettings ptr (new MidiDeviceSetting(
1816 (*n)->property (X_("name"))->value (),
1817 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1818 atoi ((*n)->property (X_("input-latency"))->value ()),
1819 atoi ((*n)->property (X_("output-latency"))->value ())
1821 state->midi_devices.push_back (ptr);
1826 /* remove accumulated duplicates (due to bug in ealier version)
1827 * this can be removed again before release
1829 for (StateList::iterator i = states.begin(); i != states.end();) {
1830 if ((*i)->backend == state->backend &&
1831 (*i)->driver == state->driver &&
1832 (*i)->device == state->device) {
1833 i = states.erase(i);
1840 states.push_back (state);
1844 /* now see if there was an active state and switch the setup to it */
1846 // purge states of backend that are not available in this built
1847 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1848 vector<std::string> backend_names;
1850 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1851 backend_names.push_back((*i)->name);
1853 for (StateList::iterator i = states.begin(); i != states.end();) {
1854 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1855 i = states.erase(i);
1861 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1864 return set_current_state (*i);
1871 EngineControl::set_current_state (const State& state)
1873 DEBUG_ECONTROL ("set_current_state");
1875 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1877 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1878 state->backend, "ardour", ""))) {
1879 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1880 // this shouldn't happen as the invalid backend names should have been
1881 // removed from the list of states.
1885 // now reflect the change in the backend in the GUI so backend_changed will
1886 // do the right thing
1887 backend_combo.set_active_text (state->backend);
1889 if (!state->driver.empty ()) {
1890 if (!backend->requires_driver_selection ()) {
1891 DEBUG_ECONTROL ("Backend should require driver selection");
1892 // A backend has changed from having driver selection to not having
1893 // it or someone has been manually editing a config file and messed
1898 if (backend->set_driver (state->driver) != 0) {
1899 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1900 // Driver names for a backend have changed and the name in the
1901 // config file is now invalid or support for driver is no longer
1902 // included in the backend
1905 // no need to set the driver_combo as backend_changed will use
1906 // backend->driver_name to set the active driver
1909 if (!state->device.empty ()) {
1910 if (backend->set_device_name (state->device) != 0) {
1912 string_compose ("Unable to set device name %1", state->device));
1913 // device is no longer available on the system
1916 // no need to set active device as it will be picked up in
1917 // via backend_changed ()/set_device_popdown_strings
1920 // backend supports separate input/output devices
1921 if (backend->set_input_device_name (state->input_device) != 0) {
1922 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1923 state->input_device));
1924 // input device is no longer available on the system
1928 if (backend->set_output_device_name (state->output_device) != 0) {
1929 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1930 state->input_device));
1931 // output device is no longer available on the system
1934 // no need to set active devices as it will be picked up in via
1935 // backend_changed ()/set_*_device_popdown_strings
1940 // Now restore the state of the rest of the controls
1942 // We don't use a SignalBlocker as set_current_state is currently only
1943 // called from set_state before any signals are connected. If at some point
1944 // a more general named state mechanism is implemented and
1945 // set_current_state is called while signals are connected then a
1946 // SignalBlocker will need to be instantiated before setting these.
1948 device_combo.set_active_text (state->device);
1949 input_device_combo.set_active_text (state->input_device);
1950 output_device_combo.set_active_text (state->output_device);
1951 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1952 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1953 input_latency.set_value (state->input_latency);
1954 output_latency.set_value (state->output_latency);
1955 midi_option_combo.set_active_text (state->midi_option);
1960 EngineControl::push_state_to_backend (bool start)
1962 DEBUG_ECONTROL ("push_state_to_backend");
1963 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1969 /* figure out what is going to change */
1971 bool restart_required = false;
1972 bool was_running = ARDOUR::AudioEngine::instance()->running();
1973 bool change_driver = false;
1974 bool change_device = false;
1975 bool change_rate = false;
1976 bool change_bufsize = false;
1977 bool change_latency = false;
1978 bool change_channels = false;
1979 bool change_midi = false;
1981 uint32_t ochan = get_output_channels ();
1982 uint32_t ichan = get_input_channels ();
1984 if (_have_control) {
1986 if (started_at_least_once) {
1988 /* we can control the backend */
1990 if (backend->requires_driver_selection()) {
1991 if (get_driver() != backend->driver_name()) {
1992 change_driver = true;
1996 if (backend->use_separate_input_and_output_devices()) {
1997 if (get_input_device_name() != backend->input_device_name()) {
1998 change_device = true;
2000 if (get_output_device_name() != backend->output_device_name()) {
2001 change_device = true;
2004 if (get_device_name() != backend->device_name()) {
2005 change_device = true;
2009 if (queue_device_changed) {
2010 change_device = true;
2013 if (get_rate() != backend->sample_rate()) {
2017 if (get_buffer_size() != backend->buffer_size()) {
2018 change_bufsize = true;
2021 if (get_midi_option() != backend->midi_option()) {
2025 /* zero-requested channels means "all available" */
2028 ichan = backend->input_channels();
2032 ochan = backend->output_channels();
2035 if (ichan != backend->input_channels()) {
2036 change_channels = true;
2039 if (ochan != backend->output_channels()) {
2040 change_channels = true;
2043 if (get_input_latency() != backend->systemic_input_latency() ||
2044 get_output_latency() != backend->systemic_output_latency()) {
2045 change_latency = true;
2048 /* backend never started, so we have to force a group
2051 change_device = true;
2052 if (backend->requires_driver_selection()) {
2053 change_driver = true;
2056 change_bufsize = true;
2057 change_channels = true;
2058 change_latency = true;
2064 /* we have no control over the backend, meaning that we can
2065 * only possibly change sample rate and buffer size.
2069 if (get_rate() != backend->sample_rate()) {
2070 change_bufsize = true;
2073 if (get_buffer_size() != backend->buffer_size()) {
2074 change_bufsize = true;
2078 queue_device_changed = false;
2080 if (!_have_control) {
2082 /* We do not have control over the backend, so the best we can
2083 * do is try to change the sample rate and/or bufsize and get
2087 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2091 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2096 backend->set_sample_rate (get_rate());
2099 if (change_bufsize) {
2100 backend->set_buffer_size (get_buffer_size());
2104 if (ARDOUR::AudioEngine::instance()->start ()) {
2105 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2115 /* determine if we need to stop the backend before changing parameters */
2117 if (change_driver || change_device || change_channels || change_latency ||
2118 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2120 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2121 restart_required = true;
2123 restart_required = false;
2128 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2129 /* no changes in any parameters that absolutely require a
2130 * restart, so check those that might be changeable without a
2134 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2135 /* can't do this while running ... */
2136 restart_required = true;
2139 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2140 /* can't do this while running ... */
2141 restart_required = true;
2147 if (restart_required) {
2148 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2155 if (change_driver && backend->set_driver (get_driver())) {
2156 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2159 if (backend->use_separate_input_and_output_devices()) {
2160 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2161 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2164 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2165 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2169 if (change_device && backend->set_device_name (get_device_name())) {
2170 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2174 if (change_rate && backend->set_sample_rate (get_rate())) {
2175 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2178 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2179 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2183 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2184 if (backend->set_input_channels (get_input_channels())) {
2185 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2188 if (backend->set_output_channels (get_output_channels())) {
2189 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2193 if (change_latency) {
2194 if (backend->set_systemic_input_latency (get_input_latency())) {
2195 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2198 if (backend->set_systemic_output_latency (get_output_latency())) {
2199 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2205 backend->set_midi_option (get_midi_option());
2209 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2210 if (_measure_midi) {
2211 if (*p == _measure_midi) {
2212 backend->set_midi_device_enabled ((*p)->name, true);
2214 backend->set_midi_device_enabled ((*p)->name, false);
2218 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2219 if (backend->can_set_systemic_midi_latencies()) {
2220 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2221 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2226 if (start || (was_running && restart_required)) {
2227 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2238 EngineControl::post_push ()
2240 /* get a pointer to the current state object, creating one if
2244 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2247 state = save_state ();
2255 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2256 (*i)->active = false;
2259 /* mark this one active (to be used next time the dialog is
2263 state->active = true;
2265 if (_have_control) { // XXX
2266 manage_control_app_sensitivity ();
2269 /* schedule a redisplay of MIDI ports */
2270 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2275 EngineControl::get_rate () const
2277 float r = atof (sample_rate_combo.get_active_text ());
2278 /* the string may have been translated with an abbreviation for
2279 * thousands, so use a crude heuristic to fix this.
2289 EngineControl::get_buffer_size () const
2291 string txt = buffer_size_combo.get_active_text ();
2294 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2295 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2296 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2304 EngineControl::get_midi_option () const
2306 return midi_option_combo.get_active_text();
2310 EngineControl::get_input_channels() const
2312 if (ARDOUR::Profile->get_mixbus()) {
2313 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2314 if (!backend) return 0;
2315 return backend->input_channels();
2317 return (uint32_t) input_channels_adjustment.get_value();
2321 EngineControl::get_output_channels() const
2323 if (ARDOUR::Profile->get_mixbus()) {
2324 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2325 if (!backend) return 0;
2326 return backend->input_channels();
2328 return (uint32_t) output_channels_adjustment.get_value();
2332 EngineControl::get_input_latency() const
2334 return (uint32_t) input_latency_adjustment.get_value();
2338 EngineControl::get_output_latency() const
2340 return (uint32_t) output_latency_adjustment.get_value();
2344 EngineControl::get_backend () const
2346 return backend_combo.get_active_text ();
2350 EngineControl::get_driver () const
2352 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2353 return driver_combo.get_active_text ();
2360 EngineControl::get_device_name () const
2362 return device_combo.get_active_text ();
2366 EngineControl::get_input_device_name () const
2368 return input_device_combo.get_active_text ();
2372 EngineControl::get_output_device_name () const
2374 return output_device_combo.get_active_text ();
2378 EngineControl::control_app_button_clicked ()
2380 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2386 backend->launch_control_app ();
2390 EngineControl::manage_control_app_sensitivity ()
2392 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2398 string appname = backend->control_app_name();
2400 if (appname.empty()) {
2401 control_app_button.set_sensitive (false);
2403 control_app_button.set_sensitive (true);
2408 EngineControl::set_desired_sample_rate (uint32_t sr)
2410 _desired_sample_rate = sr;
2415 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2417 if (page_num == 0) {
2418 cancel_button->set_sensitive (true);
2419 ok_button->set_sensitive (true);
2420 apply_button->set_sensitive (true);
2421 _measure_midi.reset();
2423 cancel_button->set_sensitive (false);
2424 ok_button->set_sensitive (false);
2425 apply_button->set_sensitive (false);
2428 if (page_num == midi_tab) {
2430 refresh_midi_display ();
2433 if (page_num == latency_tab) {
2436 if (ARDOUR::AudioEngine::instance()->running()) {
2437 // TODO - mark as 'stopped for latency
2438 ARDOUR_UI::instance()->disconnect_from_engine ();
2442 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2444 /* save any existing latency values */
2446 uint32_t il = (uint32_t) input_latency.get_value ();
2447 uint32_t ol = (uint32_t) input_latency.get_value ();
2449 /* reset to zero so that our new test instance
2450 will be clean of any existing latency measures.
2452 NB. this should really be done by the backend
2453 when stated for latency measurement.
2456 input_latency.set_value (0);
2457 output_latency.set_value (0);
2459 push_state_to_backend (false);
2463 input_latency.set_value (il);
2464 output_latency.set_value (ol);
2467 // This should be done in push_state_to_backend()
2468 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2469 disable_latency_tab ();
2472 enable_latency_tab ();
2476 end_latency_detection ();
2477 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2482 /* latency measurement */
2485 EngineControl::check_audio_latency_measurement ()
2487 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2489 if (mtdm->resolve () < 0) {
2490 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2494 if (mtdm->err () > 0.3) {
2500 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2502 if (sample_rate == 0) {
2503 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2504 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2508 int frames_total = mtdm->del();
2509 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2511 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2512 _("Detected roundtrip latency: "),
2513 frames_total, frames_total * 1000.0f/sample_rate,
2514 _("Systemic latency: "),
2515 extra, extra * 1000.0f/sample_rate);
2519 if (mtdm->err () > 0.2) {
2521 strcat (buf, _("(signal detection error)"));
2527 strcat (buf, _("(inverted - bad wiring)"));
2531 lm_results.set_markup (string_compose (results_markup, buf));
2534 have_lm_results = true;
2535 end_latency_detection ();
2536 lm_use_button.set_sensitive (true);
2544 EngineControl::check_midi_latency_measurement ()
2546 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2548 if (!mididm->have_signal () || mididm->latency () == 0) {
2549 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2554 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2556 if (sample_rate == 0) {
2557 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2558 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2562 ARDOUR::framecnt_t frames_total = mididm->latency();
2563 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2564 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2565 _("Detected roundtrip latency: "),
2566 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2567 _("Systemic latency: "),
2568 extra, extra * 1000.0f / sample_rate);
2572 if (!mididm->ok ()) {
2574 strcat (buf, _("(averaging)"));
2578 if (mididm->deviation () > 50.0) {
2580 strcat (buf, _("(too large jitter)"));
2582 } else if (mididm->deviation () > 10.0) {
2584 strcat (buf, _("(large jitter)"));
2588 have_lm_results = true;
2589 end_latency_detection ();
2590 lm_use_button.set_sensitive (true);
2591 lm_results.set_markup (string_compose (results_markup, buf));
2593 } else if (mididm->processed () > 400) {
2594 have_lm_results = false;
2595 end_latency_detection ();
2596 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2600 lm_results.set_markup (string_compose (results_markup, buf));
2606 EngineControl::start_latency_detection ()
2608 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2609 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2611 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2612 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2613 if (_measure_midi) {
2614 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2616 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2618 lm_measure_label.set_text (_("Cancel"));
2619 have_lm_results = false;
2620 lm_use_button.set_sensitive (false);
2621 lm_input_channel_combo.set_sensitive (false);
2622 lm_output_channel_combo.set_sensitive (false);
2628 EngineControl::end_latency_detection ()
2630 latency_timeout.disconnect ();
2631 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2632 lm_measure_label.set_text (_("Measure"));
2633 if (!have_lm_results) {
2634 lm_use_button.set_sensitive (false);
2636 lm_input_channel_combo.set_sensitive (true);
2637 lm_output_channel_combo.set_sensitive (true);
2642 EngineControl::latency_button_clicked ()
2645 start_latency_detection ();
2647 end_latency_detection ();
2652 EngineControl::use_latency_button_clicked ()
2654 if (_measure_midi) {
2655 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2659 ARDOUR::framecnt_t frames_total = mididm->latency();
2660 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2661 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2662 _measure_midi->input_latency = one_way;
2663 _measure_midi->output_latency = one_way;
2664 notebook.set_current_page (midi_tab);
2666 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2672 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2673 one_way = std::max (0., one_way);
2675 input_latency_adjustment.set_value (one_way);
2676 output_latency_adjustment.set_value (one_way);
2678 /* back to settings page */
2679 notebook.set_current_page (0);
2685 EngineControl::on_delete_event (GdkEventAny* ev)
2687 if (notebook.get_current_page() == 2) {
2688 /* currently on latency tab - be sure to clean up */
2689 end_latency_detection ();
2691 return ArdourDialog::on_delete_event (ev);
2695 EngineControl::engine_running ()
2697 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2700 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2701 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2703 buffer_size_combo.set_sensitive (true);
2704 sample_rate_combo.set_sensitive (true);
2706 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2707 connect_disconnect_button.show();
2709 started_at_least_once = true;
2710 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2714 EngineControl::engine_stopped ()
2716 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2719 buffer_size_combo.set_sensitive (false);
2720 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2721 connect_disconnect_button.show();
2723 sample_rate_combo.set_sensitive (true);
2724 buffer_size_combo.set_sensitive (true);
2725 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2729 EngineControl::device_list_changed ()
2731 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2733 midi_option_changed();
2737 EngineControl::connect_disconnect_click()
2739 if (ARDOUR::AudioEngine::instance()->running()) {
2740 ARDOUR_UI::instance()->disconnect_from_engine ();
2742 ARDOUR_UI::instance()->reconnect_to_engine ();
2747 EngineControl::calibrate_audio_latency ()
2749 _measure_midi.reset ();
2750 have_lm_results = false;
2751 lm_use_button.set_sensitive (false);
2752 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2753 notebook.set_current_page (latency_tab);
2757 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2760 have_lm_results = false;
2761 lm_use_button.set_sensitive (false);
2762 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2763 notebook.set_current_page (latency_tab);
2767 EngineControl::configure_midi_devices ()
2769 notebook.set_current_page (midi_tab);