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::update_sensitivity ()
722 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
724 ok_button->set_sensitive (false);
725 apply_button->set_sensitive (false);
730 size_t devices_available = 0;
732 if (backend->use_separate_input_and_output_devices ()) {
733 devices_available += get_popdown_string_count (input_device_combo);
734 devices_available += get_popdown_string_count (output_device_combo);
736 devices_available += get_popdown_string_count (device_combo);
739 if (devices_available == 0) {
741 input_latency.set_sensitive (false);
742 output_latency.set_sensitive (false);
743 input_channels.set_sensitive (false);
744 output_channels.set_sensitive (false);
746 input_latency.set_sensitive (true);
747 output_latency.set_sensitive (true);
748 input_channels.set_sensitive (true);
749 output_channels.set_sensitive (true);
752 if (get_popdown_string_count (buffer_size_combo) > 0) {
753 if (!ARDOUR::AudioEngine::instance()->running()) {
754 buffer_size_combo.set_sensitive (valid);
755 } else if (backend->can_change_sample_rate_when_running()) {
756 buffer_size_combo.set_sensitive (valid || !_have_control);
760 * Currently there is no way to manually stop the
761 * engine in order to re-configure it.
762 * This needs to remain sensitive for now.
764 buffer_size_combo.set_sensitive (true);
766 buffer_size_combo.set_sensitive (false);
770 buffer_size_combo.set_sensitive (false);
774 if (get_popdown_string_count (sample_rate_combo) > 0) {
775 if (!ARDOUR::AudioEngine::instance()->running()) {
776 sample_rate_combo.set_sensitive (true);
778 sample_rate_combo.set_sensitive (false);
781 sample_rate_combo.set_sensitive (false);
785 if (valid || !_have_control) {
786 ok_button->set_sensitive (true);
787 apply_button->set_sensitive (true);
789 ok_button->set_sensitive (false);
790 apply_button->set_sensitive (false);
795 EngineControl::setup_midi_tab_for_jack ()
800 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
802 device->input_latency = a->get_value();
804 device->output_latency = a->get_value();
809 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
810 b->set_active (!b->get_active());
811 device->enabled = b->get_active();
812 refresh_midi_display(device->name);
816 EngineControl::refresh_midi_display (std::string focus)
818 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
822 AttachOptions xopt = AttachOptions (FILL|EXPAND);
825 Gtkmm2ext::container_clear (midi_device_table);
827 midi_device_table.set_spacings (6);
829 l = manage (new Label);
830 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
831 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
832 l->set_alignment (0.5, 0.5);
836 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
837 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
838 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
839 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
841 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
842 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
843 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
844 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
847 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
852 bool enabled = (*p)->enabled;
854 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
855 m->set_name ("midi device");
856 m->set_can_focus (Gtk::CAN_FOCUS);
857 m->add_events (Gdk::BUTTON_RELEASE_MASK);
858 m->set_active (enabled);
859 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
860 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
861 if ((*p)->name == focus) {
865 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
866 s = manage (new Gtk::SpinButton (*a));
867 a->set_value ((*p)->input_latency);
868 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
869 s->set_sensitive (_can_set_midi_latencies && enabled);
870 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
872 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
873 s = manage (new Gtk::SpinButton (*a));
874 a->set_value ((*p)->output_latency);
875 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
876 s->set_sensitive (_can_set_midi_latencies && enabled);
877 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
879 b = manage (new Button (_("Calibrate")));
880 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
881 b->set_sensitive (_can_set_midi_latencies && enabled);
882 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
889 EngineControl::backend_changed ()
891 SignalBlocker blocker (*this, "backend_changed");
892 string backend_name = backend_combo.get_active_text();
893 boost::shared_ptr<ARDOUR::AudioBackend> backend;
895 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
896 /* eh? setting the backend failed... how ? */
897 /* A: stale config contains a backend that does not exist in current build */
901 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
903 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
906 setup_midi_tab_for_backend ();
907 _midi_devices.clear();
909 if (backend->requires_driver_selection()) {
910 if (set_driver_popdown_strings ()) {
911 driver_combo.set_sensitive (true);
916 driver_combo.set_sensitive (false);
917 /* this will change the device text which will cause a call to
918 * device changed which will set up parameters
923 update_midi_options ();
925 connect_disconnect_button.hide();
927 midi_option_changed();
929 started_at_least_once = false;
931 /* changing the backend implies stopping the engine
932 * ARDOUR::AudioEngine() may or may not emit this signal
933 * depending on previous engine state
935 engine_stopped (); // set "active/inactive"
937 if (!ignore_changes) {
938 maybe_display_saved_state ();
943 EngineControl::update_midi_options ()
945 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
946 vector<string> midi_options = backend->enumerate_midi_options();
948 if (midi_options.size() == 1) {
949 /* only contains the "none" option */
950 midi_option_combo.set_sensitive (false);
953 set_popdown_strings (midi_option_combo, midi_options);
954 midi_option_combo.set_active_text (midi_options.front());
955 midi_option_combo.set_sensitive (true);
957 midi_option_combo.set_sensitive (false);
963 EngineControl::print_channel_count (Gtk::SpinButton* sb)
965 if (ARDOUR::Profile->get_mixbus()) {
969 uint32_t cnt = (uint32_t) sb->get_value();
971 sb->set_text (_("all available channels"));
974 snprintf (buf, sizeof (buf), "%d", cnt);
980 // @return true if there are drivers available
982 EngineControl::set_driver_popdown_strings ()
984 DEBUG_ECONTROL ("set_driver_popdown_strings");
985 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
986 vector<string> drivers = backend->enumerate_drivers();
988 if (drivers.empty ()) {
989 // This is an error...?
993 string current_driver = backend->driver_name ();
995 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
997 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1000 current_driver = drivers.front ();
1003 set_popdown_strings (driver_combo, drivers);
1005 string_compose ("driver_combo.set_active_text: %1", current_driver));
1006 driver_combo.set_active_text (current_driver);
1010 // @return true if there are devices available
1012 EngineControl::set_device_popdown_strings ()
1014 DEBUG_ECONTROL ("set_device_popdown_strings");
1015 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1016 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1018 /* NOTE: Ardour currently does not display the "available" field of the
1021 * Doing so would require a different GUI widget than the combo
1022 * box/popdown that we currently use, since it has no way to list
1023 * items that are not selectable. Something more like a popup menu,
1024 * which could have unselectable items, would be appropriate.
1027 vector<string> available_devices;
1029 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1030 available_devices.push_back (i->name);
1033 if (available_devices.empty ()) {
1037 string current_device = backend->device_name ();
1039 // Make sure that backend->device_name () is a valid
1040 // device, the backend may not return a valid device if it hasn't
1042 if (std::find (available_devices.begin (),
1043 available_devices.end (),
1044 current_device) == available_devices.end ()) {
1046 current_device = available_devices.front ();
1049 set_popdown_strings (device_combo, available_devices);
1051 string_compose ("set device_combo active text: %1", current_device));
1053 device_combo.set_active_text (current_device);
1057 // @return true if there are input devices available
1059 EngineControl::set_input_device_popdown_strings ()
1061 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1062 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1063 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1065 vector<string> available_devices;
1067 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1068 available_devices.push_back (i->name);
1071 if (available_devices.empty()) {
1075 string current_device = backend->input_device_name ();
1077 // Make sure that backend->input_device_name () is a valid
1078 // device, the backend may not return a valid device if it hasn't
1080 if (std::find (available_devices.begin (),
1081 available_devices.end (),
1082 current_device) == available_devices.end ()) {
1084 current_device = available_devices.front ();
1087 set_popdown_strings (input_device_combo, available_devices);
1090 string_compose ("set input_device_combo active text: %1", current_device));
1091 input_device_combo.set_active_text (current_device);
1095 // @return true if there are output devices available
1097 EngineControl::set_output_device_popdown_strings ()
1099 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1100 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1101 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1103 vector<string> available_devices;
1105 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1106 available_devices.push_back (i->name);
1109 if (available_devices.empty()) {
1113 string current_device = backend->output_device_name ();
1115 // Make sure that backend->output_device_name () is a valid
1116 // device, the backend may not return a valid device if it hasn't
1118 if (std::find (available_devices.begin (),
1119 available_devices.end (),
1120 current_device) == available_devices.end ()) {
1122 current_device = available_devices.front ();
1125 set_popdown_strings (output_device_combo, available_devices);
1128 string_compose ("set output_device_combo active text: %1", current_device));
1129 output_device_combo.set_active_text (current_device);
1134 EngineControl::list_devices ()
1136 DEBUG_ECONTROL ("list_devices");
1137 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1140 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1142 bool devices_available = false;
1144 if (backend->use_separate_input_and_output_devices ()) {
1145 bool input_devices_available = set_input_device_popdown_strings ();
1146 bool output_devices_available = set_output_device_popdown_strings ();
1147 devices_available = input_devices_available || output_devices_available;
1149 devices_available = set_device_popdown_strings ();
1152 if (devices_available) {
1155 device_combo.clear();
1156 input_device_combo.clear();
1157 output_device_combo.clear();
1159 update_sensitivity ();
1163 EngineControl::driver_changed ()
1165 SignalBlocker blocker (*this, "driver_changed");
1166 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1169 backend->set_driver (driver_combo.get_active_text());
1172 if (!ignore_changes) {
1173 maybe_display_saved_state ();
1178 EngineControl::get_sample_rates_for_all_devices ()
1180 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1181 ARDOUR::AudioEngine::instance ()->current_backend ();
1182 vector<float> all_rates;
1184 if (backend->use_separate_input_and_output_devices ()) {
1185 all_rates = backend->available_sample_rates (get_input_device_name (), get_output_device_name ());
1187 all_rates = backend->available_sample_rates (get_device_name ());
1193 EngineControl::get_default_sample_rates ()
1195 vector<float> rates;
1196 rates.push_back (8000.0f);
1197 rates.push_back (16000.0f);
1198 rates.push_back (32000.0f);
1199 rates.push_back (44100.0f);
1200 rates.push_back (48000.0f);
1201 rates.push_back (88200.0f);
1202 rates.push_back (96000.0f);
1203 rates.push_back (192000.0f);
1204 rates.push_back (384000.0f);
1209 EngineControl::set_samplerate_popdown_strings ()
1211 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1212 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1217 if (_have_control) {
1218 sr = get_sample_rates_for_all_devices ();
1220 sr = get_default_sample_rates ();
1223 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1224 s.push_back (rate_as_string (*x));
1225 if (*x == _desired_sample_rate) {
1230 set_popdown_strings (sample_rate_combo, s);
1233 if (desired.empty ()) {
1234 float new_active_sr = backend->default_sample_rate ();
1236 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1237 new_active_sr = sr.front ();
1240 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1242 sample_rate_combo.set_active_text (desired);
1246 update_sensitivity ();
1250 EngineControl::get_buffer_sizes_for_all_devices ()
1252 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1253 ARDOUR::AudioEngine::instance ()->current_backend ();
1254 vector<uint32_t> all_sizes;
1256 if (backend->use_separate_input_and_output_devices ()) {
1257 all_sizes = backend->available_buffer_sizes (get_input_device_name (), get_output_device_name ());
1259 all_sizes = backend->available_buffer_sizes (get_device_name ());
1265 EngineControl::get_default_buffer_sizes ()
1267 vector<uint32_t> sizes;
1268 sizes.push_back (8);
1269 sizes.push_back (16);
1270 sizes.push_back (32);
1271 sizes.push_back (64);
1272 sizes.push_back (128);
1273 sizes.push_back (256);
1274 sizes.push_back (512);
1275 sizes.push_back (1024);
1276 sizes.push_back (2048);
1277 sizes.push_back (4096);
1278 sizes.push_back (8192);
1283 EngineControl::set_buffersize_popdown_strings ()
1285 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1286 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1287 vector<uint32_t> bs;
1290 if (_have_control) {
1291 bs = get_buffer_sizes_for_all_devices ();
1292 } else if (backend->can_change_buffer_size_when_running()) {
1293 bs = get_default_buffer_sizes ();
1296 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1297 s.push_back (bufsize_as_string (*x));
1300 set_popdown_strings (buffer_size_combo, s);
1303 buffer_size_combo.set_active_text (s.front());
1305 uint32_t period = backend->buffer_size();
1306 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1307 period = backend->default_buffer_size (get_input_device_name ());
1309 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1310 period = backend->default_buffer_size (get_output_device_name ());
1312 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1313 period = backend->default_buffer_size (get_device_name ());
1316 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1317 show_buffer_duration ();
1319 update_sensitivity ();
1323 EngineControl::device_changed ()
1325 SignalBlocker blocker (*this, "device_changed");
1326 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1329 string device_name_in;
1330 string device_name_out; // only used if backend support separate I/O devices
1332 if (backend->use_separate_input_and_output_devices()) {
1333 device_name_in = get_input_device_name ();
1334 device_name_out = get_output_device_name ();
1336 device_name_in = get_device_name ();
1339 /* we set the backend-device to query various device related intormation.
1340 * This has the side effect that backend->device_name() will match
1341 * the device_name and 'change_device' will never be true.
1342 * so work around this by setting...
1344 if (backend->use_separate_input_and_output_devices()) {
1345 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1346 queue_device_changed = true;
1349 if (device_name_in != backend->device_name()) {
1350 queue_device_changed = true;
1354 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1355 if (backend->use_separate_input_and_output_devices()) {
1356 backend->set_input_device_name (device_name_in);
1357 backend->set_output_device_name (device_name_out);
1359 backend->set_device_name(device_name_in);
1363 /* don't allow programmatic change to combos to cause a
1364 recursive call to this method.
1366 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1368 set_samplerate_popdown_strings ();
1369 set_buffersize_popdown_strings ();
1371 /* TODO set min + max channel counts here */
1373 manage_control_app_sensitivity ();
1376 /* pick up any saved state for this device */
1378 if (!ignore_changes) {
1379 maybe_display_saved_state ();
1384 EngineControl::input_device_changed ()
1386 DEBUG_ECONTROL ("input_device_changed");
1391 EngineControl::output_device_changed ()
1393 DEBUG_ECONTROL ("output_device_changed");
1398 EngineControl::bufsize_as_string (uint32_t sz)
1400 /* Translators: "samples" is always plural here, so no
1401 need for plural+singular forms.
1404 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1409 EngineControl::sample_rate_changed ()
1411 DEBUG_ECONTROL ("sample_rate_changed");
1412 /* reset the strings for buffer size to show the correct msec value
1413 (reflecting the new sample rate).
1416 show_buffer_duration ();
1421 EngineControl::buffer_size_changed ()
1423 DEBUG_ECONTROL ("buffer_size_changed");
1424 show_buffer_duration ();
1428 EngineControl::show_buffer_duration ()
1430 DEBUG_ECONTROL ("show_buffer_duration");
1431 /* buffer sizes - convert from just samples to samples + msecs for
1432 * the displayed string
1435 string bs_text = buffer_size_combo.get_active_text ();
1436 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1437 uint32_t rate = get_rate();
1439 /* Developers: note the hard-coding of a double buffered model
1440 in the (2 * samples) computation of latency. we always start
1441 the audiobackend in this configuration.
1443 /* note to jack1 developers: ardour also always starts the engine
1444 * in async mode (no jack2 --sync option) which adds an extra cycle
1445 * of latency with jack2 (and *3 would be correct)
1446 * The value can also be wrong if jackd is started externally..
1448 * At the time of writing the ALSA backend always uses double-buffering *2,
1449 * The Dummy backend *1, and who knows what ASIO really does :)
1451 * So just display the period size, that's also what
1452 * ARDOUR_UI::update_sample_rate() does for the status bar.
1453 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1454 * but still, that's the buffer period, not [round-trip] latency)
1457 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1458 buffer_size_duration_label.set_text (buf);
1462 EngineControl::midi_option_changed ()
1464 DEBUG_ECONTROL ("midi_option_changed");
1465 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1468 backend->set_midi_option (get_midi_option());
1470 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1472 //_midi_devices.clear(); // TODO merge with state-saved settings..
1473 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1474 std::vector<MidiDeviceSettings> new_devices;
1476 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1477 MidiDeviceSettings mds = find_midi_device (i->name);
1478 if (i->available && !mds) {
1479 uint32_t input_latency = 0;
1480 uint32_t output_latency = 0;
1481 if (_can_set_midi_latencies) {
1482 input_latency = backend->systemic_midi_input_latency (i->name);
1483 output_latency = backend->systemic_midi_output_latency (i->name);
1485 bool enabled = backend->midi_device_enabled (i->name);
1486 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1487 new_devices.push_back (ptr);
1488 } else if (i->available) {
1489 new_devices.push_back (mds);
1492 _midi_devices = new_devices;
1494 if (_midi_devices.empty()) {
1495 midi_devices_button.set_sensitive (false);
1497 midi_devices_button.set_sensitive (true);
1502 EngineControl::parameter_changed ()
1506 EngineControl::State
1507 EngineControl::get_matching_state (
1508 const string& backend,
1509 const string& driver,
1510 const string& device)
1512 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1513 if ((*i)->backend == backend &&
1514 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1522 EngineControl::State
1523 EngineControl::get_matching_state (
1524 const string& backend,
1525 const string& driver,
1526 const string& input_device,
1527 const string& output_device)
1529 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1530 if ((*i)->backend == backend &&
1531 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1539 EngineControl::State
1540 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1542 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1545 if (backend->use_separate_input_and_output_devices ()) {
1546 return get_matching_state (backend_combo.get_active_text(),
1547 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1548 input_device_combo.get_active_text(),
1549 output_device_combo.get_active_text());
1551 return get_matching_state (backend_combo.get_active_text(),
1552 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1553 device_combo.get_active_text());
1557 return get_matching_state (backend_combo.get_active_text(),
1559 device_combo.get_active_text());
1562 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1563 const EngineControl::State& state2)
1565 if (state1->backend == state2->backend &&
1566 state1->driver == state2->driver &&
1567 state1->device == state2->device &&
1568 state1->input_device == state2->input_device &&
1569 state1->output_device == state2->output_device) {
1575 EngineControl::State
1576 EngineControl::save_state ()
1580 if (!_have_control) {
1581 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1585 state.reset(new StateStruct);
1586 state->backend = get_backend ();
1588 state.reset(new StateStruct);
1589 store_state (state);
1592 for (StateList::iterator i = states.begin(); i != states.end();) {
1593 if (equivalent_states (*i, state)) {
1594 i = states.erase(i);
1600 states.push_back (state);
1606 EngineControl::store_state (State state)
1608 state->backend = get_backend ();
1609 state->driver = get_driver ();
1610 state->device = get_device_name ();
1611 state->input_device = get_input_device_name ();
1612 state->output_device = get_output_device_name ();
1613 state->sample_rate = get_rate ();
1614 state->buffer_size = get_buffer_size ();
1615 state->input_latency = get_input_latency ();
1616 state->output_latency = get_output_latency ();
1617 state->input_channels = get_input_channels ();
1618 state->output_channels = get_output_channels ();
1619 state->midi_option = get_midi_option ();
1620 state->midi_devices = _midi_devices;
1624 EngineControl::maybe_display_saved_state ()
1626 if (!_have_control) {
1630 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1633 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1635 if (!_desired_sample_rate) {
1636 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1638 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1639 /* call this explicitly because we're ignoring changes to
1640 the controls at this point.
1642 show_buffer_duration ();
1643 input_latency.set_value (state->input_latency);
1644 output_latency.set_value (state->output_latency);
1646 if (!state->midi_option.empty()) {
1647 midi_option_combo.set_active_text (state->midi_option);
1648 _midi_devices = state->midi_devices;
1654 EngineControl::get_state ()
1656 LocaleGuard lg (X_("C"));
1658 XMLNode* root = new XMLNode ("AudioMIDISetup");
1661 if (!states.empty()) {
1662 XMLNode* state_nodes = new XMLNode ("EngineStates");
1664 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1666 XMLNode* node = new XMLNode ("State");
1668 node->add_property ("backend", (*i)->backend);
1669 node->add_property ("driver", (*i)->driver);
1670 node->add_property ("device", (*i)->device);
1671 node->add_property ("input-device", (*i)->input_device);
1672 node->add_property ("output-device", (*i)->output_device);
1673 node->add_property ("sample-rate", (*i)->sample_rate);
1674 node->add_property ("buffer-size", (*i)->buffer_size);
1675 node->add_property ("input-latency", (*i)->input_latency);
1676 node->add_property ("output-latency", (*i)->output_latency);
1677 node->add_property ("input-channels", (*i)->input_channels);
1678 node->add_property ("output-channels", (*i)->output_channels);
1679 node->add_property ("active", (*i)->active ? "yes" : "no");
1680 node->add_property ("midi-option", (*i)->midi_option);
1682 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1683 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1684 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1685 midi_device_stuff->add_property (X_("name"), (*p)->name);
1686 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1687 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1688 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1689 midi_devices->add_child_nocopy (*midi_device_stuff);
1691 node->add_child_nocopy (*midi_devices);
1693 state_nodes->add_child_nocopy (*node);
1696 root->add_child_nocopy (*state_nodes);
1703 EngineControl::set_default_state ()
1705 vector<string> backend_names;
1706 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1708 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1709 backend_names.push_back ((*b)->name);
1711 backend_combo.set_active_text (backend_names.front());
1713 // We could set default backends per platform etc here
1719 EngineControl::set_state (const XMLNode& root)
1721 XMLNodeList clist, cclist;
1722 XMLNodeConstIterator citer, cciter;
1724 XMLNode* grandchild;
1725 XMLProperty* prop = NULL;
1727 fprintf (stderr, "EngineControl::set_state\n");
1729 if (root.name() != "AudioMIDISetup") {
1733 clist = root.children();
1737 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1741 if (child->name() != "EngineStates") {
1745 cclist = child->children();
1747 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1748 State state (new StateStruct);
1750 grandchild = *cciter;
1752 if (grandchild->name() != "State") {
1756 if ((prop = grandchild->property ("backend")) == 0) {
1759 state->backend = prop->value ();
1761 if ((prop = grandchild->property ("driver")) == 0) {
1764 state->driver = prop->value ();
1766 if ((prop = grandchild->property ("device")) == 0) {
1769 state->device = prop->value ();
1771 if ((prop = grandchild->property ("input-device")) == 0) {
1774 state->input_device = prop->value ();
1776 if ((prop = grandchild->property ("output-device")) == 0) {
1779 state->output_device = prop->value ();
1781 if ((prop = grandchild->property ("sample-rate")) == 0) {
1784 state->sample_rate = atof (prop->value ());
1786 if ((prop = grandchild->property ("buffer-size")) == 0) {
1789 state->buffer_size = atoi (prop->value ());
1791 if ((prop = grandchild->property ("input-latency")) == 0) {
1794 state->input_latency = atoi (prop->value ());
1796 if ((prop = grandchild->property ("output-latency")) == 0) {
1799 state->output_latency = atoi (prop->value ());
1801 if ((prop = grandchild->property ("input-channels")) == 0) {
1804 state->input_channels = atoi (prop->value ());
1806 if ((prop = grandchild->property ("output-channels")) == 0) {
1809 state->output_channels = atoi (prop->value ());
1811 if ((prop = grandchild->property ("active")) == 0) {
1814 state->active = string_is_affirmative (prop->value ());
1816 if ((prop = grandchild->property ("midi-option")) == 0) {
1819 state->midi_option = prop->value ();
1821 state->midi_devices.clear();
1823 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1824 const XMLNodeList mnc = midinode->children();
1825 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1826 if ((*n)->property (X_("name")) == 0
1827 || (*n)->property (X_("enabled")) == 0
1828 || (*n)->property (X_("input-latency")) == 0
1829 || (*n)->property (X_("output-latency")) == 0
1834 MidiDeviceSettings ptr (new MidiDeviceSetting(
1835 (*n)->property (X_("name"))->value (),
1836 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1837 atoi ((*n)->property (X_("input-latency"))->value ()),
1838 atoi ((*n)->property (X_("output-latency"))->value ())
1840 state->midi_devices.push_back (ptr);
1845 /* remove accumulated duplicates (due to bug in ealier version)
1846 * this can be removed again before release
1848 for (StateList::iterator i = states.begin(); i != states.end();) {
1849 if ((*i)->backend == state->backend &&
1850 (*i)->driver == state->driver &&
1851 (*i)->device == state->device) {
1852 i = states.erase(i);
1859 states.push_back (state);
1863 /* now see if there was an active state and switch the setup to it */
1865 // purge states of backend that are not available in this built
1866 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1867 vector<std::string> backend_names;
1869 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1870 backend_names.push_back((*i)->name);
1872 for (StateList::iterator i = states.begin(); i != states.end();) {
1873 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1874 i = states.erase(i);
1880 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1883 return set_current_state (*i);
1890 EngineControl::set_current_state (const State& state)
1892 DEBUG_ECONTROL ("set_current_state");
1894 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1896 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1897 state->backend, "ardour", ""))) {
1898 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1899 // this shouldn't happen as the invalid backend names should have been
1900 // removed from the list of states.
1904 // now reflect the change in the backend in the GUI so backend_changed will
1905 // do the right thing
1906 backend_combo.set_active_text (state->backend);
1908 if (!state->driver.empty ()) {
1909 if (!backend->requires_driver_selection ()) {
1910 DEBUG_ECONTROL ("Backend should require driver selection");
1911 // A backend has changed from having driver selection to not having
1912 // it or someone has been manually editing a config file and messed
1917 if (backend->set_driver (state->driver) != 0) {
1918 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1919 // Driver names for a backend have changed and the name in the
1920 // config file is now invalid or support for driver is no longer
1921 // included in the backend
1924 // no need to set the driver_combo as backend_changed will use
1925 // backend->driver_name to set the active driver
1928 if (!state->device.empty ()) {
1929 if (backend->set_device_name (state->device) != 0) {
1931 string_compose ("Unable to set device name %1", state->device));
1932 // device is no longer available on the system
1935 // no need to set active device as it will be picked up in
1936 // via backend_changed ()/set_device_popdown_strings
1939 // backend supports separate input/output devices
1940 if (backend->set_input_device_name (state->input_device) != 0) {
1941 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
1942 state->input_device));
1943 // input device is no longer available on the system
1947 if (backend->set_output_device_name (state->output_device) != 0) {
1948 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
1949 state->input_device));
1950 // output device is no longer available on the system
1953 // no need to set active devices as it will be picked up in via
1954 // backend_changed ()/set_*_device_popdown_strings
1959 // Now restore the state of the rest of the controls
1961 // We don't use a SignalBlocker as set_current_state is currently only
1962 // called from set_state before any signals are connected. If at some point
1963 // a more general named state mechanism is implemented and
1964 // set_current_state is called while signals are connected then a
1965 // SignalBlocker will need to be instantiated before setting these.
1967 device_combo.set_active_text (state->device);
1968 input_device_combo.set_active_text (state->input_device);
1969 output_device_combo.set_active_text (state->output_device);
1970 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1971 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1972 input_latency.set_value (state->input_latency);
1973 output_latency.set_value (state->output_latency);
1974 midi_option_combo.set_active_text (state->midi_option);
1979 EngineControl::push_state_to_backend (bool start)
1981 DEBUG_ECONTROL ("push_state_to_backend");
1982 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1988 /* figure out what is going to change */
1990 bool restart_required = false;
1991 bool was_running = ARDOUR::AudioEngine::instance()->running();
1992 bool change_driver = false;
1993 bool change_device = false;
1994 bool change_rate = false;
1995 bool change_bufsize = false;
1996 bool change_latency = false;
1997 bool change_channels = false;
1998 bool change_midi = false;
2000 uint32_t ochan = get_output_channels ();
2001 uint32_t ichan = get_input_channels ();
2003 if (_have_control) {
2005 if (started_at_least_once) {
2007 /* we can control the backend */
2009 if (backend->requires_driver_selection()) {
2010 if (get_driver() != backend->driver_name()) {
2011 change_driver = true;
2015 if (backend->use_separate_input_and_output_devices()) {
2016 if (get_input_device_name() != backend->input_device_name()) {
2017 change_device = true;
2019 if (get_output_device_name() != backend->output_device_name()) {
2020 change_device = true;
2023 if (get_device_name() != backend->device_name()) {
2024 change_device = true;
2028 if (queue_device_changed) {
2029 change_device = true;
2032 if (get_rate() != backend->sample_rate()) {
2036 if (get_buffer_size() != backend->buffer_size()) {
2037 change_bufsize = true;
2040 if (get_midi_option() != backend->midi_option()) {
2044 /* zero-requested channels means "all available" */
2047 ichan = backend->input_channels();
2051 ochan = backend->output_channels();
2054 if (ichan != backend->input_channels()) {
2055 change_channels = true;
2058 if (ochan != backend->output_channels()) {
2059 change_channels = true;
2062 if (get_input_latency() != backend->systemic_input_latency() ||
2063 get_output_latency() != backend->systemic_output_latency()) {
2064 change_latency = true;
2067 /* backend never started, so we have to force a group
2070 change_device = true;
2071 if (backend->requires_driver_selection()) {
2072 change_driver = true;
2075 change_bufsize = true;
2076 change_channels = true;
2077 change_latency = true;
2083 /* we have no control over the backend, meaning that we can
2084 * only possibly change sample rate and buffer size.
2088 if (get_rate() != backend->sample_rate()) {
2089 change_bufsize = true;
2092 if (get_buffer_size() != backend->buffer_size()) {
2093 change_bufsize = true;
2097 queue_device_changed = false;
2099 if (!_have_control) {
2101 /* We do not have control over the backend, so the best we can
2102 * do is try to change the sample rate and/or bufsize and get
2106 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2110 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2115 backend->set_sample_rate (get_rate());
2118 if (change_bufsize) {
2119 backend->set_buffer_size (get_buffer_size());
2123 if (ARDOUR::AudioEngine::instance()->start ()) {
2124 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2134 /* determine if we need to stop the backend before changing parameters */
2136 if (change_driver || change_device || change_channels || change_latency ||
2137 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2139 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2140 restart_required = true;
2142 restart_required = false;
2147 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2148 /* no changes in any parameters that absolutely require a
2149 * restart, so check those that might be changeable without a
2153 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2154 /* can't do this while running ... */
2155 restart_required = true;
2158 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2159 /* can't do this while running ... */
2160 restart_required = true;
2166 if (restart_required) {
2167 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2174 if (change_driver && backend->set_driver (get_driver())) {
2175 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2178 if (backend->use_separate_input_and_output_devices()) {
2179 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2180 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2183 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2184 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2188 if (change_device && backend->set_device_name (get_device_name())) {
2189 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2193 if (change_rate && backend->set_sample_rate (get_rate())) {
2194 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2197 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2198 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2202 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2203 if (backend->set_input_channels (get_input_channels())) {
2204 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2207 if (backend->set_output_channels (get_output_channels())) {
2208 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2212 if (change_latency) {
2213 if (backend->set_systemic_input_latency (get_input_latency())) {
2214 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2217 if (backend->set_systemic_output_latency (get_output_latency())) {
2218 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2224 backend->set_midi_option (get_midi_option());
2228 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2229 if (_measure_midi) {
2230 if (*p == _measure_midi) {
2231 backend->set_midi_device_enabled ((*p)->name, true);
2233 backend->set_midi_device_enabled ((*p)->name, false);
2237 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2238 if (backend->can_set_systemic_midi_latencies()) {
2239 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2240 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2245 if (start || (was_running && restart_required)) {
2246 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2257 EngineControl::post_push ()
2259 /* get a pointer to the current state object, creating one if
2263 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2266 state = save_state ();
2274 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2275 (*i)->active = false;
2278 /* mark this one active (to be used next time the dialog is
2282 state->active = true;
2284 if (_have_control) { // XXX
2285 manage_control_app_sensitivity ();
2288 /* schedule a redisplay of MIDI ports */
2289 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2294 EngineControl::get_rate () const
2296 float r = atof (sample_rate_combo.get_active_text ());
2297 /* the string may have been translated with an abbreviation for
2298 * thousands, so use a crude heuristic to fix this.
2308 EngineControl::get_buffer_size () const
2310 string txt = buffer_size_combo.get_active_text ();
2313 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2314 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2315 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2323 EngineControl::get_midi_option () const
2325 return midi_option_combo.get_active_text();
2329 EngineControl::get_input_channels() const
2331 if (ARDOUR::Profile->get_mixbus()) {
2332 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2333 if (!backend) return 0;
2334 return backend->input_channels();
2336 return (uint32_t) input_channels_adjustment.get_value();
2340 EngineControl::get_output_channels() const
2342 if (ARDOUR::Profile->get_mixbus()) {
2343 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2344 if (!backend) return 0;
2345 return backend->input_channels();
2347 return (uint32_t) output_channels_adjustment.get_value();
2351 EngineControl::get_input_latency() const
2353 return (uint32_t) input_latency_adjustment.get_value();
2357 EngineControl::get_output_latency() const
2359 return (uint32_t) output_latency_adjustment.get_value();
2363 EngineControl::get_backend () const
2365 return backend_combo.get_active_text ();
2369 EngineControl::get_driver () const
2371 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2372 return driver_combo.get_active_text ();
2379 EngineControl::get_device_name () const
2381 return device_combo.get_active_text ();
2385 EngineControl::get_input_device_name () const
2387 return input_device_combo.get_active_text ();
2391 EngineControl::get_output_device_name () const
2393 return output_device_combo.get_active_text ();
2397 EngineControl::control_app_button_clicked ()
2399 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2405 backend->launch_control_app ();
2409 EngineControl::manage_control_app_sensitivity ()
2411 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2417 string appname = backend->control_app_name();
2419 if (appname.empty()) {
2420 control_app_button.set_sensitive (false);
2422 control_app_button.set_sensitive (true);
2427 EngineControl::set_desired_sample_rate (uint32_t sr)
2429 _desired_sample_rate = sr;
2434 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2436 if (page_num == 0) {
2437 cancel_button->set_sensitive (true);
2438 _measure_midi.reset();
2439 update_sensitivity ();
2441 cancel_button->set_sensitive (false);
2442 ok_button->set_sensitive (false);
2443 apply_button->set_sensitive (false);
2446 if (page_num == midi_tab) {
2448 refresh_midi_display ();
2451 if (page_num == latency_tab) {
2454 if (ARDOUR::AudioEngine::instance()->running()) {
2455 // TODO - mark as 'stopped for latency
2456 ARDOUR_UI::instance()->disconnect_from_engine ();
2460 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2462 /* save any existing latency values */
2464 uint32_t il = (uint32_t) input_latency.get_value ();
2465 uint32_t ol = (uint32_t) input_latency.get_value ();
2467 /* reset to zero so that our new test instance
2468 will be clean of any existing latency measures.
2470 NB. this should really be done by the backend
2471 when stated for latency measurement.
2474 input_latency.set_value (0);
2475 output_latency.set_value (0);
2477 push_state_to_backend (false);
2481 input_latency.set_value (il);
2482 output_latency.set_value (ol);
2485 // This should be done in push_state_to_backend()
2486 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2487 disable_latency_tab ();
2490 enable_latency_tab ();
2494 end_latency_detection ();
2495 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2500 /* latency measurement */
2503 EngineControl::check_audio_latency_measurement ()
2505 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2507 if (mtdm->resolve () < 0) {
2508 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2512 if (mtdm->err () > 0.3) {
2518 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2520 if (sample_rate == 0) {
2521 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2522 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2526 int frames_total = mtdm->del();
2527 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2529 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2530 _("Detected roundtrip latency: "),
2531 frames_total, frames_total * 1000.0f/sample_rate,
2532 _("Systemic latency: "),
2533 extra, extra * 1000.0f/sample_rate);
2537 if (mtdm->err () > 0.2) {
2539 strcat (buf, _("(signal detection error)"));
2545 strcat (buf, _("(inverted - bad wiring)"));
2549 lm_results.set_markup (string_compose (results_markup, buf));
2552 have_lm_results = true;
2553 end_latency_detection ();
2554 lm_use_button.set_sensitive (true);
2562 EngineControl::check_midi_latency_measurement ()
2564 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2566 if (!mididm->have_signal () || mididm->latency () == 0) {
2567 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2572 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2574 if (sample_rate == 0) {
2575 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2576 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2580 ARDOUR::framecnt_t frames_total = mididm->latency();
2581 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2582 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2583 _("Detected roundtrip latency: "),
2584 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2585 _("Systemic latency: "),
2586 extra, extra * 1000.0f / sample_rate);
2590 if (!mididm->ok ()) {
2592 strcat (buf, _("(averaging)"));
2596 if (mididm->deviation () > 50.0) {
2598 strcat (buf, _("(too large jitter)"));
2600 } else if (mididm->deviation () > 10.0) {
2602 strcat (buf, _("(large jitter)"));
2606 have_lm_results = true;
2607 end_latency_detection ();
2608 lm_use_button.set_sensitive (true);
2609 lm_results.set_markup (string_compose (results_markup, buf));
2611 } else if (mididm->processed () > 400) {
2612 have_lm_results = false;
2613 end_latency_detection ();
2614 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2618 lm_results.set_markup (string_compose (results_markup, buf));
2624 EngineControl::start_latency_detection ()
2626 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2627 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2629 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2630 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2631 if (_measure_midi) {
2632 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2634 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2636 lm_measure_label.set_text (_("Cancel"));
2637 have_lm_results = false;
2638 lm_use_button.set_sensitive (false);
2639 lm_input_channel_combo.set_sensitive (false);
2640 lm_output_channel_combo.set_sensitive (false);
2646 EngineControl::end_latency_detection ()
2648 latency_timeout.disconnect ();
2649 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2650 lm_measure_label.set_text (_("Measure"));
2651 if (!have_lm_results) {
2652 lm_use_button.set_sensitive (false);
2654 lm_input_channel_combo.set_sensitive (true);
2655 lm_output_channel_combo.set_sensitive (true);
2660 EngineControl::latency_button_clicked ()
2663 start_latency_detection ();
2665 end_latency_detection ();
2670 EngineControl::use_latency_button_clicked ()
2672 if (_measure_midi) {
2673 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2677 ARDOUR::framecnt_t frames_total = mididm->latency();
2678 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2679 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2680 _measure_midi->input_latency = one_way;
2681 _measure_midi->output_latency = one_way;
2682 notebook.set_current_page (midi_tab);
2684 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2690 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2691 one_way = std::max (0., one_way);
2693 input_latency_adjustment.set_value (one_way);
2694 output_latency_adjustment.set_value (one_way);
2696 /* back to settings page */
2697 notebook.set_current_page (0);
2703 EngineControl::on_delete_event (GdkEventAny* ev)
2705 if (notebook.get_current_page() == 2) {
2706 /* currently on latency tab - be sure to clean up */
2707 end_latency_detection ();
2709 return ArdourDialog::on_delete_event (ev);
2713 EngineControl::engine_running ()
2715 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2718 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2719 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2721 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2722 connect_disconnect_button.show();
2724 started_at_least_once = true;
2725 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2726 update_sensitivity();
2730 EngineControl::engine_stopped ()
2732 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2735 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2736 connect_disconnect_button.show();
2738 if (ARDOUR::Profile->get_mixbus()) {
2739 engine_status.set_markup("");
2741 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2744 update_sensitivity();
2748 EngineControl::device_list_changed ()
2750 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2752 midi_option_changed();
2756 EngineControl::connect_disconnect_click()
2758 if (ARDOUR::AudioEngine::instance()->running()) {
2759 ARDOUR_UI::instance()->disconnect_from_engine ();
2761 ARDOUR_UI::instance()->reconnect_to_engine ();
2766 EngineControl::calibrate_audio_latency ()
2768 _measure_midi.reset ();
2769 have_lm_results = false;
2770 lm_use_button.set_sensitive (false);
2771 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2772 notebook.set_current_page (latency_tab);
2776 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2779 have_lm_results = false;
2780 lm_use_button.set_sensitive (false);
2781 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2782 notebook.set_current_page (latency_tab);
2786 EngineControl::configure_midi_devices ()
2788 notebook.set_current_page (midi_tab);