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 (Splash::instance()) {
421 Splash::instance()->hide ();
423 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
424 // re-check _have_control (jackd running) see #6041
428 start_stop_button.grab_focus();
432 EngineControl::on_map ()
434 if (!ARDOUR_UI::instance()->session_loaded && !PublicEditor::_instance) {
435 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
436 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
437 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
439 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
441 ArdourDialog::on_map ();
445 EngineControl::try_autostart ()
447 if (!start_stop_button.get_sensitive()) {
450 if (ARDOUR::AudioEngine::instance()->running()) {
453 return start_engine ();
457 EngineControl::start_engine ()
459 if (push_state_to_backend(true) != 0) {
460 MessageDialog msg(*this,
461 ARDOUR::AudioEngine::instance()->get_last_backend_error());
469 EngineControl::stop_engine (bool for_latency)
471 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
472 MessageDialog msg(*this,
473 ARDOUR::AudioEngine::instance()->get_last_backend_error());
481 EngineControl::build_notebook ()
484 AttachOptions xopt = AttachOptions (FILL|EXPAND);
486 /* clear the table */
488 Gtkmm2ext::container_clear (basic_vbox);
489 Gtkmm2ext::container_clear (basic_packer);
491 if (control_app_button.get_parent()) {
492 control_app_button.get_parent()->remove (control_app_button);
495 label = manage (left_aligned_label (_("Audio System:")));
496 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
497 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
499 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
500 engine_status.show();
502 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
503 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
504 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
506 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
507 lm_button_audio.set_name ("generic button");
508 lm_button_audio.set_can_focus(true);
511 build_full_control_notebook ();
513 build_no_control_notebook ();
516 basic_vbox.pack_start (basic_hbox, false, false);
519 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
520 basic_vbox.show_all ();
525 EngineControl::build_full_control_notebook ()
527 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
530 using namespace Notebook_Helpers;
532 vector<string> strings;
533 AttachOptions xopt = AttachOptions (FILL|EXPAND);
534 int row = 1; // row zero == backend combo
536 /* start packing it up */
538 if (backend->requires_driver_selection()) {
539 label = manage (left_aligned_label (_("Driver:")));
540 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
541 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
545 if (backend->use_separate_input_and_output_devices()) {
546 label = manage (left_aligned_label (_("Input Device:")));
547 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
548 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
550 label = manage (left_aligned_label (_("Output Device:")));
551 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
552 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
554 // reset so it isn't used in state comparisons
555 device_combo.set_active_text ("");
557 label = manage (left_aligned_label (_("Device:")));
558 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
559 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
561 // reset these so they don't get used in state comparisons
562 input_device_combo.set_active_text ("");
563 output_device_combo.set_active_text ("");
566 label = manage (left_aligned_label (_("Sample rate:")));
567 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
568 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
572 label = manage (left_aligned_label (_("Buffer size:")));
573 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
574 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
575 buffer_size_duration_label.set_alignment (0.0); /* left-align */
576 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
578 int ctrl_btn_span = 1;
579 if (backend->can_set_period_size ()) {
581 label = manage (left_aligned_label (_("Periods:")));
582 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
583 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
587 /* button spans 2 or 3 rows */
589 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
592 input_channels.set_name ("InputChannels");
593 input_channels.set_flags (Gtk::CAN_FOCUS);
594 input_channels.set_digits (0);
595 input_channels.set_wrap (false);
596 output_channels.set_editable (true);
598 if (!ARDOUR::Profile->get_mixbus()) {
599 label = manage (left_aligned_label (_("Input Channels:")));
600 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
601 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
605 output_channels.set_name ("OutputChannels");
606 output_channels.set_flags (Gtk::CAN_FOCUS);
607 output_channels.set_digits (0);
608 output_channels.set_wrap (false);
609 output_channels.set_editable (true);
611 if (!ARDOUR::Profile->get_mixbus()) {
612 label = manage (left_aligned_label (_("Output Channels:")));
613 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
614 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
618 input_latency.set_name ("InputLatency");
619 input_latency.set_flags (Gtk::CAN_FOCUS);
620 input_latency.set_digits (0);
621 input_latency.set_wrap (false);
622 input_latency.set_editable (true);
624 label = manage (left_aligned_label (_("Hardware input latency:")));
625 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
626 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
627 label = manage (left_aligned_label (_("samples")));
628 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
631 output_latency.set_name ("OutputLatency");
632 output_latency.set_flags (Gtk::CAN_FOCUS);
633 output_latency.set_digits (0);
634 output_latency.set_wrap (false);
635 output_latency.set_editable (true);
637 label = manage (left_aligned_label (_("Hardware output latency:")));
638 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
639 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
640 label = manage (left_aligned_label (_("samples")));
641 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
643 /* button spans 2 rows */
645 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
648 label = manage (left_aligned_label (_("MIDI System:")));
649 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
650 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
651 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
656 EngineControl::build_no_control_notebook ()
658 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
661 using namespace Notebook_Helpers;
663 vector<string> strings;
664 AttachOptions xopt = AttachOptions (FILL|EXPAND);
665 int row = 1; // row zero == backend combo
666 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
668 label = manage (new Label);
669 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
670 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
673 if (backend->can_change_sample_rate_when_running()) {
674 label = manage (left_aligned_label (_("Sample rate:")));
675 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
676 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
680 if (backend->can_change_buffer_size_when_running()) {
681 label = manage (left_aligned_label (_("Buffer size:")));
682 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
683 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
684 buffer_size_duration_label.set_alignment (0.0); /* left-align */
685 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
689 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
693 EngineControl::~EngineControl ()
695 ignore_changes = true;
699 EngineControl::disable_latency_tab ()
701 vector<string> empty;
702 set_popdown_strings (lm_output_channel_combo, empty);
703 set_popdown_strings (lm_input_channel_combo, empty);
704 lm_measure_button.set_sensitive (false);
705 lm_use_button.set_sensitive (false);
709 EngineControl::enable_latency_tab ()
711 vector<string> outputs;
712 vector<string> inputs;
714 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
715 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
716 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
718 if (!ARDOUR::AudioEngine::instance()->running()) {
719 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
720 notebook.set_current_page (0);
724 else if (inputs.empty() || outputs.empty()) {
725 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
726 notebook.set_current_page (0);
731 lm_back_button_signal.disconnect();
733 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
736 lm_back_button_signal = lm_back_button.signal_clicked().connect(
737 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
741 set_popdown_strings (lm_output_channel_combo, outputs);
742 lm_output_channel_combo.set_active_text (outputs.front());
743 lm_output_channel_combo.set_sensitive (true);
745 set_popdown_strings (lm_input_channel_combo, inputs);
746 lm_input_channel_combo.set_active_text (inputs.front());
747 lm_input_channel_combo.set_sensitive (true);
749 lm_measure_button.set_sensitive (true);
753 EngineControl::setup_midi_tab_for_backend ()
755 string backend = backend_combo.get_active_text ();
757 Gtkmm2ext::container_clear (midi_vbox);
759 midi_vbox.set_border_width (12);
760 midi_device_table.set_border_width (12);
762 if (backend == "JACK") {
763 setup_midi_tab_for_jack ();
766 midi_vbox.pack_start (midi_device_table, true, true);
767 midi_vbox.pack_start (midi_back_button, false, false);
768 midi_vbox.show_all ();
772 EngineControl::update_sensitivity ()
774 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
776 start_stop_button.set_sensitive (false);
781 size_t devices_available = 0;
783 if (backend->use_separate_input_and_output_devices ()) {
784 devices_available += get_popdown_string_count (input_device_combo);
785 devices_available += get_popdown_string_count (output_device_combo);
787 devices_available += get_popdown_string_count (device_combo);
790 if (devices_available == 0) {
792 input_latency.set_sensitive (false);
793 output_latency.set_sensitive (false);
794 input_channels.set_sensitive (false);
795 output_channels.set_sensitive (false);
797 input_latency.set_sensitive (true);
798 output_latency.set_sensitive (true);
799 input_channels.set_sensitive (true);
800 output_channels.set_sensitive (true);
803 if (get_popdown_string_count (buffer_size_combo) > 0) {
804 if (!ARDOUR::AudioEngine::instance()->running()) {
805 buffer_size_combo.set_sensitive (valid);
806 } else if (backend->can_change_sample_rate_when_running()) {
807 buffer_size_combo.set_sensitive (valid || !_have_control);
811 * Currently there is no way to manually stop the
812 * engine in order to re-configure it.
813 * This needs to remain sensitive for now.
815 * (it's also handy to implicily
816 * re-start the engine)
818 buffer_size_combo.set_sensitive (true);
820 buffer_size_combo.set_sensitive (false);
824 buffer_size_combo.set_sensitive (false);
828 if (get_popdown_string_count (sample_rate_combo) > 0) {
829 bool allow_to_set_rate = false;
830 if (!ARDOUR::AudioEngine::instance()->running()) {
831 if (!ARDOUR_UI::instance()->session_loaded) {
832 // engine is not running, no session loaded -> anything goes.
833 allow_to_set_rate = true;
834 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
835 // only allow to change if the current setting is not the native session rate.
836 allow_to_set_rate = true;
839 sample_rate_combo.set_sensitive (allow_to_set_rate);
841 sample_rate_combo.set_sensitive (false);
845 if (get_popdown_string_count (nperiods_combo) > 0) {
846 if (!ARDOUR::AudioEngine::instance()->running()) {
847 nperiods_combo.set_sensitive (true);
849 nperiods_combo.set_sensitive (false);
852 nperiods_combo.set_sensitive (false);
856 start_stop_button.set_sensitive(true);
857 start_stop_button.show();
858 if (ARDOUR::AudioEngine::instance()->running()) {
859 start_stop_button.set_text("Stop");
860 update_devices_button.set_sensitive(false);
861 use_buffered_io_button.set_sensitive(false);
863 if (backend->can_request_update_devices()) {
864 update_devices_button.show();
866 update_devices_button.hide();
868 if (backend->can_use_buffered_io()) {
869 use_buffered_io_button.show();
871 use_buffered_io_button.hide();
873 start_stop_button.set_text("Start");
874 update_devices_button.set_sensitive(true);
875 use_buffered_io_button.set_sensitive(true);
878 update_devices_button.set_sensitive(false);
879 update_devices_button.hide();
880 use_buffered_io_button.set_sensitive(false);
881 use_buffered_io_button.hide();
882 start_stop_button.set_sensitive(false);
883 start_stop_button.hide();
886 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
887 input_device_combo.set_sensitive (false);
888 output_device_combo.set_sensitive (false);
889 device_combo.set_sensitive (false);
890 driver_combo.set_sensitive (false);
892 input_device_combo.set_sensitive (true);
893 output_device_combo.set_sensitive (true);
894 device_combo.set_sensitive (true);
895 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
896 driver_combo.set_sensitive (true);
898 driver_combo.set_sensitive (false);
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) {
1804 EngineControl::state_sort_cmp (const State &a, const State &b) {
1808 else if (b->active) {
1812 return a->lru < b->lru;
1816 EngineControl::State
1817 EngineControl::save_state ()
1821 if (!_have_control) {
1822 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1824 state->lru = time (NULL) ;
1827 state.reset(new StateStruct);
1828 state->backend = get_backend ();
1830 state.reset(new StateStruct);
1831 store_state (state);
1834 for (StateList::iterator i = states.begin(); i != states.end();) {
1835 if (equivalent_states (*i, state)) {
1836 i = states.erase(i);
1842 states.push_back (state);
1844 states.sort (state_sort_cmp);
1850 EngineControl::store_state (State state)
1852 state->backend = get_backend ();
1853 state->driver = get_driver ();
1854 state->device = get_device_name ();
1855 state->input_device = get_input_device_name ();
1856 state->output_device = get_output_device_name ();
1857 state->sample_rate = get_rate ();
1858 state->buffer_size = get_buffer_size ();
1859 state->n_periods = get_nperiods ();
1860 state->input_latency = get_input_latency ();
1861 state->output_latency = get_output_latency ();
1862 state->input_channels = get_input_channels ();
1863 state->output_channels = get_output_channels ();
1864 state->midi_option = get_midi_option ();
1865 state->midi_devices = _midi_devices;
1866 state->use_buffered_io = get_use_buffered_io ();
1867 state->lru = time (NULL) ;
1871 EngineControl::maybe_display_saved_state ()
1873 if (!_have_control) {
1877 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1880 DEBUG_ECONTROL ("Restoring saved state");
1881 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1883 if (!_desired_sample_rate) {
1884 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1886 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1888 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1889 /* call this explicitly because we're ignoring changes to
1890 the controls at this point.
1892 show_buffer_duration ();
1893 input_latency.set_value (state->input_latency);
1894 output_latency.set_value (state->output_latency);
1896 use_buffered_io_button.set_active (state->use_buffered_io);
1898 if (!state->midi_option.empty()) {
1899 midi_option_combo.set_active_text (state->midi_option);
1900 _midi_devices = state->midi_devices;
1903 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1908 EngineControl::get_state ()
1912 XMLNode* root = new XMLNode ("AudioMIDISetup");
1915 if (!states.empty()) {
1916 XMLNode* state_nodes = new XMLNode ("EngineStates");
1918 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1920 XMLNode* node = new XMLNode ("State");
1922 node->add_property ("backend", (*i)->backend);
1923 node->add_property ("driver", (*i)->driver);
1924 node->add_property ("device", (*i)->device);
1925 node->add_property ("input-device", (*i)->input_device);
1926 node->add_property ("output-device", (*i)->output_device);
1927 node->add_property ("sample-rate", (*i)->sample_rate);
1928 node->add_property ("buffer-size", (*i)->buffer_size);
1929 node->add_property ("n-periods", (*i)->n_periods);
1930 node->add_property ("input-latency", (*i)->input_latency);
1931 node->add_property ("output-latency", (*i)->output_latency);
1932 node->add_property ("input-channels", (*i)->input_channels);
1933 node->add_property ("output-channels", (*i)->output_channels);
1934 node->add_property ("active", (*i)->active ? "yes" : "no");
1935 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1936 node->add_property ("midi-option", (*i)->midi_option);
1937 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1939 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1940 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1941 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1942 midi_device_stuff->add_property (X_("name"), (*p)->name);
1943 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1944 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1945 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1946 midi_devices->add_child_nocopy (*midi_device_stuff);
1948 node->add_child_nocopy (*midi_devices);
1950 state_nodes->add_child_nocopy (*node);
1953 root->add_child_nocopy (*state_nodes);
1960 EngineControl::set_default_state ()
1962 vector<string> backend_names;
1963 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1965 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1966 backend_names.push_back ((*b)->name);
1968 backend_combo.set_active_text (backend_names.front());
1970 // We could set default backends per platform etc here
1976 EngineControl::set_state (const XMLNode& root)
1978 XMLNodeList clist, cclist;
1979 XMLNodeConstIterator citer, cciter;
1980 XMLNode const * child;
1981 XMLNode const * grandchild;
1982 XMLProperty const * prop = NULL;
1984 if (root.name() != "AudioMIDISetup") {
1988 clist = root.children();
1992 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1996 if (child->name() != "EngineStates") {
2000 cclist = child->children();
2002 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2003 State state (new StateStruct);
2005 grandchild = *cciter;
2007 if (grandchild->name() != "State") {
2011 if ((prop = grandchild->property ("backend")) == 0) {
2014 state->backend = prop->value ();
2016 if ((prop = grandchild->property ("driver")) == 0) {
2019 state->driver = prop->value ();
2021 if ((prop = grandchild->property ("device")) == 0) {
2024 state->device = prop->value ();
2026 if ((prop = grandchild->property ("input-device")) == 0) {
2029 state->input_device = prop->value ();
2031 if ((prop = grandchild->property ("output-device")) == 0) {
2034 state->output_device = prop->value ();
2036 if ((prop = grandchild->property ("sample-rate")) == 0) {
2039 state->sample_rate = atof (prop->value ());
2041 if ((prop = grandchild->property ("buffer-size")) == 0) {
2044 state->buffer_size = atoi (prop->value ());
2046 if ((prop = grandchild->property ("n-periods")) == 0) {
2047 // optional (new value in 4.5)
2048 state->n_periods = 0;
2050 state->n_periods = atoi (prop->value ());
2053 if ((prop = grandchild->property ("input-latency")) == 0) {
2056 state->input_latency = atoi (prop->value ());
2058 if ((prop = grandchild->property ("output-latency")) == 0) {
2061 state->output_latency = atoi (prop->value ());
2063 if ((prop = grandchild->property ("input-channels")) == 0) {
2066 state->input_channels = atoi (prop->value ());
2068 if ((prop = grandchild->property ("output-channels")) == 0) {
2071 state->output_channels = atoi (prop->value ());
2073 if ((prop = grandchild->property ("active")) == 0) {
2076 state->active = string_is_affirmative (prop->value ());
2078 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2081 state->use_buffered_io = string_is_affirmative (prop->value ());
2083 if ((prop = grandchild->property ("midi-option")) == 0) {
2086 state->midi_option = prop->value ();
2088 state->midi_devices.clear();
2090 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2091 const XMLNodeList mnc = midinode->children();
2092 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2093 if ((*n)->property (X_("name")) == 0
2094 || (*n)->property (X_("enabled")) == 0
2095 || (*n)->property (X_("input-latency")) == 0
2096 || (*n)->property (X_("output-latency")) == 0
2101 MidiDeviceSettings ptr (new MidiDeviceSetting(
2102 (*n)->property (X_("name"))->value (),
2103 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2104 atoi ((*n)->property (X_("input-latency"))->value ()),
2105 atoi ((*n)->property (X_("output-latency"))->value ())
2107 state->midi_devices.push_back (ptr);
2111 if ((prop = grandchild->property ("lru"))) {
2112 state->lru = atoi (prop->value ());
2116 /* remove accumulated duplicates (due to bug in ealier version)
2117 * this can be removed again before release
2119 for (StateList::iterator i = states.begin(); i != states.end();) {
2120 if ((*i)->backend == state->backend &&
2121 (*i)->driver == state->driver &&
2122 (*i)->device == state->device) {
2123 i = states.erase(i);
2130 states.push_back (state);
2134 /* now see if there was an active state and switch the setup to it */
2136 // purge states of backend that are not available in this built
2137 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2138 vector<std::string> backend_names;
2140 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2141 backend_names.push_back((*i)->name);
2143 for (StateList::iterator i = states.begin(); i != states.end();) {
2144 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2145 i = states.erase(i);
2151 states.sort (state_sort_cmp);
2153 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2156 return set_current_state (*i);
2163 EngineControl::set_current_state (const State& state)
2165 DEBUG_ECONTROL ("set_current_state");
2167 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2169 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2170 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2171 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2172 // this shouldn't happen as the invalid backend names should have been
2173 // removed from the list of states.
2177 // now reflect the change in the backend in the GUI so backend_changed will
2178 // do the right thing
2179 backend_combo.set_active_text (state->backend);
2181 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2183 // we don't have control don't restore state
2188 if (!state->driver.empty ()) {
2189 if (!backend->requires_driver_selection ()) {
2190 DEBUG_ECONTROL ("Backend should require driver selection");
2191 // A backend has changed from having driver selection to not having
2192 // it or someone has been manually editing a config file and messed
2197 if (backend->set_driver (state->driver) != 0) {
2198 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2199 // Driver names for a backend have changed and the name in the
2200 // config file is now invalid or support for driver is no longer
2201 // included in the backend
2204 // no need to set the driver_combo as backend_changed will use
2205 // backend->driver_name to set the active driver
2208 if (!state->device.empty ()) {
2209 if (backend->set_device_name (state->device) != 0) {
2211 string_compose ("Unable to set device name %1", state->device));
2212 // device is no longer available on the system
2215 // no need to set active device as it will be picked up in
2216 // via backend_changed ()/set_device_popdown_strings
2219 // backend supports separate input/output devices
2220 if (backend->set_input_device_name (state->input_device) != 0) {
2221 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2222 state->input_device));
2223 // input device is no longer available on the system
2227 if (backend->set_output_device_name (state->output_device) != 0) {
2228 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2229 state->input_device));
2230 // output device is no longer available on the system
2233 // no need to set active devices as it will be picked up in via
2234 // backend_changed ()/set_*_device_popdown_strings
2239 // Now restore the state of the rest of the controls
2241 // We don't use a SignalBlocker as set_current_state is currently only
2242 // called from set_state before any signals are connected. If at some point
2243 // a more general named state mechanism is implemented and
2244 // set_current_state is called while signals are connected then a
2245 // SignalBlocker will need to be instantiated before setting these.
2247 device_combo.set_active_text (state->device);
2248 input_device_combo.set_active_text (state->input_device);
2249 output_device_combo.set_active_text (state->output_device);
2250 if (!_desired_sample_rate) {
2251 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2253 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2254 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2255 input_latency.set_value (state->input_latency);
2256 output_latency.set_value (state->output_latency);
2257 midi_option_combo.set_active_text (state->midi_option);
2258 use_buffered_io_button.set_active (state->use_buffered_io);
2263 EngineControl::push_state_to_backend (bool start)
2265 DEBUG_ECONTROL ("push_state_to_backend");
2266 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2267 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2273 /* figure out what is going to change */
2275 bool restart_required = false;
2276 bool was_running = ARDOUR::AudioEngine::instance()->running();
2277 bool change_driver = false;
2278 bool change_device = false;
2279 bool change_rate = false;
2280 bool change_bufsize = false;
2281 bool change_nperiods = false;
2282 bool change_latency = false;
2283 bool change_channels = false;
2284 bool change_midi = false;
2285 bool change_buffered_io = false;
2287 uint32_t ochan = get_output_channels ();
2288 uint32_t ichan = get_input_channels ();
2290 if (_have_control) {
2292 if (started_at_least_once) {
2294 /* we can control the backend */
2296 if (backend->requires_driver_selection()) {
2297 if (get_driver() != backend->driver_name()) {
2298 change_driver = true;
2302 if (backend->use_separate_input_and_output_devices()) {
2303 if (get_input_device_name() != backend->input_device_name()) {
2304 change_device = true;
2306 if (get_output_device_name() != backend->output_device_name()) {
2307 change_device = true;
2310 if (get_device_name() != backend->device_name()) {
2311 change_device = true;
2315 if (queue_device_changed) {
2316 change_device = true;
2319 if (get_rate() != backend->sample_rate()) {
2323 if (get_buffer_size() != backend->buffer_size()) {
2324 change_bufsize = true;
2327 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2328 && get_nperiods() != backend->period_size()) {
2329 change_nperiods = true;
2332 if (get_midi_option() != backend->midi_option()) {
2336 if (backend->can_use_buffered_io()) {
2337 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2338 change_buffered_io = true;
2342 /* zero-requested channels means "all available" */
2345 ichan = backend->input_channels();
2349 ochan = backend->output_channels();
2352 if (ichan != backend->input_channels()) {
2353 change_channels = true;
2356 if (ochan != backend->output_channels()) {
2357 change_channels = true;
2360 if (get_input_latency() != backend->systemic_input_latency() ||
2361 get_output_latency() != backend->systemic_output_latency()) {
2362 change_latency = true;
2365 /* backend never started, so we have to force a group
2368 change_device = true;
2369 if (backend->requires_driver_selection()) {
2370 change_driver = true;
2373 change_bufsize = true;
2374 change_channels = true;
2375 change_latency = true;
2377 change_buffered_io = backend->can_use_buffered_io();
2378 change_channels = true;
2379 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2384 /* we have no control over the backend, meaning that we can
2385 * only possibly change sample rate and buffer size.
2389 if (get_rate() != backend->sample_rate()) {
2390 change_bufsize = true;
2393 if (get_buffer_size() != backend->buffer_size()) {
2394 change_bufsize = true;
2398 queue_device_changed = false;
2400 if (!_have_control) {
2402 /* We do not have control over the backend, so the best we can
2403 * do is try to change the sample rate and/or bufsize and get
2407 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2411 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2416 backend->set_sample_rate (get_rate());
2419 if (change_bufsize) {
2420 backend->set_buffer_size (get_buffer_size());
2424 if (ARDOUR::AudioEngine::instance()->start ()) {
2425 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2435 /* determine if we need to stop the backend before changing parameters */
2437 if (change_driver || change_device || change_channels || change_nperiods ||
2438 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2439 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2440 change_midi || change_buffered_io ||
2441 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2442 restart_required = true;
2444 restart_required = false;
2449 if (restart_required) {
2450 if (ARDOUR::AudioEngine::instance()->stop()) {
2456 if (change_driver && backend->set_driver (get_driver())) {
2457 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2460 if (backend->use_separate_input_and_output_devices()) {
2461 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2462 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2465 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2466 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2470 if (change_device && backend->set_device_name (get_device_name())) {
2471 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2475 if (change_rate && backend->set_sample_rate (get_rate())) {
2476 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2479 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2480 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2483 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2484 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2488 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2489 if (backend->set_input_channels (get_input_channels())) {
2490 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2493 if (backend->set_output_channels (get_output_channels())) {
2494 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2498 if (change_latency) {
2499 if (backend->set_systemic_input_latency (get_input_latency())) {
2500 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2503 if (backend->set_systemic_output_latency (get_output_latency())) {
2504 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2510 backend->set_midi_option (get_midi_option());
2513 if (change_buffered_io) {
2514 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2518 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2519 if (_measure_midi) {
2520 if (*p == _measure_midi) {
2521 backend->set_midi_device_enabled ((*p)->name, true);
2523 backend->set_midi_device_enabled ((*p)->name, false);
2525 if (backend->can_change_systemic_latency_when_running ()) {
2526 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2527 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2531 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2532 if (backend->can_set_systemic_midi_latencies()) {
2533 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2534 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2539 if (start || (was_running && restart_required)) {
2540 if (ARDOUR::AudioEngine::instance()->start()) {
2551 EngineControl::post_push ()
2553 /* get a pointer to the current state object, creating one if
2557 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2560 state = save_state ();
2566 states.sort (state_sort_cmp);
2570 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2571 (*i)->active = false;
2574 /* mark this one active (to be used next time the dialog is
2578 state->active = true;
2580 if (_have_control) { // XXX
2581 manage_control_app_sensitivity ();
2584 /* schedule a redisplay of MIDI ports */
2585 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2590 EngineControl::get_rate () const
2592 float r = atof (sample_rate_combo.get_active_text ());
2593 /* the string may have been translated with an abbreviation for
2594 * thousands, so use a crude heuristic to fix this.
2604 EngineControl::get_buffer_size () const
2606 string txt = buffer_size_combo.get_active_text ();
2609 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2610 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2611 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2619 EngineControl::get_nperiods () const
2621 string txt = nperiods_combo.get_active_text ();
2622 return atoi (txt.c_str());
2626 EngineControl::get_midi_option () const
2628 return midi_option_combo.get_active_text();
2632 EngineControl::get_use_buffered_io () const
2634 return use_buffered_io_button.get_active();
2638 EngineControl::get_input_channels() const
2640 if (ARDOUR::Profile->get_mixbus()) {
2641 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2642 if (!backend) return 0;
2643 return backend->input_channels();
2645 return (uint32_t) input_channels_adjustment.get_value();
2649 EngineControl::get_output_channels() const
2651 if (ARDOUR::Profile->get_mixbus()) {
2652 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2653 if (!backend) return 0;
2654 return backend->input_channels();
2656 return (uint32_t) output_channels_adjustment.get_value();
2660 EngineControl::get_input_latency() const
2662 return (uint32_t) input_latency_adjustment.get_value();
2666 EngineControl::get_output_latency() const
2668 return (uint32_t) output_latency_adjustment.get_value();
2672 EngineControl::get_backend () const
2674 return backend_combo.get_active_text ();
2678 EngineControl::get_driver () const
2680 if (driver_combo.get_parent()) {
2681 return driver_combo.get_active_text ();
2688 EngineControl::get_device_name () const
2690 return device_combo.get_active_text ();
2694 EngineControl::get_input_device_name () const
2696 return input_device_combo.get_active_text ();
2700 EngineControl::get_output_device_name () const
2702 return output_device_combo.get_active_text ();
2706 EngineControl::control_app_button_clicked ()
2708 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2714 backend->launch_control_app ();
2718 EngineControl::start_stop_button_clicked ()
2720 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2726 if (ARDOUR::AudioEngine::instance()->running()) {
2727 ARDOUR::AudioEngine::instance()->stop ();
2729 if (!ARDOUR_UI::instance()->session_loaded) {
2733 if (!ARDOUR_UI::instance()->session_loaded) {
2734 ArdourDialog::on_response (RESPONSE_OK);
2735 if (Splash::instance()) {
2736 Splash::instance()->pop_front ();
2743 EngineControl::update_devices_button_clicked ()
2745 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2751 if (backend->update_devices()) {
2752 device_list_changed ();
2757 EngineControl::use_buffered_io_button_clicked ()
2759 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2765 bool set_buffered_io = !use_buffered_io_button.get_active();
2766 use_buffered_io_button.set_active (set_buffered_io);
2767 backend->set_use_buffered_io (set_buffered_io);
2771 EngineControl::manage_control_app_sensitivity ()
2773 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2779 string appname = backend->control_app_name();
2781 if (appname.empty()) {
2782 control_app_button.set_sensitive (false);
2784 control_app_button.set_sensitive (true);
2789 EngineControl::set_desired_sample_rate (uint32_t sr)
2791 _desired_sample_rate = sr;
2792 if (ARDOUR::AudioEngine::instance ()->running ()
2793 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2800 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2802 if (page_num == 0) {
2803 _measure_midi.reset();
2804 update_sensitivity ();
2807 if (page_num == midi_tab) {
2809 refresh_midi_display ();
2812 if (page_num == latency_tab) {
2815 if (ARDOUR::AudioEngine::instance()->running()) {
2820 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2822 /* save any existing latency values */
2824 uint32_t il = (uint32_t) input_latency.get_value ();
2825 uint32_t ol = (uint32_t) input_latency.get_value ();
2827 /* reset to zero so that our new test instance
2828 will be clean of any existing latency measures.
2830 NB. this should really be done by the backend
2831 when stated for latency measurement.
2834 input_latency.set_value (0);
2835 output_latency.set_value (0);
2837 push_state_to_backend (false);
2841 input_latency.set_value (il);
2842 output_latency.set_value (ol);
2845 // This should be done in push_state_to_backend()
2846 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2847 disable_latency_tab ();
2850 enable_latency_tab ();
2854 end_latency_detection ();
2855 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2860 /* latency measurement */
2863 EngineControl::check_audio_latency_measurement ()
2865 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2867 if (mtdm->resolve () < 0) {
2868 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2872 if (mtdm->get_peak () > 0.707f) {
2873 // get_peak() resets the peak-hold in the detector.
2874 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2875 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2879 if (mtdm->err () > 0.3) {
2885 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2887 if (sample_rate == 0) {
2888 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2889 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2893 int frames_total = mtdm->del();
2894 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2896 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2897 _("Detected roundtrip latency: "),
2898 frames_total, frames_total * 1000.0f/sample_rate,
2899 _("Systemic latency: "),
2900 extra, extra * 1000.0f/sample_rate);
2904 if (mtdm->err () > 0.2) {
2906 strcat (buf, _("(signal detection error)"));
2912 strcat (buf, _("(inverted - bad wiring)"));
2916 lm_results.set_markup (string_compose (results_markup, buf));
2919 have_lm_results = true;
2920 end_latency_detection ();
2921 lm_use_button.set_sensitive (true);
2929 EngineControl::check_midi_latency_measurement ()
2931 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2933 if (!mididm->have_signal () || mididm->latency () == 0) {
2934 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2939 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2941 if (sample_rate == 0) {
2942 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2943 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2947 ARDOUR::framecnt_t frames_total = mididm->latency();
2948 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2949 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2950 _("Detected roundtrip latency: "),
2951 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2952 _("Systemic latency: "),
2953 extra, extra * 1000.0f / sample_rate);
2957 if (!mididm->ok ()) {
2959 strcat (buf, _("(averaging)"));
2963 if (mididm->deviation () > 50.0) {
2965 strcat (buf, _("(too large jitter)"));
2967 } else if (mididm->deviation () > 10.0) {
2969 strcat (buf, _("(large jitter)"));
2973 have_lm_results = true;
2974 end_latency_detection ();
2975 lm_use_button.set_sensitive (true);
2976 lm_results.set_markup (string_compose (results_markup, buf));
2978 } else if (mididm->processed () > 400) {
2979 have_lm_results = false;
2980 end_latency_detection ();
2981 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2985 lm_results.set_markup (string_compose (results_markup, buf));
2991 EngineControl::start_latency_detection ()
2993 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2994 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2996 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2997 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2998 if (_measure_midi) {
2999 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3001 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3003 lm_measure_label.set_text (_("Cancel"));
3004 have_lm_results = false;
3005 lm_use_button.set_sensitive (false);
3006 lm_input_channel_combo.set_sensitive (false);
3007 lm_output_channel_combo.set_sensitive (false);
3013 EngineControl::end_latency_detection ()
3015 latency_timeout.disconnect ();
3016 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3017 lm_measure_label.set_text (_("Measure"));
3018 if (!have_lm_results) {
3019 lm_use_button.set_sensitive (false);
3021 lm_input_channel_combo.set_sensitive (true);
3022 lm_output_channel_combo.set_sensitive (true);
3027 EngineControl::latency_button_clicked ()
3030 start_latency_detection ();
3032 end_latency_detection ();
3037 EngineControl::latency_back_button_clicked ()
3039 ARDOUR::AudioEngine::instance()->stop(true);
3040 notebook.set_current_page(0);
3044 EngineControl::use_latency_button_clicked ()
3046 if (_measure_midi) {
3047 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3051 ARDOUR::framecnt_t frames_total = mididm->latency();
3052 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3053 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3054 _measure_midi->input_latency = one_way;
3055 _measure_midi->output_latency = one_way;
3056 notebook.set_current_page (midi_tab);
3058 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3064 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3065 one_way = std::max (0., one_way);
3067 input_latency_adjustment.set_value (one_way);
3068 output_latency_adjustment.set_value (one_way);
3070 /* back to settings page */
3071 notebook.set_current_page (0);
3076 EngineControl::on_delete_event (GdkEventAny* ev)
3078 if (notebook.get_current_page() == 2) {
3079 /* currently on latency tab - be sure to clean up */
3080 end_latency_detection ();
3082 return ArdourDialog::on_delete_event (ev);
3086 EngineControl::engine_running ()
3088 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3091 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3092 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3094 if (backend->can_set_period_size ()) {
3095 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3098 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3099 connect_disconnect_button.show();
3101 started_at_least_once = true;
3102 if (_have_control) {
3103 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3105 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3107 update_sensitivity();
3111 EngineControl::engine_stopped ()
3113 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3116 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3117 connect_disconnect_button.show();
3119 if (_have_control) {
3120 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3122 engine_status.set_markup(X_(""));
3125 update_sensitivity();
3129 EngineControl::device_list_changed ()
3131 if (ignore_device_changes) {
3134 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3136 midi_option_changed();
3140 EngineControl::connect_disconnect_click()
3142 if (ARDOUR::AudioEngine::instance()->running()) {
3145 if (!ARDOUR_UI::instance()->session_loaded) {
3149 if (!ARDOUR_UI::instance()->session_loaded) {
3150 ArdourDialog::on_response (RESPONSE_OK);
3151 if (Splash::instance()) {
3152 Splash::instance()->pop_front ();
3159 EngineControl::calibrate_audio_latency ()
3161 _measure_midi.reset ();
3162 have_lm_results = false;
3163 lm_use_button.set_sensitive (false);
3164 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3165 notebook.set_current_page (latency_tab);
3169 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3172 have_lm_results = false;
3173 lm_use_button.set_sensitive (false);
3174 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3175 notebook.set_current_page (latency_tab);
3179 EngineControl::configure_midi_devices ()
3181 notebook.set_current_page (midi_tab);