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.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
55 #include "ui_config.h"
56 #include "public_editor.h"
63 using namespace Gtkmm2ext;
66 using namespace ARDOUR_UI_UTILS;
68 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
70 static const unsigned int midi_tab = 2;
71 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
73 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
75 EngineControl::EngineControl ()
76 : ArdourDialog (_("Audio/MIDI Setup"))
79 , input_latency_adjustment (0, 0, 99999, 1)
80 , input_latency (input_latency_adjustment)
81 , output_latency_adjustment (0, 0, 99999, 1)
82 , output_latency (output_latency_adjustment)
83 , input_channels_adjustment (0, 0, 256, 1)
84 , input_channels (input_channels_adjustment)
85 , output_channels_adjustment (0, 0, 256, 1)
86 , output_channels (output_channels_adjustment)
87 , ports_adjustment (128, 8, 1024, 1, 16)
88 , ports_spinner (ports_adjustment)
89 , control_app_button (_("Device Control Panel"))
90 , midi_devices_button (_("Midi Device Setup"))
91 , start_stop_button (_("Stop"))
92 , update_devices_button (_("Refresh Devices"))
93 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
94 , lm_measure_label (_("Measure"))
95 , lm_use_button (_("Use results"))
96 , lm_back_button (_("Back to settings ... (ignore results)"))
97 , lm_button_audio (_("Calibrate Audio"))
99 , have_lm_results (false)
101 , midi_back_button (_("Back to settings"))
103 , ignore_device_changes (0)
104 , _desired_sample_rate (0)
105 , started_at_least_once (false)
106 , queue_device_changed (false)
107 , _have_control (true)
110 using namespace Notebook_Helpers;
111 vector<string> backend_names;
113 AttachOptions xopt = AttachOptions (FILL|EXPAND);
116 set_name (X_("AudioMIDISetup"));
118 /* the backend combo is the one thing that is ALWAYS visible */
120 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
122 if (backends.empty()) {
123 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));
125 throw failed_constructor ();
128 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
129 backend_names.push_back ((*b)->name);
132 set_popdown_strings (backend_combo, backend_names);
134 /* setup basic packing characteristics for the table used on the main
135 * tab of the notebook
138 basic_packer.set_spacings (6);
139 basic_packer.set_border_width (12);
140 basic_packer.set_homogeneous (false);
144 basic_hbox.pack_start (basic_packer, false, false);
146 /* latency measurement tab */
148 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
151 lm_table.set_row_spacings (12);
152 lm_table.set_col_spacings (6);
153 lm_table.set_homogeneous (false);
155 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
158 lm_preamble.set_width_chars (60);
159 lm_preamble.set_line_wrap (true);
160 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
162 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
165 Gtk::Label* preamble;
166 preamble = manage (new Label);
167 preamble->set_width_chars (60);
168 preamble->set_line_wrap (true);
169 preamble->set_markup (_("Select two channels below and connect them using a cable."));
171 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
174 label = manage (new Label (_("Output channel")));
175 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
177 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
178 misc_align->add (lm_output_channel_combo);
179 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
182 label = manage (new Label (_("Input channel")));
183 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
185 misc_align = manage (new Alignment (0.0, 0.5));
186 misc_align->add (lm_input_channel_combo);
187 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
190 lm_measure_label.set_padding (10, 10);
191 lm_measure_button.add (lm_measure_label);
192 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
193 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
194 lm_back_button_signal = lm_back_button.signal_clicked().connect(
195 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
197 lm_use_button.set_sensitive (false);
199 /* Increase the default spacing around the labels of these three
205 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
206 l->set_padding (10, 10);
209 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
210 l->set_padding (10, 10);
213 preamble = manage (new Label);
214 preamble->set_width_chars (60);
215 preamble->set_line_wrap (true);
216 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
217 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220 preamble = manage (new Label);
221 preamble->set_width_chars (60);
222 preamble->set_line_wrap (true);
223 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
224 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 ++row; // skip a row in the table
227 ++row; // skip a row in the table
229 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 ++row; // skip a row in the table
232 ++row; // skip a row in the table
234 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
236 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
238 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
240 lm_vbox.set_border_width (12);
241 lm_vbox.pack_start (lm_table, false, false);
243 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
247 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
248 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
249 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
250 notebook.set_border_width (12);
252 notebook.set_show_tabs (false);
253 notebook.show_all ();
255 notebook.set_name ("SettingsNotebook");
257 /* packup the notebook */
259 get_vbox()->set_border_width (12);
260 get_vbox()->pack_start (notebook);
262 /* need a special function to print "all available channels" when the
263 * channel counts hit zero.
266 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
267 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
269 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
270 midi_devices_button.set_name ("generic button");
271 midi_devices_button.set_can_focus(true);
273 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
274 control_app_button.set_name ("generic button");
275 control_app_button.set_can_focus(true);
276 manage_control_app_sensitivity ();
278 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
279 start_stop_button.set_sensitive (false);
280 start_stop_button.set_name ("generic button");
281 start_stop_button.set_can_focus(true);
282 start_stop_button.set_can_default(true);
283 start_stop_button.set_act_on_release (false);
285 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
286 update_devices_button.set_sensitive (false);
287 update_devices_button.set_name ("generic button");
288 update_devices_button.set_can_focus(true);
290 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
291 use_buffered_io_button.set_sensitive (false);
292 use_buffered_io_button.set_name ("generic button");
293 use_buffered_io_button.set_can_focus(true);
295 /* Pick up any existing audio setup configuration, if appropriate */
297 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
299 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
300 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
301 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
302 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
305 if (!set_state (*audio_setup)) {
306 set_default_state ();
309 set_default_state ();
312 update_sensitivity ();
313 connect_changed_signals ();
315 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
317 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
319 connect_disconnect_button.set_no_show_all();
320 use_buffered_io_button.set_no_show_all();
321 update_devices_button.set_no_show_all();
322 start_stop_button.set_no_show_all();
323 midi_devices_button.set_no_show_all();
327 EngineControl::connect_changed_signals ()
329 backend_combo_connection = backend_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::backend_changed));
331 driver_combo_connection = driver_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::driver_changed));
333 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
335 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
337 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
339 device_combo_connection = device_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::device_changed));
341 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
342 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
344 input_device_combo_connection = input_device_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::input_device_changed));
346 output_device_combo_connection = output_device_combo.signal_changed ().connect (
347 sigc::mem_fun (*this, &EngineControl::output_device_changed));
349 input_latency_connection = input_latency.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::parameter_changed));
351 output_latency_connection = output_latency.signal_changed ().connect (
352 sigc::mem_fun (*this, &EngineControl::parameter_changed));
353 input_channels_connection = input_channels.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::parameter_changed));
355 output_channels_connection = output_channels.signal_changed ().connect (
356 sigc::mem_fun (*this, &EngineControl::parameter_changed));
360 EngineControl::block_changed_signals ()
362 if (block_signals++ == 0) {
363 DEBUG_ECONTROL ("Blocking changed signals");
364 backend_combo_connection.block ();
365 driver_combo_connection.block ();
366 sample_rate_combo_connection.block ();
367 buffer_size_combo_connection.block ();
368 nperiods_combo_connection.block ();
369 device_combo_connection.block ();
370 input_device_combo_connection.block ();
371 output_device_combo_connection.block ();
372 midi_option_combo_connection.block ();
373 input_latency_connection.block ();
374 output_latency_connection.block ();
375 input_channels_connection.block ();
376 output_channels_connection.block ();
381 EngineControl::unblock_changed_signals ()
383 if (--block_signals == 0) {
384 DEBUG_ECONTROL ("Unblocking changed signals");
385 backend_combo_connection.unblock ();
386 driver_combo_connection.unblock ();
387 sample_rate_combo_connection.unblock ();
388 buffer_size_combo_connection.unblock ();
389 nperiods_combo_connection.unblock ();
390 device_combo_connection.unblock ();
391 input_device_combo_connection.unblock ();
392 output_device_combo_connection.unblock ();
393 midi_option_combo_connection.unblock ();
394 input_latency_connection.unblock ();
395 output_latency_connection.unblock ();
396 input_channels_connection.unblock ();
397 output_channels_connection.unblock ();
401 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
402 const std::string& reason)
403 : ec (engine_control)
406 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
407 ec.block_changed_signals ();
410 EngineControl::SignalBlocker::~SignalBlocker ()
412 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
413 ec.unblock_changed_signals ();
417 EngineControl::on_show ()
419 ArdourDialog::on_show ();
420 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
421 // re-check _have_control (jackd running) see #6041
425 start_stop_button.grab_focus();
429 EngineControl::on_map ()
431 if (!ARDOUR_UI::instance()->session_loaded && !PublicEditor::_instance) {
432 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
433 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
434 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
436 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
438 ArdourDialog::on_map ();
442 EngineControl::try_autostart ()
444 if (!start_stop_button.get_sensitive()) {
447 if (ARDOUR::AudioEngine::instance()->running()) {
450 return start_engine ();
454 EngineControl::start_engine ()
456 if (push_state_to_backend(true) != 0) {
457 MessageDialog msg(*this,
458 ARDOUR::AudioEngine::instance()->get_last_backend_error());
466 EngineControl::stop_engine (bool for_latency)
468 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
469 MessageDialog msg(*this,
470 ARDOUR::AudioEngine::instance()->get_last_backend_error());
478 EngineControl::build_notebook ()
481 AttachOptions xopt = AttachOptions (FILL|EXPAND);
483 /* clear the table */
485 Gtkmm2ext::container_clear (basic_vbox);
486 Gtkmm2ext::container_clear (basic_packer);
488 if (control_app_button.get_parent()) {
489 control_app_button.get_parent()->remove (control_app_button);
492 label = manage (left_aligned_label (_("Audio System:")));
493 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
494 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
496 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
497 engine_status.show();
499 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
500 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
501 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
503 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
504 lm_button_audio.set_name ("generic button");
505 lm_button_audio.set_can_focus(true);
508 build_full_control_notebook ();
510 build_no_control_notebook ();
513 basic_vbox.pack_start (basic_hbox, false, false);
516 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
517 basic_vbox.show_all ();
522 EngineControl::build_full_control_notebook ()
524 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
527 using namespace Notebook_Helpers;
529 vector<string> strings;
530 AttachOptions xopt = AttachOptions (FILL|EXPAND);
531 int row = 1; // row zero == backend combo
533 /* start packing it up */
535 if (backend->requires_driver_selection()) {
536 label = manage (left_aligned_label (_("Driver:")));
537 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
538 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
542 if (backend->use_separate_input_and_output_devices()) {
543 label = manage (left_aligned_label (_("Input Device:")));
544 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
545 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
547 label = manage (left_aligned_label (_("Output Device:")));
548 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
549 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
551 // reset so it isn't used in state comparisons
552 device_combo.set_active_text ("");
554 label = manage (left_aligned_label (_("Device:")));
555 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
556 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
558 // reset these so they don't get used in state comparisons
559 input_device_combo.set_active_text ("");
560 output_device_combo.set_active_text ("");
563 label = manage (left_aligned_label (_("Sample rate:")));
564 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
565 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
569 label = manage (left_aligned_label (_("Buffer size:")));
570 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
571 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
572 buffer_size_duration_label.set_alignment (0.0); /* left-align */
573 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
575 int ctrl_btn_span = 1;
576 if (backend->can_set_period_size ()) {
578 label = manage (left_aligned_label (_("Periods:")));
579 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
580 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
584 /* button spans 2 or 3 rows */
586 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
589 input_channels.set_name ("InputChannels");
590 input_channels.set_flags (Gtk::CAN_FOCUS);
591 input_channels.set_digits (0);
592 input_channels.set_wrap (false);
593 output_channels.set_editable (true);
595 if (!ARDOUR::Profile->get_mixbus()) {
596 label = manage (left_aligned_label (_("Input Channels:")));
597 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
598 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
602 output_channels.set_name ("OutputChannels");
603 output_channels.set_flags (Gtk::CAN_FOCUS);
604 output_channels.set_digits (0);
605 output_channels.set_wrap (false);
606 output_channels.set_editable (true);
608 if (!ARDOUR::Profile->get_mixbus()) {
609 label = manage (left_aligned_label (_("Output Channels:")));
610 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
611 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
615 input_latency.set_name ("InputLatency");
616 input_latency.set_flags (Gtk::CAN_FOCUS);
617 input_latency.set_digits (0);
618 input_latency.set_wrap (false);
619 input_latency.set_editable (true);
621 label = manage (left_aligned_label (_("Hardware input latency:")));
622 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
623 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
624 label = manage (left_aligned_label (_("samples")));
625 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
628 output_latency.set_name ("OutputLatency");
629 output_latency.set_flags (Gtk::CAN_FOCUS);
630 output_latency.set_digits (0);
631 output_latency.set_wrap (false);
632 output_latency.set_editable (true);
634 label = manage (left_aligned_label (_("Hardware output latency:")));
635 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
636 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
637 label = manage (left_aligned_label (_("samples")));
638 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
640 /* button spans 2 rows */
642 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
645 label = manage (left_aligned_label (_("MIDI System:")));
646 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
647 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
648 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
653 EngineControl::build_no_control_notebook ()
655 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
658 using namespace Notebook_Helpers;
660 vector<string> strings;
661 AttachOptions xopt = AttachOptions (FILL|EXPAND);
662 int row = 1; // row zero == backend combo
663 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
665 label = manage (new Label);
666 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
667 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
670 if (backend->can_change_sample_rate_when_running()) {
671 label = manage (left_aligned_label (_("Sample rate:")));
672 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
673 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
677 if (backend->can_change_buffer_size_when_running()) {
678 label = manage (left_aligned_label (_("Buffer size:")));
679 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
680 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
681 buffer_size_duration_label.set_alignment (0.0); /* left-align */
682 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
686 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
690 EngineControl::~EngineControl ()
692 ignore_changes = true;
696 EngineControl::disable_latency_tab ()
698 vector<string> empty;
699 set_popdown_strings (lm_output_channel_combo, empty);
700 set_popdown_strings (lm_input_channel_combo, empty);
701 lm_measure_button.set_sensitive (false);
702 lm_use_button.set_sensitive (false);
706 EngineControl::enable_latency_tab ()
708 vector<string> outputs;
709 vector<string> inputs;
711 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
712 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
713 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
715 if (!ARDOUR::AudioEngine::instance()->running()) {
716 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
717 notebook.set_current_page (0);
721 else if (inputs.empty() || outputs.empty()) {
722 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
723 notebook.set_current_page (0);
728 lm_back_button_signal.disconnect();
730 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
733 lm_back_button_signal = lm_back_button.signal_clicked().connect(
734 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
738 set_popdown_strings (lm_output_channel_combo, outputs);
739 lm_output_channel_combo.set_active_text (outputs.front());
740 lm_output_channel_combo.set_sensitive (true);
742 set_popdown_strings (lm_input_channel_combo, inputs);
743 lm_input_channel_combo.set_active_text (inputs.front());
744 lm_input_channel_combo.set_sensitive (true);
746 lm_measure_button.set_sensitive (true);
750 EngineControl::setup_midi_tab_for_backend ()
752 string backend = backend_combo.get_active_text ();
754 Gtkmm2ext::container_clear (midi_vbox);
756 midi_vbox.set_border_width (12);
757 midi_device_table.set_border_width (12);
759 if (backend == "JACK") {
760 setup_midi_tab_for_jack ();
763 midi_vbox.pack_start (midi_device_table, true, true);
764 midi_vbox.pack_start (midi_back_button, false, false);
765 midi_vbox.show_all ();
769 EngineControl::update_sensitivity ()
771 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
773 start_stop_button.set_sensitive (false);
778 size_t devices_available = 0;
779 bool engine_running = ARDOUR::AudioEngine::instance()->running();
781 if (backend->use_separate_input_and_output_devices ()) {
782 devices_available += get_popdown_string_count (input_device_combo);
783 devices_available += get_popdown_string_count (output_device_combo);
785 devices_available += get_popdown_string_count (device_combo);
788 if (devices_available == 0) {
790 input_latency.set_sensitive (false);
791 output_latency.set_sensitive (false);
792 input_channels.set_sensitive (false);
793 output_channels.set_sensitive (false);
795 input_latency.set_sensitive (true);
796 output_latency.set_sensitive (true);
797 input_channels.set_sensitive (!engine_running);
798 output_channels.set_sensitive (!engine_running);
801 if (get_popdown_string_count (buffer_size_combo) > 0) {
802 if (!engine_running) {
803 buffer_size_combo.set_sensitive (valid);
804 } else if (backend->can_change_sample_rate_when_running()) {
805 buffer_size_combo.set_sensitive (valid || !_have_control);
809 * Currently there is no way to manually stop the
810 * engine in order to re-configure it.
811 * This needs to remain sensitive for now.
813 * (it's also handy to implicily
814 * re-start the engine)
816 buffer_size_combo.set_sensitive (true);
818 buffer_size_combo.set_sensitive (false);
822 buffer_size_combo.set_sensitive (false);
826 if (get_popdown_string_count (sample_rate_combo) > 0) {
827 bool allow_to_set_rate = false;
828 if (!engine_running) {
829 if (!ARDOUR_UI::instance()->session_loaded) {
830 // engine is not running, no session loaded -> anything goes.
831 allow_to_set_rate = true;
832 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
833 // only allow to change if the current setting is not the native session rate.
834 allow_to_set_rate = true;
837 sample_rate_combo.set_sensitive (allow_to_set_rate);
839 sample_rate_combo.set_sensitive (false);
843 if (get_popdown_string_count (nperiods_combo) > 0) {
844 if (!engine_running) {
845 nperiods_combo.set_sensitive (true);
847 nperiods_combo.set_sensitive (false);
850 nperiods_combo.set_sensitive (false);
854 start_stop_button.set_sensitive(true);
855 start_stop_button.show();
856 if (engine_running) {
857 start_stop_button.set_text("Stop");
858 update_devices_button.set_sensitive(false);
859 use_buffered_io_button.set_sensitive(false);
861 if (backend->can_request_update_devices()) {
862 update_devices_button.show();
864 update_devices_button.hide();
866 if (backend->can_use_buffered_io()) {
867 use_buffered_io_button.show();
869 use_buffered_io_button.hide();
871 start_stop_button.set_text("Start");
872 update_devices_button.set_sensitive(true);
873 use_buffered_io_button.set_sensitive(true);
876 update_devices_button.set_sensitive(false);
877 update_devices_button.hide();
878 use_buffered_io_button.set_sensitive(false);
879 use_buffered_io_button.hide();
880 start_stop_button.set_sensitive(false);
881 start_stop_button.hide();
884 if (engine_running && _have_control) {
885 input_device_combo.set_sensitive (false);
886 output_device_combo.set_sensitive (false);
887 device_combo.set_sensitive (false);
888 driver_combo.set_sensitive (false);
890 input_device_combo.set_sensitive (true);
891 output_device_combo.set_sensitive (true);
892 device_combo.set_sensitive (true);
893 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
894 driver_combo.set_sensitive (true);
896 driver_combo.set_sensitive (false);
900 midi_option_combo.set_sensitive (!engine_running);
904 EngineControl::setup_midi_tab_for_jack ()
909 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
911 device->input_latency = a->get_value();
913 device->output_latency = a->get_value();
918 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
919 b->set_active (!b->get_active());
920 device->enabled = b->get_active();
921 refresh_midi_display(device->name);
925 EngineControl::refresh_midi_display (std::string focus)
927 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
931 AttachOptions xopt = AttachOptions (FILL|EXPAND);
934 Gtkmm2ext::container_clear (midi_device_table);
936 midi_device_table.set_spacings (6);
938 l = manage (new Label);
939 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
940 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
941 l->set_alignment (0.5, 0.5);
945 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
946 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
947 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
948 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
950 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
951 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
952 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
953 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
956 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
961 bool enabled = (*p)->enabled;
963 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
964 m->set_name ("midi device");
965 m->set_can_focus (Gtk::CAN_FOCUS);
966 m->add_events (Gdk::BUTTON_RELEASE_MASK);
967 m->set_active (enabled);
968 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
969 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
970 if ((*p)->name == focus) {
974 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
975 s = manage (new Gtk::SpinButton (*a));
976 a->set_value ((*p)->input_latency);
977 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
978 s->set_sensitive (_can_set_midi_latencies && enabled);
979 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
981 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
982 s = manage (new Gtk::SpinButton (*a));
983 a->set_value ((*p)->output_latency);
984 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
985 s->set_sensitive (_can_set_midi_latencies && enabled);
986 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
988 b = manage (new Button (_("Calibrate")));
989 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
990 b->set_sensitive (_can_set_midi_latencies && enabled);
991 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
998 EngineControl::backend_changed ()
1000 SignalBlocker blocker (*this, "backend_changed");
1001 string backend_name = backend_combo.get_active_text();
1002 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1004 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1005 /* eh? setting the backend failed... how ? */
1006 /* A: stale config contains a backend that does not exist in current build */
1010 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1012 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1015 setup_midi_tab_for_backend ();
1016 _midi_devices.clear();
1018 if (backend->requires_driver_selection()) {
1019 if (set_driver_popdown_strings ()) {
1023 /* this will change the device text which will cause a call to
1024 * device changed which will set up parameters
1029 update_midi_options ();
1031 connect_disconnect_button.hide();
1033 midi_option_changed();
1035 started_at_least_once = false;
1037 /* changing the backend implies stopping the engine
1038 * ARDOUR::AudioEngine() may or may not emit this signal
1039 * depending on previous engine state
1041 engine_stopped (); // set "active/inactive"
1043 if (!_have_control) {
1044 // set settings from backend that we do have control over
1045 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1048 if (_have_control && !ignore_changes) {
1049 // set driver & devices
1050 State state = get_matching_state (backend_combo.get_active_text());
1052 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1053 set_current_state (state);
1057 if (!ignore_changes) {
1058 maybe_display_saved_state ();
1063 EngineControl::update_midi_options ()
1065 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1066 vector<string> midi_options = backend->enumerate_midi_options();
1068 if (midi_options.size() == 1) {
1069 /* only contains the "none" option */
1070 midi_option_combo.set_sensitive (false);
1072 if (_have_control) {
1073 set_popdown_strings (midi_option_combo, midi_options);
1074 midi_option_combo.set_active_text (midi_options.front());
1075 midi_option_combo.set_sensitive (true);
1077 midi_option_combo.set_sensitive (false);
1083 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1085 if (ARDOUR::Profile->get_mixbus()) {
1089 uint32_t cnt = (uint32_t) sb->get_value();
1091 sb->set_text (_("all available channels"));
1094 snprintf (buf, sizeof (buf), "%d", cnt);
1100 // @return true if there are drivers available
1102 EngineControl::set_driver_popdown_strings ()
1104 DEBUG_ECONTROL ("set_driver_popdown_strings");
1105 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1106 vector<string> drivers = backend->enumerate_drivers();
1108 if (drivers.empty ()) {
1109 // This is an error...?
1113 string current_driver = backend->driver_name ();
1115 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1117 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1120 current_driver = drivers.front ();
1123 set_popdown_strings (driver_combo, drivers);
1125 string_compose ("driver_combo.set_active_text: %1", current_driver));
1126 driver_combo.set_active_text (current_driver);
1131 EngineControl::get_default_device(const string& current_device_name,
1132 const vector<string>& available_devices)
1134 // If the current device is available, use it as default
1135 if (std::find (available_devices.begin (),
1136 available_devices.end (),
1137 current_device_name) != available_devices.end ()) {
1139 return current_device_name;
1142 using namespace ARDOUR;
1144 string default_device_name =
1145 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1147 vector<string>::const_iterator i;
1149 // If there is a "Default" device available, use it
1150 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1151 if (*i == default_device_name) {
1156 string none_device_name =
1157 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1159 // Use the first device that isn't "None"
1160 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1161 if (*i != none_device_name) {
1166 // Use "None" if there are no other available
1167 return available_devices.front();
1170 // @return true if there are devices available
1172 EngineControl::set_device_popdown_strings ()
1174 DEBUG_ECONTROL ("set_device_popdown_strings");
1175 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1176 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1178 /* NOTE: Ardour currently does not display the "available" field of the
1181 * Doing so would require a different GUI widget than the combo
1182 * box/popdown that we currently use, since it has no way to list
1183 * items that are not selectable. Something more like a popup menu,
1184 * which could have unselectable items, would be appropriate.
1187 vector<string> available_devices;
1189 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1190 available_devices.push_back (i->name);
1193 if (available_devices.empty ()) {
1197 set_popdown_strings (device_combo, available_devices);
1199 std::string default_device =
1200 get_default_device(backend->device_name(), available_devices);
1203 string_compose ("set device_combo active text: %1", default_device));
1205 device_combo.set_active_text(default_device);
1209 // @return true if there are input devices available
1211 EngineControl::set_input_device_popdown_strings ()
1213 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1214 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1215 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1217 vector<string> available_devices;
1219 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1220 available_devices.push_back (i->name);
1223 if (available_devices.empty()) {
1227 set_popdown_strings (input_device_combo, available_devices);
1229 std::string default_device =
1230 get_default_device(backend->input_device_name(), available_devices);
1233 string_compose ("set input_device_combo active text: %1", default_device));
1234 input_device_combo.set_active_text(default_device);
1238 // @return true if there are output devices available
1240 EngineControl::set_output_device_popdown_strings ()
1242 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1243 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1244 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1246 vector<string> available_devices;
1248 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1249 available_devices.push_back (i->name);
1252 if (available_devices.empty()) {
1256 set_popdown_strings (output_device_combo, available_devices);
1258 std::string default_device =
1259 get_default_device(backend->output_device_name(), available_devices);
1262 string_compose ("set output_device_combo active text: %1", default_device));
1263 output_device_combo.set_active_text(default_device);
1268 EngineControl::list_devices ()
1270 DEBUG_ECONTROL ("list_devices");
1271 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1274 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1276 bool devices_available = false;
1278 if (backend->use_separate_input_and_output_devices ()) {
1279 bool input_devices_available = set_input_device_popdown_strings ();
1280 bool output_devices_available = set_output_device_popdown_strings ();
1281 devices_available = input_devices_available || output_devices_available;
1283 devices_available = set_device_popdown_strings ();
1286 if (devices_available) {
1289 device_combo.clear();
1290 input_device_combo.clear();
1291 output_device_combo.clear();
1293 update_sensitivity ();
1297 EngineControl::driver_changed ()
1299 SignalBlocker blocker (*this, "driver_changed");
1300 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1303 backend->set_driver (driver_combo.get_active_text());
1306 // TODO load LRU device(s) for backend + driver combo
1308 if (!ignore_changes) {
1309 maybe_display_saved_state ();
1314 EngineControl::get_sample_rates_for_all_devices ()
1316 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1317 ARDOUR::AudioEngine::instance ()->current_backend ();
1318 vector<float> all_rates;
1320 if (backend->use_separate_input_and_output_devices ()) {
1321 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1323 all_rates = backend->available_sample_rates (get_device_name ());
1329 EngineControl::get_default_sample_rates ()
1331 vector<float> rates;
1332 rates.push_back (8000.0f);
1333 rates.push_back (16000.0f);
1334 rates.push_back (32000.0f);
1335 rates.push_back (44100.0f);
1336 rates.push_back (48000.0f);
1337 rates.push_back (88200.0f);
1338 rates.push_back (96000.0f);
1339 rates.push_back (192000.0f);
1340 rates.push_back (384000.0f);
1345 EngineControl::set_samplerate_popdown_strings ()
1347 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1348 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1353 if (_have_control) {
1354 sr = get_sample_rates_for_all_devices ();
1356 sr = get_default_sample_rates ();
1359 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1360 s.push_back (rate_as_string (*x));
1361 if (*x == _desired_sample_rate) {
1366 set_popdown_strings (sample_rate_combo, s);
1369 if (ARDOUR::AudioEngine::instance()->running()) {
1370 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1372 else if (desired.empty ()) {
1373 float new_active_sr = backend->default_sample_rate ();
1375 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1376 new_active_sr = sr.front ();
1379 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1381 sample_rate_combo.set_active_text (desired);
1385 update_sensitivity ();
1389 EngineControl::get_buffer_sizes_for_all_devices ()
1391 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1392 ARDOUR::AudioEngine::instance ()->current_backend ();
1393 vector<uint32_t> all_sizes;
1395 if (backend->use_separate_input_and_output_devices ()) {
1396 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1398 all_sizes = backend->available_buffer_sizes (get_device_name ());
1404 EngineControl::get_default_buffer_sizes ()
1406 vector<uint32_t> sizes;
1407 sizes.push_back (8);
1408 sizes.push_back (16);
1409 sizes.push_back (32);
1410 sizes.push_back (64);
1411 sizes.push_back (128);
1412 sizes.push_back (256);
1413 sizes.push_back (512);
1414 sizes.push_back (1024);
1415 sizes.push_back (2048);
1416 sizes.push_back (4096);
1417 sizes.push_back (8192);
1422 EngineControl::set_buffersize_popdown_strings ()
1424 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1425 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1426 vector<uint32_t> bs;
1429 if (_have_control) {
1430 bs = get_buffer_sizes_for_all_devices ();
1431 } else if (backend->can_change_buffer_size_when_running()) {
1432 bs = get_default_buffer_sizes ();
1435 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1436 s.push_back (bufsize_as_string (*x));
1439 uint32_t previous_size = 0;
1440 if (!buffer_size_combo.get_active_text().empty()) {
1441 previous_size = get_buffer_size ();
1444 set_popdown_strings (buffer_size_combo, s);
1448 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1449 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1452 buffer_size_combo.set_active_text(s.front());
1454 uint32_t period = backend->buffer_size();
1455 if (0 == period && backend->use_separate_input_and_output_devices()) {
1456 period = backend->default_buffer_size(get_input_device_name());
1458 if (0 == period && backend->use_separate_input_and_output_devices()) {
1459 period = backend->default_buffer_size(get_output_device_name());
1461 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1462 period = backend->default_buffer_size(get_device_name());
1465 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1467 show_buffer_duration ();
1469 update_sensitivity ();
1473 EngineControl::set_nperiods_popdown_strings ()
1475 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1476 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1477 vector<uint32_t> np;
1480 if (backend->can_set_period_size()) {
1481 np = backend->available_period_sizes (get_driver());
1484 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1485 s.push_back (to_string (*x));
1488 set_popdown_strings (nperiods_combo, s);
1491 set_active_text_if_present (nperiods_combo, to_string (backend->period_size())); // XXX
1494 update_sensitivity ();
1498 EngineControl::device_changed ()
1500 SignalBlocker blocker (*this, "device_changed");
1501 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1504 string device_name_in;
1505 string device_name_out; // only used if backend support separate I/O devices
1507 if (backend->use_separate_input_and_output_devices()) {
1508 device_name_in = get_input_device_name ();
1509 device_name_out = get_output_device_name ();
1511 device_name_in = get_device_name ();
1514 /* we set the backend-device to query various device related intormation.
1515 * This has the side effect that backend->device_name() will match
1516 * the device_name and 'change_device' will never be true.
1517 * so work around this by setting...
1519 if (backend->use_separate_input_and_output_devices()) {
1520 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1521 queue_device_changed = true;
1524 if (device_name_in != backend->device_name()) {
1525 queue_device_changed = true;
1529 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1530 if (backend->use_separate_input_and_output_devices()) {
1531 backend->set_input_device_name (device_name_in);
1532 backend->set_output_device_name (device_name_out);
1534 backend->set_device_name(device_name_in);
1538 /* don't allow programmatic change to combos to cause a
1539 recursive call to this method.
1541 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1543 set_samplerate_popdown_strings ();
1544 set_buffersize_popdown_strings ();
1545 set_nperiods_popdown_strings ();
1547 /* TODO set min + max channel counts here */
1549 manage_control_app_sensitivity ();
1552 /* pick up any saved state for this device */
1554 if (!ignore_changes) {
1555 maybe_display_saved_state ();
1560 EngineControl::input_device_changed ()
1562 DEBUG_ECONTROL ("input_device_changed");
1564 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1565 if (backend && backend->match_input_output_devices_or_none ()) {
1566 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1568 if (get_output_device_name () != dev_none
1569 && get_input_device_name () != dev_none
1570 && get_input_device_name () != get_output_device_name ()) {
1571 block_changed_signals ();
1572 if (contains_value (output_device_combo, get_input_device_name ())) {
1573 output_device_combo.set_active_text (get_input_device_name ());
1575 assert (contains_value (output_device_combo, dev_none));
1576 output_device_combo.set_active_text (dev_none);
1578 unblock_changed_signals ();
1585 EngineControl::output_device_changed ()
1587 DEBUG_ECONTROL ("output_device_changed");
1588 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1589 if (backend && backend->match_input_output_devices_or_none ()) {
1590 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1592 if (get_input_device_name () != dev_none
1593 && get_input_device_name () != dev_none
1594 && get_input_device_name () != get_output_device_name ()) {
1595 block_changed_signals ();
1596 if (contains_value (input_device_combo, get_output_device_name ())) {
1597 input_device_combo.set_active_text (get_output_device_name ());
1599 assert (contains_value (input_device_combo, dev_none));
1600 input_device_combo.set_active_text (dev_none);
1602 unblock_changed_signals ();
1609 EngineControl::bufsize_as_string (uint32_t sz)
1611 return string_compose (P_("%1 sample", "%1 samples", sz), to_string(sz));
1615 EngineControl::sample_rate_changed ()
1617 DEBUG_ECONTROL ("sample_rate_changed");
1618 /* reset the strings for buffer size to show the correct msec value
1619 (reflecting the new sample rate).
1622 show_buffer_duration ();
1627 EngineControl::buffer_size_changed ()
1629 DEBUG_ECONTROL ("buffer_size_changed");
1630 show_buffer_duration ();
1634 EngineControl::nperiods_changed ()
1636 DEBUG_ECONTROL ("nperiods_changed");
1637 show_buffer_duration ();
1641 EngineControl::show_buffer_duration ()
1643 DEBUG_ECONTROL ("show_buffer_duration");
1644 /* buffer sizes - convert from just samples to samples + msecs for
1645 * the displayed string
1648 string bs_text = buffer_size_combo.get_active_text ();
1649 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1650 uint32_t rate = get_rate();
1652 /* Except for ALSA and Dummy backends, we don't know the number of periods
1653 * per cycle and settings.
1655 * jack1 vs jack2 have different default latencies since jack2 start
1656 * in async-mode unless --sync is given which adds an extra cycle
1657 * of latency. The value is not known if jackd is started externally..
1659 * So just display the period size, that's also what
1660 * ARDOUR_UI::update_sample_rate() does for the status bar.
1661 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1662 * but still, that's the buffer period, not [round-trip] latency)
1665 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1666 buffer_size_duration_label.set_text (buf);
1670 EngineControl::midi_option_changed ()
1672 DEBUG_ECONTROL ("midi_option_changed");
1673 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1676 backend->set_midi_option (get_midi_option());
1678 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1680 //_midi_devices.clear(); // TODO merge with state-saved settings..
1681 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1682 std::vector<MidiDeviceSettings> new_devices;
1684 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1685 MidiDeviceSettings mds = find_midi_device (i->name);
1686 if (i->available && !mds) {
1687 uint32_t input_latency = 0;
1688 uint32_t output_latency = 0;
1689 if (_can_set_midi_latencies) {
1690 input_latency = backend->systemic_midi_input_latency (i->name);
1691 output_latency = backend->systemic_midi_output_latency (i->name);
1693 bool enabled = backend->midi_device_enabled (i->name);
1694 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1695 new_devices.push_back (ptr);
1696 } else if (i->available) {
1697 new_devices.push_back (mds);
1700 _midi_devices = new_devices;
1702 if (_midi_devices.empty()) {
1703 midi_devices_button.hide ();
1705 midi_devices_button.show ();
1710 EngineControl::parameter_changed ()
1714 EngineControl::State
1715 EngineControl::get_matching_state (const string& backend)
1717 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1718 if ((*i)->backend == backend) {
1725 EngineControl::State
1726 EngineControl::get_matching_state (
1727 const string& backend,
1728 const string& driver,
1729 const string& device)
1731 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1732 if ((*i)->backend == backend &&
1733 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1741 EngineControl::State
1742 EngineControl::get_matching_state (
1743 const string& backend,
1744 const string& driver,
1745 const string& input_device,
1746 const string& output_device)
1748 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1749 if ((*i)->backend == backend &&
1750 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1758 EngineControl::State
1759 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1761 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1764 if (backend->use_separate_input_and_output_devices ()) {
1765 return get_matching_state (backend_combo.get_active_text(),
1766 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1767 input_device_combo.get_active_text(),
1768 output_device_combo.get_active_text());
1770 return get_matching_state (backend_combo.get_active_text(),
1771 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1772 device_combo.get_active_text());
1776 return get_matching_state (backend_combo.get_active_text(),
1778 device_combo.get_active_text());
1781 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1782 const EngineControl::State& state2)
1784 if (state1->backend == state2->backend &&
1785 state1->driver == state2->driver &&
1786 state1->device == state2->device &&
1787 state1->input_device == state2->input_device &&
1788 state1->output_device == state2->output_device) {
1794 // sort active first, then most recently used to the beginning of the list
1796 EngineControl::state_sort_cmp (const State &a, const State &b) {
1800 else if (b->active) {
1804 return a->lru > b->lru;
1808 EngineControl::State
1809 EngineControl::save_state ()
1813 if (!_have_control) {
1814 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1816 state->lru = time (NULL) ;
1819 state.reset(new StateStruct);
1820 state->backend = get_backend ();
1822 state.reset(new StateStruct);
1823 store_state (state);
1826 for (StateList::iterator i = states.begin(); i != states.end();) {
1827 if (equivalent_states (*i, state)) {
1828 i = states.erase(i);
1834 states.push_back (state);
1836 states.sort (state_sort_cmp);
1842 EngineControl::store_state (State state)
1844 state->backend = get_backend ();
1845 state->driver = get_driver ();
1846 state->device = get_device_name ();
1847 state->input_device = get_input_device_name ();
1848 state->output_device = get_output_device_name ();
1849 state->sample_rate = get_rate ();
1850 state->buffer_size = get_buffer_size ();
1851 state->n_periods = get_nperiods ();
1852 state->input_latency = get_input_latency ();
1853 state->output_latency = get_output_latency ();
1854 state->input_channels = get_input_channels ();
1855 state->output_channels = get_output_channels ();
1856 state->midi_option = get_midi_option ();
1857 state->midi_devices = _midi_devices;
1858 state->use_buffered_io = get_use_buffered_io ();
1859 state->lru = time (NULL) ;
1863 EngineControl::maybe_display_saved_state ()
1865 if (!_have_control) {
1869 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1872 DEBUG_ECONTROL ("Restoring saved state");
1873 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1875 if (!_desired_sample_rate) {
1876 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1878 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1880 set_active_text_if_present (nperiods_combo, to_string(state->n_periods));
1881 /* call this explicitly because we're ignoring changes to
1882 the controls at this point.
1884 show_buffer_duration ();
1885 input_latency.set_value (state->input_latency);
1886 output_latency.set_value (state->output_latency);
1888 use_buffered_io_button.set_active (state->use_buffered_io);
1890 if (!state->midi_option.empty()) {
1891 midi_option_combo.set_active_text (state->midi_option);
1892 _midi_devices = state->midi_devices;
1895 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1900 EngineControl::get_state ()
1904 XMLNode* root = new XMLNode ("AudioMIDISetup");
1907 if (!states.empty()) {
1908 XMLNode* state_nodes = new XMLNode ("EngineStates");
1910 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1912 XMLNode* node = new XMLNode ("State");
1914 node->set_property ("backend", (*i)->backend);
1915 node->set_property ("driver", (*i)->driver);
1916 node->set_property ("device", (*i)->device);
1917 node->set_property ("input-device", (*i)->input_device);
1918 node->set_property ("output-device", (*i)->output_device);
1919 node->set_property ("sample-rate", (*i)->sample_rate);
1920 node->set_property ("buffer-size", (*i)->buffer_size);
1921 node->set_property ("n-periods", (*i)->n_periods);
1922 node->set_property ("input-latency", (*i)->input_latency);
1923 node->set_property ("output-latency", (*i)->output_latency);
1924 node->set_property ("input-channels", (*i)->input_channels);
1925 node->set_property ("output-channels", (*i)->output_channels);
1926 node->set_property ("active", (*i)->active);
1927 node->set_property ("use-buffered-io", (*i)->use_buffered_io);
1928 node->set_property ("midi-option", (*i)->midi_option);
1929 int32_t lru_val = (*i)->active ? time (NULL) : (*i)->lru;
1930 node->set_property ("lru", lru_val );
1932 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1933 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1934 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1935 midi_device_stuff->set_property (X_("name"), (*p)->name);
1936 midi_device_stuff->set_property (X_("enabled"), (*p)->enabled);
1937 midi_device_stuff->set_property (X_("input-latency"), (*p)->input_latency);
1938 midi_device_stuff->set_property (X_("output-latency"), (*p)->output_latency);
1939 midi_devices->add_child_nocopy (*midi_device_stuff);
1941 node->add_child_nocopy (*midi_devices);
1943 state_nodes->add_child_nocopy (*node);
1946 root->add_child_nocopy (*state_nodes);
1953 EngineControl::set_default_state ()
1955 vector<string> backend_names;
1956 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1958 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1959 backend_names.push_back ((*b)->name);
1961 backend_combo.set_active_text (backend_names.front());
1963 // We could set default backends per platform etc here
1969 EngineControl::set_state (const XMLNode& root)
1971 XMLNodeList clist, cclist;
1972 XMLNodeConstIterator citer, cciter;
1973 XMLNode const * child;
1974 XMLNode const * grandchild;
1976 if (root.name() != "AudioMIDISetup") {
1980 clist = root.children();
1984 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1988 if (child->name() != "EngineStates") {
1992 cclist = child->children();
1994 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1995 State state (new StateStruct);
1997 grandchild = *cciter;
1999 if (grandchild->name() != "State") {
2003 if (!grandchild->get_property ("backend", state->backend)) {
2007 // If any of the required properties are not found in the state node
2008 // then continue/skip to the next engine state
2009 if (!grandchild->get_property ("driver", state->driver) ||
2010 !grandchild->get_property ("device", state->device) ||
2011 !grandchild->get_property ("input-device", state->input_device) ||
2012 !grandchild->get_property ("output-device", state->output_device) ||
2013 !grandchild->get_property ("sample-rate", state->sample_rate) ||
2014 !grandchild->get_property ("buffer-size", state->buffer_size) ||
2015 !grandchild->get_property ("input-latency", state->input_latency) ||
2016 !grandchild->get_property ("output-latency", state->output_latency) ||
2017 !grandchild->get_property ("input-channels", state->input_channels) ||
2018 !grandchild->get_property ("output-channels", state->output_channels) ||
2019 !grandchild->get_property ("active", state->active) ||
2020 !grandchild->get_property ("use-buffered-io", state->use_buffered_io) ||
2021 !grandchild->get_property ("midi-option", state->midi_option)) {
2025 if (!grandchild->get_property ("n-periods", state->n_periods)) {
2026 // optional (new value in 4.5)
2027 state->n_periods = 0;
2030 state->midi_devices.clear();
2032 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2033 const XMLNodeList mnc = midinode->children();
2034 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2037 uint32_t input_latency;
2038 uint32_t output_latency;
2040 if (!(*n)->get_property (X_("name"), name) ||
2041 !(*n)->get_property (X_("enabled"), enabled) ||
2042 !(*n)->get_property (X_("input-latency"), input_latency) ||
2043 !(*n)->get_property (X_("output-latency"), output_latency)) {
2047 MidiDeviceSettings ptr (
2048 new MidiDeviceSetting (name, enabled, input_latency, output_latency));
2049 state->midi_devices.push_back (ptr);
2054 if (grandchild->get_property ("lru", lru_val)) {
2055 state->lru = lru_val;
2059 /* remove accumulated duplicates (due to bug in ealier version)
2060 * this can be removed again before release
2062 for (StateList::iterator i = states.begin(); i != states.end();) {
2063 if ((*i)->backend == state->backend &&
2064 (*i)->driver == state->driver &&
2065 (*i)->device == state->device) {
2066 i = states.erase(i);
2073 states.push_back (state);
2077 /* now see if there was an active state and switch the setup to it */
2079 // purge states of backend that are not available in this built
2080 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2081 vector<std::string> backend_names;
2083 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2084 backend_names.push_back((*i)->name);
2086 for (StateList::iterator i = states.begin(); i != states.end();) {
2087 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2088 i = states.erase(i);
2094 states.sort (state_sort_cmp);
2096 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2099 return set_current_state (*i);
2106 EngineControl::set_current_state (const State& state)
2108 DEBUG_ECONTROL ("set_current_state");
2110 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2112 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2113 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2114 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2115 // this shouldn't happen as the invalid backend names should have been
2116 // removed from the list of states.
2120 // now reflect the change in the backend in the GUI so backend_changed will
2121 // do the right thing
2122 backend_combo.set_active_text (state->backend);
2124 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2126 // we don't have control don't restore state
2131 if (!state->driver.empty ()) {
2132 if (!backend->requires_driver_selection ()) {
2133 DEBUG_ECONTROL ("Backend should require driver selection");
2134 // A backend has changed from having driver selection to not having
2135 // it or someone has been manually editing a config file and messed
2140 if (backend->set_driver (state->driver) != 0) {
2141 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2142 // Driver names for a backend have changed and the name in the
2143 // config file is now invalid or support for driver is no longer
2144 // included in the backend
2147 // no need to set the driver_combo as backend_changed will use
2148 // backend->driver_name to set the active driver
2151 if (!state->device.empty ()) {
2152 if (backend->set_device_name (state->device) != 0) {
2154 string_compose ("Unable to set device name %1", state->device));
2155 // device is no longer available on the system
2158 // no need to set active device as it will be picked up in
2159 // via backend_changed ()/set_device_popdown_strings
2162 // backend supports separate input/output devices
2163 if (backend->set_input_device_name (state->input_device) != 0) {
2164 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2165 state->input_device));
2166 // input device is no longer available on the system
2170 if (backend->set_output_device_name (state->output_device) != 0) {
2171 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2172 state->input_device));
2173 // output device is no longer available on the system
2176 // no need to set active devices as it will be picked up in via
2177 // backend_changed ()/set_*_device_popdown_strings
2182 // Now restore the state of the rest of the controls
2184 // We don't use a SignalBlocker as set_current_state is currently only
2185 // called from set_state before any signals are connected. If at some point
2186 // a more general named state mechanism is implemented and
2187 // set_current_state is called while signals are connected then a
2188 // SignalBlocker will need to be instantiated before setting these.
2190 device_combo.set_active_text (state->device);
2191 input_device_combo.set_active_text (state->input_device);
2192 output_device_combo.set_active_text (state->output_device);
2193 if (!_desired_sample_rate) {
2194 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2196 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2197 set_active_text_if_present (nperiods_combo, to_string (state->n_periods));
2198 input_latency.set_value (state->input_latency);
2199 output_latency.set_value (state->output_latency);
2200 midi_option_combo.set_active_text (state->midi_option);
2201 use_buffered_io_button.set_active (state->use_buffered_io);
2206 EngineControl::push_state_to_backend (bool start)
2208 DEBUG_ECONTROL ("push_state_to_backend");
2209 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2210 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2216 /* figure out what is going to change */
2218 bool restart_required = false;
2219 bool was_running = ARDOUR::AudioEngine::instance()->running();
2220 bool change_driver = false;
2221 bool change_device = false;
2222 bool change_rate = false;
2223 bool change_bufsize = false;
2224 bool change_nperiods = false;
2225 bool change_latency = false;
2226 bool change_channels = false;
2227 bool change_midi = false;
2228 bool change_buffered_io = false;
2230 uint32_t ochan = get_output_channels ();
2231 uint32_t ichan = get_input_channels ();
2233 if (_have_control) {
2235 if (started_at_least_once) {
2237 /* we can control the backend */
2239 if (backend->requires_driver_selection()) {
2240 if (get_driver() != backend->driver_name()) {
2241 change_driver = true;
2245 if (backend->use_separate_input_and_output_devices()) {
2246 if (get_input_device_name() != backend->input_device_name()) {
2247 change_device = true;
2249 if (get_output_device_name() != backend->output_device_name()) {
2250 change_device = true;
2253 if (get_device_name() != backend->device_name()) {
2254 change_device = true;
2258 if (queue_device_changed) {
2259 change_device = true;
2262 if (get_rate() != backend->sample_rate()) {
2266 if (get_buffer_size() != backend->buffer_size()) {
2267 change_bufsize = true;
2270 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2271 && get_nperiods() != backend->period_size()) {
2272 change_nperiods = true;
2275 if (get_midi_option() != backend->midi_option()) {
2279 if (backend->can_use_buffered_io()) {
2280 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2281 change_buffered_io = true;
2285 /* zero-requested channels means "all available" */
2288 ichan = backend->input_channels();
2292 ochan = backend->output_channels();
2295 if (ichan != backend->input_channels()) {
2296 change_channels = true;
2299 if (ochan != backend->output_channels()) {
2300 change_channels = true;
2303 if (get_input_latency() != backend->systemic_input_latency() ||
2304 get_output_latency() != backend->systemic_output_latency()) {
2305 change_latency = true;
2308 /* backend never started, so we have to force a group
2311 change_device = true;
2312 if (backend->requires_driver_selection()) {
2313 change_driver = true;
2316 change_bufsize = true;
2317 change_channels = true;
2318 change_latency = true;
2320 change_buffered_io = backend->can_use_buffered_io();
2321 change_channels = true;
2322 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2327 /* we have no control over the backend, meaning that we can
2328 * only possibly change sample rate and buffer size.
2332 if (get_rate() != backend->sample_rate()) {
2333 change_bufsize = true;
2336 if (get_buffer_size() != backend->buffer_size()) {
2337 change_bufsize = true;
2341 queue_device_changed = false;
2343 if (!_have_control) {
2345 /* We do not have control over the backend, so the best we can
2346 * do is try to change the sample rate and/or bufsize and get
2350 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2354 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2359 backend->set_sample_rate (get_rate());
2362 if (change_bufsize) {
2363 backend->set_buffer_size (get_buffer_size());
2367 if (ARDOUR::AudioEngine::instance()->start ()) {
2368 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2378 /* determine if we need to stop the backend before changing parameters */
2380 if (change_driver || change_device || change_channels || change_nperiods ||
2381 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2382 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2383 change_midi || change_buffered_io ||
2384 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2385 restart_required = true;
2387 restart_required = false;
2392 if (restart_required) {
2393 if (ARDOUR::AudioEngine::instance()->stop()) {
2399 if (change_driver && backend->set_driver (get_driver())) {
2400 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2403 if (backend->use_separate_input_and_output_devices()) {
2404 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2405 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2408 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2409 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2413 if (change_device && backend->set_device_name (get_device_name())) {
2414 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2418 if (change_rate && backend->set_sample_rate (get_rate())) {
2419 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2422 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2423 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2426 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2427 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2431 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2432 if (backend->set_input_channels (get_input_channels())) {
2433 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2436 if (backend->set_output_channels (get_output_channels())) {
2437 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2441 if (change_latency) {
2442 if (backend->set_systemic_input_latency (get_input_latency())) {
2443 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2446 if (backend->set_systemic_output_latency (get_output_latency())) {
2447 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2453 backend->set_midi_option (get_midi_option());
2456 if (change_buffered_io) {
2457 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2461 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2462 if (_measure_midi) {
2463 if (*p == _measure_midi) {
2464 backend->set_midi_device_enabled ((*p)->name, true);
2466 backend->set_midi_device_enabled ((*p)->name, false);
2468 if (backend->can_change_systemic_latency_when_running ()) {
2469 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2470 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2474 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2475 if (backend->can_set_systemic_midi_latencies()) {
2476 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2477 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2482 if (start || (was_running && restart_required)) {
2483 if (ARDOUR::AudioEngine::instance()->start()) {
2494 EngineControl::post_push ()
2496 /* get a pointer to the current state object, creating one if
2500 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2503 state = save_state ();
2509 states.sort (state_sort_cmp);
2513 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2514 (*i)->active = false;
2517 /* mark this one active (to be used next time the dialog is
2521 state->active = true;
2523 if (_have_control) { // XXX
2524 manage_control_app_sensitivity ();
2527 /* schedule a redisplay of MIDI ports */
2528 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2533 EngineControl::get_rate () const
2535 float r = atof (sample_rate_combo.get_active_text ());
2536 /* the string may have been translated with an abbreviation for
2537 * thousands, so use a crude heuristic to fix this.
2547 EngineControl::get_buffer_size () const
2549 string txt = buffer_size_combo.get_active_text ();
2552 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2553 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2554 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2562 EngineControl::get_nperiods () const
2564 string txt = nperiods_combo.get_active_text ();
2565 return atoi (txt.c_str());
2569 EngineControl::get_midi_option () const
2571 return midi_option_combo.get_active_text();
2575 EngineControl::get_use_buffered_io () const
2577 return use_buffered_io_button.get_active();
2581 EngineControl::get_input_channels() const
2583 if (ARDOUR::Profile->get_mixbus()) {
2584 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2585 if (!backend) return 0;
2586 return backend->input_channels();
2588 return (uint32_t) input_channels_adjustment.get_value();
2592 EngineControl::get_output_channels() const
2594 if (ARDOUR::Profile->get_mixbus()) {
2595 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2596 if (!backend) return 0;
2597 return backend->input_channels();
2599 return (uint32_t) output_channels_adjustment.get_value();
2603 EngineControl::get_input_latency() const
2605 return (uint32_t) input_latency_adjustment.get_value();
2609 EngineControl::get_output_latency() const
2611 return (uint32_t) output_latency_adjustment.get_value();
2615 EngineControl::get_backend () const
2617 return backend_combo.get_active_text ();
2621 EngineControl::get_driver () const
2623 if (driver_combo.get_parent()) {
2624 return driver_combo.get_active_text ();
2631 EngineControl::get_device_name () const
2633 return device_combo.get_active_text ();
2637 EngineControl::get_input_device_name () const
2639 return input_device_combo.get_active_text ();
2643 EngineControl::get_output_device_name () const
2645 return output_device_combo.get_active_text ();
2649 EngineControl::control_app_button_clicked ()
2651 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2657 backend->launch_control_app ();
2661 EngineControl::start_stop_button_clicked ()
2663 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2669 if (ARDOUR::AudioEngine::instance()->running()) {
2670 ARDOUR::AudioEngine::instance()->stop ();
2672 if (!ARDOUR_UI::instance()->session_loaded) {
2678 if (!ARDOUR_UI::instance()->session_loaded) {
2679 ArdourDialog::on_response (RESPONSE_OK);
2685 EngineControl::update_devices_button_clicked ()
2687 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2693 if (backend->update_devices()) {
2694 device_list_changed ();
2699 EngineControl::use_buffered_io_button_clicked ()
2701 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2707 bool set_buffered_io = !use_buffered_io_button.get_active();
2708 use_buffered_io_button.set_active (set_buffered_io);
2709 backend->set_use_buffered_io (set_buffered_io);
2713 EngineControl::manage_control_app_sensitivity ()
2715 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2721 string appname = backend->control_app_name();
2723 if (appname.empty()) {
2724 control_app_button.set_sensitive (false);
2726 control_app_button.set_sensitive (true);
2731 EngineControl::set_desired_sample_rate (uint32_t sr)
2733 _desired_sample_rate = sr;
2734 if (ARDOUR::AudioEngine::instance ()->running ()
2735 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2742 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2744 if (page_num == 0) {
2745 _measure_midi.reset();
2746 update_sensitivity ();
2749 if (page_num == midi_tab) {
2751 refresh_midi_display ();
2754 if (page_num == latency_tab) {
2757 if (ARDOUR::AudioEngine::instance()->running()) {
2762 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2764 /* save any existing latency values */
2766 uint32_t il = (uint32_t) input_latency.get_value ();
2767 uint32_t ol = (uint32_t) input_latency.get_value ();
2769 /* reset to zero so that our new test instance
2770 will be clean of any existing latency measures.
2772 NB. this should really be done by the backend
2773 when stated for latency measurement.
2776 input_latency.set_value (0);
2777 output_latency.set_value (0);
2779 push_state_to_backend (false);
2783 input_latency.set_value (il);
2784 output_latency.set_value (ol);
2787 // This should be done in push_state_to_backend()
2788 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2789 disable_latency_tab ();
2792 enable_latency_tab ();
2796 end_latency_detection ();
2797 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2802 /* latency measurement */
2805 EngineControl::check_audio_latency_measurement ()
2807 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2809 if (mtdm->resolve () < 0) {
2810 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2814 if (mtdm->get_peak () > 0.707f) {
2815 // get_peak() resets the peak-hold in the detector.
2816 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2817 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2821 if (mtdm->err () > 0.3) {
2827 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2829 if (sample_rate == 0) {
2830 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2831 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2835 int frames_total = mtdm->del();
2836 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2838 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2839 _("Detected roundtrip latency: "),
2840 frames_total, frames_total * 1000.0f/sample_rate,
2841 _("Systemic latency: "),
2842 extra, extra * 1000.0f/sample_rate);
2846 if (mtdm->err () > 0.2) {
2848 strcat (buf, _("(signal detection error)"));
2854 strcat (buf, _("(inverted - bad wiring)"));
2858 lm_results.set_markup (string_compose (results_markup, buf));
2861 have_lm_results = true;
2862 end_latency_detection ();
2863 lm_use_button.set_sensitive (true);
2871 EngineControl::check_midi_latency_measurement ()
2873 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2875 if (!mididm->have_signal () || mididm->latency () == 0) {
2876 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2881 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2883 if (sample_rate == 0) {
2884 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2885 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2889 ARDOUR::framecnt_t frames_total = mididm->latency();
2890 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2891 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2892 _("Detected roundtrip latency: "),
2893 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2894 _("Systemic latency: "),
2895 extra, extra * 1000.0f / sample_rate);
2899 if (!mididm->ok ()) {
2901 strcat (buf, _("(averaging)"));
2905 if (mididm->deviation () > 50.0) {
2907 strcat (buf, _("(too large jitter)"));
2909 } else if (mididm->deviation () > 10.0) {
2911 strcat (buf, _("(large jitter)"));
2915 have_lm_results = true;
2916 end_latency_detection ();
2917 lm_use_button.set_sensitive (true);
2918 lm_results.set_markup (string_compose (results_markup, buf));
2920 } else if (mididm->processed () > 400) {
2921 have_lm_results = false;
2922 end_latency_detection ();
2923 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2927 lm_results.set_markup (string_compose (results_markup, buf));
2933 EngineControl::start_latency_detection ()
2935 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2936 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2938 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2939 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2940 if (_measure_midi) {
2941 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2943 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2945 lm_measure_label.set_text (_("Cancel"));
2946 have_lm_results = false;
2947 lm_use_button.set_sensitive (false);
2948 lm_input_channel_combo.set_sensitive (false);
2949 lm_output_channel_combo.set_sensitive (false);
2955 EngineControl::end_latency_detection ()
2957 latency_timeout.disconnect ();
2958 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2959 lm_measure_label.set_text (_("Measure"));
2960 if (!have_lm_results) {
2961 lm_use_button.set_sensitive (false);
2963 lm_input_channel_combo.set_sensitive (true);
2964 lm_output_channel_combo.set_sensitive (true);
2969 EngineControl::latency_button_clicked ()
2972 start_latency_detection ();
2974 end_latency_detection ();
2979 EngineControl::latency_back_button_clicked ()
2981 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2982 notebook.set_current_page(0);
2986 EngineControl::use_latency_button_clicked ()
2988 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2989 if (_measure_midi) {
2990 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2994 ARDOUR::framecnt_t frames_total = mididm->latency();
2995 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2996 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2997 _measure_midi->input_latency = one_way;
2998 _measure_midi->output_latency = one_way;
2999 if (backend->can_change_systemic_latency_when_running ()) {
3000 backend->set_systemic_midi_input_latency (_measure_midi->name, one_way);
3001 backend->set_systemic_midi_output_latency (_measure_midi->name, one_way);
3003 notebook.set_current_page (midi_tab);
3005 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3011 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3012 one_way = std::max (0., one_way);
3014 input_latency_adjustment.set_value (one_way);
3015 output_latency_adjustment.set_value (one_way);
3016 if (backend->can_change_systemic_latency_when_running ()) {
3017 backend->set_systemic_input_latency (one_way);
3018 backend->set_systemic_output_latency (one_way);
3021 /* back to settings page */
3022 notebook.set_current_page (0);
3027 EngineControl::on_delete_event (GdkEventAny* ev)
3029 if (notebook.get_current_page() == 2) {
3030 /* currently on latency tab - be sure to clean up */
3031 end_latency_detection ();
3033 return ArdourDialog::on_delete_event (ev);
3037 EngineControl::engine_running ()
3039 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3042 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3043 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3045 if (backend->can_set_period_size ()) {
3046 set_active_text_if_present (nperiods_combo, to_string (backend->period_size()));
3049 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3050 connect_disconnect_button.show();
3052 started_at_least_once = true;
3053 if (_have_control) {
3054 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3056 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3058 update_sensitivity();
3062 EngineControl::engine_stopped ()
3064 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3067 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3068 connect_disconnect_button.show();
3070 if (_have_control) {
3071 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3073 engine_status.set_markup(X_(""));
3076 update_sensitivity();
3080 EngineControl::device_list_changed ()
3082 if (ignore_device_changes) {
3085 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3087 midi_option_changed();
3091 EngineControl::connect_disconnect_click()
3093 if (ARDOUR::AudioEngine::instance()->running()) {
3096 if (!ARDOUR_UI::instance()->session_loaded) {
3102 if (!ARDOUR_UI::instance()->session_loaded) {
3103 ArdourDialog::on_response (RESPONSE_OK);
3109 EngineControl::calibrate_audio_latency ()
3111 _measure_midi.reset ();
3112 have_lm_results = false;
3113 lm_use_button.set_sensitive (false);
3114 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3115 notebook.set_current_page (latency_tab);
3119 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3122 have_lm_results = false;
3123 lm_use_button.set_sensitive (false);
3124 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3125 notebook.set_current_page (latency_tab);
3129 EngineControl::configure_midi_devices ()
3131 notebook.set_current_page (midi_tab);