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 (nperiods_as_string (*x));
1488 set_popdown_strings (nperiods_combo, s);
1491 set_active_text_if_present (nperiods_combo, nperiods_as_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), sz);
1615 EngineControl::nperiods_as_string (uint32_t np)
1618 snprintf (buf, sizeof (buf), "%u", np);
1624 EngineControl::sample_rate_changed ()
1626 DEBUG_ECONTROL ("sample_rate_changed");
1627 /* reset the strings for buffer size to show the correct msec value
1628 (reflecting the new sample rate).
1631 show_buffer_duration ();
1636 EngineControl::buffer_size_changed ()
1638 DEBUG_ECONTROL ("buffer_size_changed");
1639 show_buffer_duration ();
1643 EngineControl::nperiods_changed ()
1645 DEBUG_ECONTROL ("nperiods_changed");
1646 show_buffer_duration ();
1650 EngineControl::show_buffer_duration ()
1652 DEBUG_ECONTROL ("show_buffer_duration");
1653 /* buffer sizes - convert from just samples to samples + msecs for
1654 * the displayed string
1657 string bs_text = buffer_size_combo.get_active_text ();
1658 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1659 uint32_t rate = get_rate();
1661 /* Except for ALSA and Dummy backends, we don't know the number of periods
1662 * per cycle and settings.
1664 * jack1 vs jack2 have different default latencies since jack2 start
1665 * in async-mode unless --sync is given which adds an extra cycle
1666 * of latency. The value is not known if jackd is started externally..
1668 * So just display the period size, that's also what
1669 * ARDOUR_UI::update_sample_rate() does for the status bar.
1670 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1671 * but still, that's the buffer period, not [round-trip] latency)
1674 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1675 buffer_size_duration_label.set_text (buf);
1679 EngineControl::midi_option_changed ()
1681 DEBUG_ECONTROL ("midi_option_changed");
1682 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1685 backend->set_midi_option (get_midi_option());
1687 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1689 //_midi_devices.clear(); // TODO merge with state-saved settings..
1690 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1691 std::vector<MidiDeviceSettings> new_devices;
1693 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1694 MidiDeviceSettings mds = find_midi_device (i->name);
1695 if (i->available && !mds) {
1696 uint32_t input_latency = 0;
1697 uint32_t output_latency = 0;
1698 if (_can_set_midi_latencies) {
1699 input_latency = backend->systemic_midi_input_latency (i->name);
1700 output_latency = backend->systemic_midi_output_latency (i->name);
1702 bool enabled = backend->midi_device_enabled (i->name);
1703 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1704 new_devices.push_back (ptr);
1705 } else if (i->available) {
1706 new_devices.push_back (mds);
1709 _midi_devices = new_devices;
1711 if (_midi_devices.empty()) {
1712 midi_devices_button.hide ();
1714 midi_devices_button.show ();
1719 EngineControl::parameter_changed ()
1723 EngineControl::State
1724 EngineControl::get_matching_state (const string& backend)
1726 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1727 if ((*i)->backend == backend) {
1734 EngineControl::State
1735 EngineControl::get_matching_state (
1736 const string& backend,
1737 const string& driver,
1738 const string& device)
1740 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1741 if ((*i)->backend == backend &&
1742 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1750 EngineControl::State
1751 EngineControl::get_matching_state (
1752 const string& backend,
1753 const string& driver,
1754 const string& input_device,
1755 const string& output_device)
1757 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1758 if ((*i)->backend == backend &&
1759 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1767 EngineControl::State
1768 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1770 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1773 if (backend->use_separate_input_and_output_devices ()) {
1774 return get_matching_state (backend_combo.get_active_text(),
1775 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1776 input_device_combo.get_active_text(),
1777 output_device_combo.get_active_text());
1779 return get_matching_state (backend_combo.get_active_text(),
1780 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1781 device_combo.get_active_text());
1785 return get_matching_state (backend_combo.get_active_text(),
1787 device_combo.get_active_text());
1790 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1791 const EngineControl::State& state2)
1793 if (state1->backend == state2->backend &&
1794 state1->driver == state2->driver &&
1795 state1->device == state2->device &&
1796 state1->input_device == state2->input_device &&
1797 state1->output_device == state2->output_device) {
1803 // sort active first, then most recently used to the beginning of the list
1805 EngineControl::state_sort_cmp (const State &a, const State &b) {
1809 else if (b->active) {
1813 return a->lru > b->lru;
1817 EngineControl::State
1818 EngineControl::save_state ()
1822 if (!_have_control) {
1823 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1825 state->lru = time (NULL) ;
1828 state.reset(new StateStruct);
1829 state->backend = get_backend ();
1831 state.reset(new StateStruct);
1832 store_state (state);
1835 for (StateList::iterator i = states.begin(); i != states.end();) {
1836 if (equivalent_states (*i, state)) {
1837 i = states.erase(i);
1843 states.push_back (state);
1845 states.sort (state_sort_cmp);
1851 EngineControl::store_state (State state)
1853 state->backend = get_backend ();
1854 state->driver = get_driver ();
1855 state->device = get_device_name ();
1856 state->input_device = get_input_device_name ();
1857 state->output_device = get_output_device_name ();
1858 state->sample_rate = get_rate ();
1859 state->buffer_size = get_buffer_size ();
1860 state->n_periods = get_nperiods ();
1861 state->input_latency = get_input_latency ();
1862 state->output_latency = get_output_latency ();
1863 state->input_channels = get_input_channels ();
1864 state->output_channels = get_output_channels ();
1865 state->midi_option = get_midi_option ();
1866 state->midi_devices = _midi_devices;
1867 state->use_buffered_io = get_use_buffered_io ();
1868 state->lru = time (NULL) ;
1872 EngineControl::maybe_display_saved_state ()
1874 if (!_have_control) {
1878 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1881 DEBUG_ECONTROL ("Restoring saved state");
1882 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1884 if (!_desired_sample_rate) {
1885 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1887 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1889 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1890 /* call this explicitly because we're ignoring changes to
1891 the controls at this point.
1893 show_buffer_duration ();
1894 input_latency.set_value (state->input_latency);
1895 output_latency.set_value (state->output_latency);
1897 use_buffered_io_button.set_active (state->use_buffered_io);
1899 if (!state->midi_option.empty()) {
1900 midi_option_combo.set_active_text (state->midi_option);
1901 _midi_devices = state->midi_devices;
1904 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1909 EngineControl::get_state ()
1913 XMLNode* root = new XMLNode ("AudioMIDISetup");
1916 if (!states.empty()) {
1917 XMLNode* state_nodes = new XMLNode ("EngineStates");
1919 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1921 XMLNode* node = new XMLNode ("State");
1923 node->add_property ("backend", (*i)->backend);
1924 node->add_property ("driver", (*i)->driver);
1925 node->add_property ("device", (*i)->device);
1926 node->add_property ("input-device", (*i)->input_device);
1927 node->add_property ("output-device", (*i)->output_device);
1928 node->add_property ("sample-rate", (*i)->sample_rate);
1929 node->add_property ("buffer-size", (*i)->buffer_size);
1930 node->add_property ("n-periods", (*i)->n_periods);
1931 node->add_property ("input-latency", (*i)->input_latency);
1932 node->add_property ("output-latency", (*i)->output_latency);
1933 node->add_property ("input-channels", (*i)->input_channels);
1934 node->add_property ("output-channels", (*i)->output_channels);
1935 node->add_property ("active", (*i)->active ? "yes" : "no");
1936 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1937 node->add_property ("midi-option", (*i)->midi_option);
1938 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1940 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1941 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1942 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1943 midi_device_stuff->add_property (X_("name"), (*p)->name);
1944 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1945 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1946 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1947 midi_devices->add_child_nocopy (*midi_device_stuff);
1949 node->add_child_nocopy (*midi_devices);
1951 state_nodes->add_child_nocopy (*node);
1954 root->add_child_nocopy (*state_nodes);
1961 EngineControl::set_default_state ()
1963 vector<string> backend_names;
1964 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1966 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1967 backend_names.push_back ((*b)->name);
1969 backend_combo.set_active_text (backend_names.front());
1971 // We could set default backends per platform etc here
1977 EngineControl::set_state (const XMLNode& root)
1979 XMLNodeList clist, cclist;
1980 XMLNodeConstIterator citer, cciter;
1981 XMLNode const * child;
1982 XMLNode const * grandchild;
1983 XMLProperty const * prop = NULL;
1985 if (root.name() != "AudioMIDISetup") {
1989 clist = root.children();
1993 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1997 if (child->name() != "EngineStates") {
2001 cclist = child->children();
2003 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2004 State state (new StateStruct);
2006 grandchild = *cciter;
2008 if (grandchild->name() != "State") {
2012 if ((prop = grandchild->property ("backend")) == 0) {
2015 state->backend = prop->value ();
2017 if ((prop = grandchild->property ("driver")) == 0) {
2020 state->driver = prop->value ();
2022 if ((prop = grandchild->property ("device")) == 0) {
2025 state->device = prop->value ();
2027 if ((prop = grandchild->property ("input-device")) == 0) {
2030 state->input_device = prop->value ();
2032 if ((prop = grandchild->property ("output-device")) == 0) {
2035 state->output_device = prop->value ();
2037 if ((prop = grandchild->property ("sample-rate")) == 0) {
2040 state->sample_rate = atof (prop->value ());
2042 if ((prop = grandchild->property ("buffer-size")) == 0) {
2045 state->buffer_size = atoi (prop->value ());
2047 if ((prop = grandchild->property ("n-periods")) == 0) {
2048 // optional (new value in 4.5)
2049 state->n_periods = 0;
2051 state->n_periods = atoi (prop->value ());
2054 if ((prop = grandchild->property ("input-latency")) == 0) {
2057 state->input_latency = atoi (prop->value ());
2059 if ((prop = grandchild->property ("output-latency")) == 0) {
2062 state->output_latency = atoi (prop->value ());
2064 if ((prop = grandchild->property ("input-channels")) == 0) {
2067 state->input_channels = atoi (prop->value ());
2069 if ((prop = grandchild->property ("output-channels")) == 0) {
2072 state->output_channels = atoi (prop->value ());
2074 if ((prop = grandchild->property ("active")) == 0) {
2077 state->active = string_is_affirmative (prop->value ());
2079 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2082 state->use_buffered_io = string_is_affirmative (prop->value ());
2084 if ((prop = grandchild->property ("midi-option")) == 0) {
2087 state->midi_option = prop->value ();
2089 state->midi_devices.clear();
2091 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2092 const XMLNodeList mnc = midinode->children();
2093 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2094 if ((*n)->property (X_("name")) == 0
2095 || (*n)->property (X_("enabled")) == 0
2096 || (*n)->property (X_("input-latency")) == 0
2097 || (*n)->property (X_("output-latency")) == 0
2102 MidiDeviceSettings ptr (new MidiDeviceSetting(
2103 (*n)->property (X_("name"))->value (),
2104 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2105 atoi ((*n)->property (X_("input-latency"))->value ()),
2106 atoi ((*n)->property (X_("output-latency"))->value ())
2108 state->midi_devices.push_back (ptr);
2112 if ((prop = grandchild->property ("lru"))) {
2113 state->lru = atoi (prop->value ());
2117 /* remove accumulated duplicates (due to bug in ealier version)
2118 * this can be removed again before release
2120 for (StateList::iterator i = states.begin(); i != states.end();) {
2121 if ((*i)->backend == state->backend &&
2122 (*i)->driver == state->driver &&
2123 (*i)->device == state->device) {
2124 i = states.erase(i);
2131 states.push_back (state);
2135 /* now see if there was an active state and switch the setup to it */
2137 // purge states of backend that are not available in this built
2138 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2139 vector<std::string> backend_names;
2141 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2142 backend_names.push_back((*i)->name);
2144 for (StateList::iterator i = states.begin(); i != states.end();) {
2145 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2146 i = states.erase(i);
2152 states.sort (state_sort_cmp);
2154 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2157 return set_current_state (*i);
2164 EngineControl::set_current_state (const State& state)
2166 DEBUG_ECONTROL ("set_current_state");
2168 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2170 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2171 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2172 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2173 // this shouldn't happen as the invalid backend names should have been
2174 // removed from the list of states.
2178 // now reflect the change in the backend in the GUI so backend_changed will
2179 // do the right thing
2180 backend_combo.set_active_text (state->backend);
2182 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2184 // we don't have control don't restore state
2189 if (!state->driver.empty ()) {
2190 if (!backend->requires_driver_selection ()) {
2191 DEBUG_ECONTROL ("Backend should require driver selection");
2192 // A backend has changed from having driver selection to not having
2193 // it or someone has been manually editing a config file and messed
2198 if (backend->set_driver (state->driver) != 0) {
2199 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2200 // Driver names for a backend have changed and the name in the
2201 // config file is now invalid or support for driver is no longer
2202 // included in the backend
2205 // no need to set the driver_combo as backend_changed will use
2206 // backend->driver_name to set the active driver
2209 if (!state->device.empty ()) {
2210 if (backend->set_device_name (state->device) != 0) {
2212 string_compose ("Unable to set device name %1", state->device));
2213 // device is no longer available on the system
2216 // no need to set active device as it will be picked up in
2217 // via backend_changed ()/set_device_popdown_strings
2220 // backend supports separate input/output devices
2221 if (backend->set_input_device_name (state->input_device) != 0) {
2222 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2223 state->input_device));
2224 // input device is no longer available on the system
2228 if (backend->set_output_device_name (state->output_device) != 0) {
2229 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2230 state->input_device));
2231 // output device is no longer available on the system
2234 // no need to set active devices as it will be picked up in via
2235 // backend_changed ()/set_*_device_popdown_strings
2240 // Now restore the state of the rest of the controls
2242 // We don't use a SignalBlocker as set_current_state is currently only
2243 // called from set_state before any signals are connected. If at some point
2244 // a more general named state mechanism is implemented and
2245 // set_current_state is called while signals are connected then a
2246 // SignalBlocker will need to be instantiated before setting these.
2248 device_combo.set_active_text (state->device);
2249 input_device_combo.set_active_text (state->input_device);
2250 output_device_combo.set_active_text (state->output_device);
2251 if (!_desired_sample_rate) {
2252 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2254 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2255 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2256 input_latency.set_value (state->input_latency);
2257 output_latency.set_value (state->output_latency);
2258 midi_option_combo.set_active_text (state->midi_option);
2259 use_buffered_io_button.set_active (state->use_buffered_io);
2264 EngineControl::push_state_to_backend (bool start)
2266 DEBUG_ECONTROL ("push_state_to_backend");
2267 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2268 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2274 /* figure out what is going to change */
2276 bool restart_required = false;
2277 bool was_running = ARDOUR::AudioEngine::instance()->running();
2278 bool change_driver = false;
2279 bool change_device = false;
2280 bool change_rate = false;
2281 bool change_bufsize = false;
2282 bool change_nperiods = false;
2283 bool change_latency = false;
2284 bool change_channels = false;
2285 bool change_midi = false;
2286 bool change_buffered_io = false;
2288 uint32_t ochan = get_output_channels ();
2289 uint32_t ichan = get_input_channels ();
2291 if (_have_control) {
2293 if (started_at_least_once) {
2295 /* we can control the backend */
2297 if (backend->requires_driver_selection()) {
2298 if (get_driver() != backend->driver_name()) {
2299 change_driver = true;
2303 if (backend->use_separate_input_and_output_devices()) {
2304 if (get_input_device_name() != backend->input_device_name()) {
2305 change_device = true;
2307 if (get_output_device_name() != backend->output_device_name()) {
2308 change_device = true;
2311 if (get_device_name() != backend->device_name()) {
2312 change_device = true;
2316 if (queue_device_changed) {
2317 change_device = true;
2320 if (get_rate() != backend->sample_rate()) {
2324 if (get_buffer_size() != backend->buffer_size()) {
2325 change_bufsize = true;
2328 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2329 && get_nperiods() != backend->period_size()) {
2330 change_nperiods = true;
2333 if (get_midi_option() != backend->midi_option()) {
2337 if (backend->can_use_buffered_io()) {
2338 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2339 change_buffered_io = true;
2343 /* zero-requested channels means "all available" */
2346 ichan = backend->input_channels();
2350 ochan = backend->output_channels();
2353 if (ichan != backend->input_channels()) {
2354 change_channels = true;
2357 if (ochan != backend->output_channels()) {
2358 change_channels = true;
2361 if (get_input_latency() != backend->systemic_input_latency() ||
2362 get_output_latency() != backend->systemic_output_latency()) {
2363 change_latency = true;
2366 /* backend never started, so we have to force a group
2369 change_device = true;
2370 if (backend->requires_driver_selection()) {
2371 change_driver = true;
2374 change_bufsize = true;
2375 change_channels = true;
2376 change_latency = true;
2378 change_buffered_io = backend->can_use_buffered_io();
2379 change_channels = true;
2380 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2385 /* we have no control over the backend, meaning that we can
2386 * only possibly change sample rate and buffer size.
2390 if (get_rate() != backend->sample_rate()) {
2391 change_bufsize = true;
2394 if (get_buffer_size() != backend->buffer_size()) {
2395 change_bufsize = true;
2399 queue_device_changed = false;
2401 if (!_have_control) {
2403 /* We do not have control over the backend, so the best we can
2404 * do is try to change the sample rate and/or bufsize and get
2408 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2412 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2417 backend->set_sample_rate (get_rate());
2420 if (change_bufsize) {
2421 backend->set_buffer_size (get_buffer_size());
2425 if (ARDOUR::AudioEngine::instance()->start ()) {
2426 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2436 /* determine if we need to stop the backend before changing parameters */
2438 if (change_driver || change_device || change_channels || change_nperiods ||
2439 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2440 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2441 change_midi || change_buffered_io ||
2442 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2443 restart_required = true;
2445 restart_required = false;
2450 if (restart_required) {
2451 if (ARDOUR::AudioEngine::instance()->stop()) {
2457 if (change_driver && backend->set_driver (get_driver())) {
2458 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2461 if (backend->use_separate_input_and_output_devices()) {
2462 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2463 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2466 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2467 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2471 if (change_device && backend->set_device_name (get_device_name())) {
2472 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2476 if (change_rate && backend->set_sample_rate (get_rate())) {
2477 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2480 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2481 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2484 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2485 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2489 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2490 if (backend->set_input_channels (get_input_channels())) {
2491 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2494 if (backend->set_output_channels (get_output_channels())) {
2495 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2499 if (change_latency) {
2500 if (backend->set_systemic_input_latency (get_input_latency())) {
2501 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2504 if (backend->set_systemic_output_latency (get_output_latency())) {
2505 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2511 backend->set_midi_option (get_midi_option());
2514 if (change_buffered_io) {
2515 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2519 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2520 if (_measure_midi) {
2521 if (*p == _measure_midi) {
2522 backend->set_midi_device_enabled ((*p)->name, true);
2524 backend->set_midi_device_enabled ((*p)->name, false);
2526 if (backend->can_change_systemic_latency_when_running ()) {
2527 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2528 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2532 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2533 if (backend->can_set_systemic_midi_latencies()) {
2534 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2535 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2540 if (start || (was_running && restart_required)) {
2541 if (ARDOUR::AudioEngine::instance()->start()) {
2552 EngineControl::post_push ()
2554 /* get a pointer to the current state object, creating one if
2558 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2561 state = save_state ();
2567 states.sort (state_sort_cmp);
2571 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2572 (*i)->active = false;
2575 /* mark this one active (to be used next time the dialog is
2579 state->active = true;
2581 if (_have_control) { // XXX
2582 manage_control_app_sensitivity ();
2585 /* schedule a redisplay of MIDI ports */
2586 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2591 EngineControl::get_rate () const
2593 float r = atof (sample_rate_combo.get_active_text ());
2594 /* the string may have been translated with an abbreviation for
2595 * thousands, so use a crude heuristic to fix this.
2605 EngineControl::get_buffer_size () const
2607 string txt = buffer_size_combo.get_active_text ();
2610 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2611 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2612 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2620 EngineControl::get_nperiods () const
2622 string txt = nperiods_combo.get_active_text ();
2623 return atoi (txt.c_str());
2627 EngineControl::get_midi_option () const
2629 return midi_option_combo.get_active_text();
2633 EngineControl::get_use_buffered_io () const
2635 return use_buffered_io_button.get_active();
2639 EngineControl::get_input_channels() const
2641 if (ARDOUR::Profile->get_mixbus()) {
2642 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2643 if (!backend) return 0;
2644 return backend->input_channels();
2646 return (uint32_t) input_channels_adjustment.get_value();
2650 EngineControl::get_output_channels() const
2652 if (ARDOUR::Profile->get_mixbus()) {
2653 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2654 if (!backend) return 0;
2655 return backend->input_channels();
2657 return (uint32_t) output_channels_adjustment.get_value();
2661 EngineControl::get_input_latency() const
2663 return (uint32_t) input_latency_adjustment.get_value();
2667 EngineControl::get_output_latency() const
2669 return (uint32_t) output_latency_adjustment.get_value();
2673 EngineControl::get_backend () const
2675 return backend_combo.get_active_text ();
2679 EngineControl::get_driver () const
2681 if (driver_combo.get_parent()) {
2682 return driver_combo.get_active_text ();
2689 EngineControl::get_device_name () const
2691 return device_combo.get_active_text ();
2695 EngineControl::get_input_device_name () const
2697 return input_device_combo.get_active_text ();
2701 EngineControl::get_output_device_name () const
2703 return output_device_combo.get_active_text ();
2707 EngineControl::control_app_button_clicked ()
2709 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2715 backend->launch_control_app ();
2719 EngineControl::start_stop_button_clicked ()
2721 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2727 if (ARDOUR::AudioEngine::instance()->running()) {
2728 ARDOUR::AudioEngine::instance()->stop ();
2730 if (!ARDOUR_UI::instance()->session_loaded) {
2734 if (!ARDOUR_UI::instance()->session_loaded) {
2735 ArdourDialog::on_response (RESPONSE_OK);
2741 EngineControl::update_devices_button_clicked ()
2743 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2749 if (backend->update_devices()) {
2750 device_list_changed ();
2755 EngineControl::use_buffered_io_button_clicked ()
2757 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2763 bool set_buffered_io = !use_buffered_io_button.get_active();
2764 use_buffered_io_button.set_active (set_buffered_io);
2765 backend->set_use_buffered_io (set_buffered_io);
2769 EngineControl::manage_control_app_sensitivity ()
2771 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2777 string appname = backend->control_app_name();
2779 if (appname.empty()) {
2780 control_app_button.set_sensitive (false);
2782 control_app_button.set_sensitive (true);
2787 EngineControl::set_desired_sample_rate (uint32_t sr)
2789 _desired_sample_rate = sr;
2790 if (ARDOUR::AudioEngine::instance ()->running ()
2791 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2798 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2800 if (page_num == 0) {
2801 _measure_midi.reset();
2802 update_sensitivity ();
2805 if (page_num == midi_tab) {
2807 refresh_midi_display ();
2810 if (page_num == latency_tab) {
2813 if (ARDOUR::AudioEngine::instance()->running()) {
2818 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2820 /* save any existing latency values */
2822 uint32_t il = (uint32_t) input_latency.get_value ();
2823 uint32_t ol = (uint32_t) input_latency.get_value ();
2825 /* reset to zero so that our new test instance
2826 will be clean of any existing latency measures.
2828 NB. this should really be done by the backend
2829 when stated for latency measurement.
2832 input_latency.set_value (0);
2833 output_latency.set_value (0);
2835 push_state_to_backend (false);
2839 input_latency.set_value (il);
2840 output_latency.set_value (ol);
2843 // This should be done in push_state_to_backend()
2844 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2845 disable_latency_tab ();
2848 enable_latency_tab ();
2852 end_latency_detection ();
2853 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2858 /* latency measurement */
2861 EngineControl::check_audio_latency_measurement ()
2863 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2865 if (mtdm->resolve () < 0) {
2866 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2870 if (mtdm->get_peak () > 0.707f) {
2871 // get_peak() resets the peak-hold in the detector.
2872 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2873 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2877 if (mtdm->err () > 0.3) {
2883 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2885 if (sample_rate == 0) {
2886 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2887 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2891 int frames_total = mtdm->del();
2892 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2894 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2895 _("Detected roundtrip latency: "),
2896 frames_total, frames_total * 1000.0f/sample_rate,
2897 _("Systemic latency: "),
2898 extra, extra * 1000.0f/sample_rate);
2902 if (mtdm->err () > 0.2) {
2904 strcat (buf, _("(signal detection error)"));
2910 strcat (buf, _("(inverted - bad wiring)"));
2914 lm_results.set_markup (string_compose (results_markup, buf));
2917 have_lm_results = true;
2918 end_latency_detection ();
2919 lm_use_button.set_sensitive (true);
2927 EngineControl::check_midi_latency_measurement ()
2929 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2931 if (!mididm->have_signal () || mididm->latency () == 0) {
2932 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2937 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2939 if (sample_rate == 0) {
2940 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2941 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2945 ARDOUR::framecnt_t frames_total = mididm->latency();
2946 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2947 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2948 _("Detected roundtrip latency: "),
2949 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2950 _("Systemic latency: "),
2951 extra, extra * 1000.0f / sample_rate);
2955 if (!mididm->ok ()) {
2957 strcat (buf, _("(averaging)"));
2961 if (mididm->deviation () > 50.0) {
2963 strcat (buf, _("(too large jitter)"));
2965 } else if (mididm->deviation () > 10.0) {
2967 strcat (buf, _("(large jitter)"));
2971 have_lm_results = true;
2972 end_latency_detection ();
2973 lm_use_button.set_sensitive (true);
2974 lm_results.set_markup (string_compose (results_markup, buf));
2976 } else if (mididm->processed () > 400) {
2977 have_lm_results = false;
2978 end_latency_detection ();
2979 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2983 lm_results.set_markup (string_compose (results_markup, buf));
2989 EngineControl::start_latency_detection ()
2991 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2992 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2994 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2995 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2996 if (_measure_midi) {
2997 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2999 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3001 lm_measure_label.set_text (_("Cancel"));
3002 have_lm_results = false;
3003 lm_use_button.set_sensitive (false);
3004 lm_input_channel_combo.set_sensitive (false);
3005 lm_output_channel_combo.set_sensitive (false);
3011 EngineControl::end_latency_detection ()
3013 latency_timeout.disconnect ();
3014 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3015 lm_measure_label.set_text (_("Measure"));
3016 if (!have_lm_results) {
3017 lm_use_button.set_sensitive (false);
3019 lm_input_channel_combo.set_sensitive (true);
3020 lm_output_channel_combo.set_sensitive (true);
3025 EngineControl::latency_button_clicked ()
3028 start_latency_detection ();
3030 end_latency_detection ();
3035 EngineControl::latency_back_button_clicked ()
3037 ARDOUR::AudioEngine::instance()->stop(true);
3038 notebook.set_current_page(0);
3042 EngineControl::use_latency_button_clicked ()
3044 if (_measure_midi) {
3045 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3049 ARDOUR::framecnt_t frames_total = mididm->latency();
3050 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3051 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3052 _measure_midi->input_latency = one_way;
3053 _measure_midi->output_latency = one_way;
3054 notebook.set_current_page (midi_tab);
3056 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3062 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3063 one_way = std::max (0., one_way);
3065 input_latency_adjustment.set_value (one_way);
3066 output_latency_adjustment.set_value (one_way);
3068 /* back to settings page */
3069 notebook.set_current_page (0);
3074 EngineControl::on_delete_event (GdkEventAny* ev)
3076 if (notebook.get_current_page() == 2) {
3077 /* currently on latency tab - be sure to clean up */
3078 end_latency_detection ();
3080 return ArdourDialog::on_delete_event (ev);
3084 EngineControl::engine_running ()
3086 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3089 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3090 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3092 if (backend->can_set_period_size ()) {
3093 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3096 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3097 connect_disconnect_button.show();
3099 started_at_least_once = true;
3100 if (_have_control) {
3101 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3103 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3105 update_sensitivity();
3109 EngineControl::engine_stopped ()
3111 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3114 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3115 connect_disconnect_button.show();
3117 if (_have_control) {
3118 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3120 engine_status.set_markup(X_(""));
3123 update_sensitivity();
3127 EngineControl::device_list_changed ()
3129 if (ignore_device_changes) {
3132 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3134 midi_option_changed();
3138 EngineControl::connect_disconnect_click()
3140 if (ARDOUR::AudioEngine::instance()->running()) {
3143 if (!ARDOUR_UI::instance()->session_loaded) {
3147 if (!ARDOUR_UI::instance()->session_loaded) {
3148 ArdourDialog::on_response (RESPONSE_OK);
3154 EngineControl::calibrate_audio_latency ()
3156 _measure_midi.reset ();
3157 have_lm_results = false;
3158 lm_use_button.set_sensitive (false);
3159 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3160 notebook.set_current_page (latency_tab);
3164 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3167 have_lm_results = false;
3168 lm_use_button.set_sensitive (false);
3169 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3170 notebook.set_current_page (latency_tab);
3174 EngineControl::configure_midi_devices ()
3176 notebook.set_current_page (midi_tab);