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"
62 using namespace Gtkmm2ext;
65 using namespace ARDOUR_UI_UTILS;
67 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
69 static const unsigned int midi_tab = 2;
70 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
72 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
74 EngineControl::EngineControl ()
75 : ArdourDialog (_("Audio/MIDI Setup"))
78 , input_latency_adjustment (0, 0, 99999, 1)
79 , input_latency (input_latency_adjustment)
80 , output_latency_adjustment (0, 0, 99999, 1)
81 , output_latency (output_latency_adjustment)
82 , input_channels_adjustment (0, 0, 256, 1)
83 , input_channels (input_channels_adjustment)
84 , output_channels_adjustment (0, 0, 256, 1)
85 , output_channels (output_channels_adjustment)
86 , ports_adjustment (128, 8, 1024, 1, 16)
87 , ports_spinner (ports_adjustment)
88 , control_app_button (_("Device Control Panel"))
89 , midi_devices_button (_("Midi Device Setup"))
90 , start_stop_button (_("Stop"))
91 , update_devices_button (_("Refresh Devices"))
92 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
93 , lm_measure_label (_("Measure"))
94 , lm_use_button (_("Use results"))
95 , lm_back_button (_("Back to settings ... (ignore results)"))
96 , lm_button_audio (_("Calibrate Audio"))
98 , have_lm_results (false)
100 , midi_back_button (_("Back to settings"))
102 , ignore_device_changes (0)
103 , _desired_sample_rate (0)
104 , started_at_least_once (false)
105 , queue_device_changed (false)
106 , _have_control (true)
109 using namespace Notebook_Helpers;
110 vector<string> backend_names;
112 AttachOptions xopt = AttachOptions (FILL|EXPAND);
115 set_name (X_("AudioMIDISetup"));
117 if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
118 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
120 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
123 /* the backend combo is the one thing that is ALWAYS visible */
125 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
127 if (backends.empty()) {
128 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));
130 throw failed_constructor ();
133 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
134 backend_names.push_back ((*b)->name);
137 set_popdown_strings (backend_combo, backend_names);
139 /* setup basic packing characteristics for the table used on the main
140 * tab of the notebook
143 basic_packer.set_spacings (6);
144 basic_packer.set_border_width (12);
145 basic_packer.set_homogeneous (false);
149 basic_hbox.pack_start (basic_packer, false, false);
151 /* latency measurement tab */
153 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
156 lm_table.set_row_spacings (12);
157 lm_table.set_col_spacings (6);
158 lm_table.set_homogeneous (false);
160 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
163 lm_preamble.set_width_chars (60);
164 lm_preamble.set_line_wrap (true);
165 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
167 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
170 Gtk::Label* preamble;
171 preamble = manage (new Label);
172 preamble->set_width_chars (60);
173 preamble->set_line_wrap (true);
174 preamble->set_markup (_("Select two channels below and connect them using a cable."));
176 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
179 label = manage (new Label (_("Output channel")));
180 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
182 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
183 misc_align->add (lm_output_channel_combo);
184 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
187 label = manage (new Label (_("Input channel")));
188 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
190 misc_align = manage (new Alignment (0.0, 0.5));
191 misc_align->add (lm_input_channel_combo);
192 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
195 lm_measure_label.set_padding (10, 10);
196 lm_measure_button.add (lm_measure_label);
197 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
198 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
199 lm_back_button_signal = lm_back_button.signal_clicked().connect(
200 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
202 lm_use_button.set_sensitive (false);
204 /* Increase the default spacing around the labels of these three
210 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
211 l->set_padding (10, 10);
214 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
215 l->set_padding (10, 10);
218 preamble = manage (new Label);
219 preamble->set_width_chars (60);
220 preamble->set_line_wrap (true);
221 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
222 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 preamble = manage (new Label);
226 preamble->set_width_chars (60);
227 preamble->set_line_wrap (true);
228 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
229 lm_table.attach (*preamble, 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_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
236 ++row; // skip a row in the table
237 ++row; // skip a row in the table
239 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
240 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
241 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
243 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
245 lm_vbox.set_border_width (12);
246 lm_vbox.pack_start (lm_table, false, false);
248 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
252 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
253 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
254 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
255 notebook.set_border_width (12);
257 notebook.set_show_tabs (false);
258 notebook.show_all ();
260 notebook.set_name ("SettingsNotebook");
262 /* packup the notebook */
264 get_vbox()->set_border_width (12);
265 get_vbox()->pack_start (notebook);
267 /* need a special function to print "all available channels" when the
268 * channel counts hit zero.
271 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
272 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
274 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
275 midi_devices_button.set_name ("generic button");
276 midi_devices_button.set_can_focus(true);
278 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
279 control_app_button.set_name ("generic button");
280 control_app_button.set_can_focus(true);
281 manage_control_app_sensitivity ();
283 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
284 start_stop_button.set_sensitive (false);
285 start_stop_button.set_name ("generic button");
286 start_stop_button.set_can_focus(true);
287 start_stop_button.set_can_default(true);
289 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
290 update_devices_button.set_sensitive (false);
291 update_devices_button.set_name ("generic button");
292 update_devices_button.set_can_focus(true);
294 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
295 use_buffered_io_button.set_sensitive (false);
296 use_buffered_io_button.set_name ("generic button");
297 use_buffered_io_button.set_can_focus(true);
299 /* Pick up any existing audio setup configuration, if appropriate */
301 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
303 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
304 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
305 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
306 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
309 if (!set_state (*audio_setup)) {
310 set_default_state ();
313 set_default_state ();
316 update_sensitivity ();
317 connect_changed_signals ();
319 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
321 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
323 connect_disconnect_button.set_no_show_all();
324 use_buffered_io_button.set_no_show_all();
325 update_devices_button.set_no_show_all();
326 start_stop_button.set_no_show_all();
327 midi_devices_button.set_no_show_all();
331 EngineControl::connect_changed_signals ()
333 backend_combo_connection = backend_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::backend_changed));
335 driver_combo_connection = driver_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::driver_changed));
337 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
339 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
341 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
342 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
343 device_combo_connection = device_combo.signal_changed ().connect (
344 sigc::mem_fun (*this, &EngineControl::device_changed));
345 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
346 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
348 input_device_combo_connection = input_device_combo.signal_changed ().connect (
349 sigc::mem_fun (*this, &EngineControl::input_device_changed));
350 output_device_combo_connection = output_device_combo.signal_changed ().connect (
351 sigc::mem_fun (*this, &EngineControl::output_device_changed));
353 input_latency_connection = input_latency.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::parameter_changed));
355 output_latency_connection = output_latency.signal_changed ().connect (
356 sigc::mem_fun (*this, &EngineControl::parameter_changed));
357 input_channels_connection = input_channels.signal_changed ().connect (
358 sigc::mem_fun (*this, &EngineControl::parameter_changed));
359 output_channels_connection = output_channels.signal_changed ().connect (
360 sigc::mem_fun (*this, &EngineControl::parameter_changed));
364 EngineControl::block_changed_signals ()
366 if (block_signals++ == 0) {
367 DEBUG_ECONTROL ("Blocking changed signals");
368 backend_combo_connection.block ();
369 driver_combo_connection.block ();
370 sample_rate_combo_connection.block ();
371 buffer_size_combo_connection.block ();
372 nperiods_combo_connection.block ();
373 device_combo_connection.block ();
374 input_device_combo_connection.block ();
375 output_device_combo_connection.block ();
376 midi_option_combo_connection.block ();
377 input_latency_connection.block ();
378 output_latency_connection.block ();
379 input_channels_connection.block ();
380 output_channels_connection.block ();
385 EngineControl::unblock_changed_signals ()
387 if (--block_signals == 0) {
388 DEBUG_ECONTROL ("Unblocking changed signals");
389 backend_combo_connection.unblock ();
390 driver_combo_connection.unblock ();
391 sample_rate_combo_connection.unblock ();
392 buffer_size_combo_connection.unblock ();
393 nperiods_combo_connection.unblock ();
394 device_combo_connection.unblock ();
395 input_device_combo_connection.unblock ();
396 output_device_combo_connection.unblock ();
397 midi_option_combo_connection.unblock ();
398 input_latency_connection.unblock ();
399 output_latency_connection.unblock ();
400 input_channels_connection.unblock ();
401 output_channels_connection.unblock ();
405 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
406 const std::string& reason)
407 : ec (engine_control)
410 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
411 ec.block_changed_signals ();
414 EngineControl::SignalBlocker::~SignalBlocker ()
416 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
417 ec.unblock_changed_signals ();
421 EngineControl::on_show ()
423 ArdourDialog::on_show ();
424 if (Splash::instance()) {
425 Splash::instance()->hide ();
427 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
428 // re-check _have_control (jackd running) see #6041
432 start_stop_button.grab_focus();
436 EngineControl::try_autostart ()
438 if (!start_stop_button.get_sensitive()) {
441 if (ARDOUR::AudioEngine::instance()->running()) {
444 return start_engine ();
448 EngineControl::start_engine ()
450 if (push_state_to_backend(true) != 0) {
451 MessageDialog msg(*this,
452 ARDOUR::AudioEngine::instance()->get_last_backend_error());
460 EngineControl::stop_engine (bool for_latency)
462 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
463 MessageDialog msg(*this,
464 ARDOUR::AudioEngine::instance()->get_last_backend_error());
472 EngineControl::build_notebook ()
475 AttachOptions xopt = AttachOptions (FILL|EXPAND);
477 /* clear the table */
479 Gtkmm2ext::container_clear (basic_vbox);
480 Gtkmm2ext::container_clear (basic_packer);
482 if (control_app_button.get_parent()) {
483 control_app_button.get_parent()->remove (control_app_button);
486 label = manage (left_aligned_label (_("Audio System:")));
487 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
488 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
490 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
491 engine_status.show();
493 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
494 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
495 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
497 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
498 lm_button_audio.set_name ("generic button");
499 lm_button_audio.set_can_focus(true);
502 build_full_control_notebook ();
504 build_no_control_notebook ();
507 basic_vbox.pack_start (basic_hbox, false, false);
510 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
511 basic_vbox.show_all ();
516 EngineControl::build_full_control_notebook ()
518 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
521 using namespace Notebook_Helpers;
523 vector<string> strings;
524 AttachOptions xopt = AttachOptions (FILL|EXPAND);
525 int row = 1; // row zero == backend combo
527 /* start packing it up */
529 if (backend->requires_driver_selection()) {
530 label = manage (left_aligned_label (_("Driver:")));
531 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
532 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
536 if (backend->use_separate_input_and_output_devices()) {
537 label = manage (left_aligned_label (_("Input Device:")));
538 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
539 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
541 label = manage (left_aligned_label (_("Output Device:")));
542 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
543 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
545 // reset so it isn't used in state comparisons
546 device_combo.set_active_text ("");
548 label = manage (left_aligned_label (_("Device:")));
549 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
550 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
552 // reset these so they don't get used in state comparisons
553 input_device_combo.set_active_text ("");
554 output_device_combo.set_active_text ("");
557 label = manage (left_aligned_label (_("Sample rate:")));
558 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
559 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
563 label = manage (left_aligned_label (_("Buffer size:")));
564 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
565 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
566 buffer_size_duration_label.set_alignment (0.0); /* left-align */
567 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
569 int ctrl_btn_span = 1;
570 if (backend->can_set_period_size ()) {
572 label = manage (left_aligned_label (_("Periods:")));
573 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
574 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
578 /* button spans 2 or 3 rows */
580 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
583 input_channels.set_name ("InputChannels");
584 input_channels.set_flags (Gtk::CAN_FOCUS);
585 input_channels.set_digits (0);
586 input_channels.set_wrap (false);
587 output_channels.set_editable (true);
589 if (!ARDOUR::Profile->get_mixbus()) {
590 label = manage (left_aligned_label (_("Input Channels:")));
591 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
592 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
596 output_channels.set_name ("OutputChannels");
597 output_channels.set_flags (Gtk::CAN_FOCUS);
598 output_channels.set_digits (0);
599 output_channels.set_wrap (false);
600 output_channels.set_editable (true);
602 if (!ARDOUR::Profile->get_mixbus()) {
603 label = manage (left_aligned_label (_("Output Channels:")));
604 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
605 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
609 input_latency.set_name ("InputLatency");
610 input_latency.set_flags (Gtk::CAN_FOCUS);
611 input_latency.set_digits (0);
612 input_latency.set_wrap (false);
613 input_latency.set_editable (true);
615 label = manage (left_aligned_label (_("Hardware input latency:")));
616 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
617 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
618 label = manage (left_aligned_label (_("samples")));
619 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
622 output_latency.set_name ("OutputLatency");
623 output_latency.set_flags (Gtk::CAN_FOCUS);
624 output_latency.set_digits (0);
625 output_latency.set_wrap (false);
626 output_latency.set_editable (true);
628 label = manage (left_aligned_label (_("Hardware output latency:")));
629 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
630 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
631 label = manage (left_aligned_label (_("samples")));
632 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
634 /* button spans 2 rows */
636 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
639 label = manage (left_aligned_label (_("MIDI System:")));
640 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
641 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
642 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
647 EngineControl::build_no_control_notebook ()
649 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
652 using namespace Notebook_Helpers;
654 vector<string> strings;
655 AttachOptions xopt = AttachOptions (FILL|EXPAND);
656 int row = 1; // row zero == backend combo
657 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
659 label = manage (new Label);
660 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
661 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
664 if (backend->can_change_sample_rate_when_running()) {
665 label = manage (left_aligned_label (_("Sample rate:")));
666 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
667 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
671 if (backend->can_change_buffer_size_when_running()) {
672 label = manage (left_aligned_label (_("Buffer size:")));
673 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
674 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
675 buffer_size_duration_label.set_alignment (0.0); /* left-align */
676 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
680 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
684 EngineControl::~EngineControl ()
686 ignore_changes = true;
690 EngineControl::disable_latency_tab ()
692 vector<string> empty;
693 set_popdown_strings (lm_output_channel_combo, empty);
694 set_popdown_strings (lm_input_channel_combo, empty);
695 lm_measure_button.set_sensitive (false);
696 lm_use_button.set_sensitive (false);
700 EngineControl::enable_latency_tab ()
702 vector<string> outputs;
703 vector<string> inputs;
705 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
706 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
707 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
709 if (!ARDOUR::AudioEngine::instance()->running()) {
710 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
711 notebook.set_current_page (0);
715 else if (inputs.empty() || outputs.empty()) {
716 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
717 notebook.set_current_page (0);
722 lm_back_button_signal.disconnect();
724 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
727 lm_back_button_signal = lm_back_button.signal_clicked().connect(
728 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
732 set_popdown_strings (lm_output_channel_combo, outputs);
733 lm_output_channel_combo.set_active_text (outputs.front());
734 lm_output_channel_combo.set_sensitive (true);
736 set_popdown_strings (lm_input_channel_combo, inputs);
737 lm_input_channel_combo.set_active_text (inputs.front());
738 lm_input_channel_combo.set_sensitive (true);
740 lm_measure_button.set_sensitive (true);
744 EngineControl::setup_midi_tab_for_backend ()
746 string backend = backend_combo.get_active_text ();
748 Gtkmm2ext::container_clear (midi_vbox);
750 midi_vbox.set_border_width (12);
751 midi_device_table.set_border_width (12);
753 if (backend == "JACK") {
754 setup_midi_tab_for_jack ();
757 midi_vbox.pack_start (midi_device_table, true, true);
758 midi_vbox.pack_start (midi_back_button, false, false);
759 midi_vbox.show_all ();
763 EngineControl::update_sensitivity ()
765 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
767 start_stop_button.set_sensitive (false);
772 size_t devices_available = 0;
774 if (backend->use_separate_input_and_output_devices ()) {
775 devices_available += get_popdown_string_count (input_device_combo);
776 devices_available += get_popdown_string_count (output_device_combo);
778 devices_available += get_popdown_string_count (device_combo);
781 if (devices_available == 0) {
783 input_latency.set_sensitive (false);
784 output_latency.set_sensitive (false);
785 input_channels.set_sensitive (false);
786 output_channels.set_sensitive (false);
788 input_latency.set_sensitive (true);
789 output_latency.set_sensitive (true);
790 input_channels.set_sensitive (true);
791 output_channels.set_sensitive (true);
794 if (get_popdown_string_count (buffer_size_combo) > 0) {
795 if (!ARDOUR::AudioEngine::instance()->running()) {
796 buffer_size_combo.set_sensitive (valid);
797 } else if (backend->can_change_sample_rate_when_running()) {
798 buffer_size_combo.set_sensitive (valid || !_have_control);
802 * Currently there is no way to manually stop the
803 * engine in order to re-configure it.
804 * This needs to remain sensitive for now.
806 * (it's also handy to implicily
807 * re-start the engine)
809 buffer_size_combo.set_sensitive (true);
811 buffer_size_combo.set_sensitive (false);
815 buffer_size_combo.set_sensitive (false);
819 if (get_popdown_string_count (sample_rate_combo) > 0) {
820 bool allow_to_set_rate = false;
821 if (!ARDOUR::AudioEngine::instance()->running()) {
822 if (!ARDOUR_UI::instance()->session_loaded) {
823 // engine is not running, no session loaded -> anything goes.
824 allow_to_set_rate = true;
825 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
826 // only allow to change if the current setting is not the native session rate.
827 allow_to_set_rate = true;
830 sample_rate_combo.set_sensitive (allow_to_set_rate);
832 sample_rate_combo.set_sensitive (false);
836 if (get_popdown_string_count (nperiods_combo) > 0) {
837 if (!ARDOUR::AudioEngine::instance()->running()) {
838 nperiods_combo.set_sensitive (true);
840 nperiods_combo.set_sensitive (false);
843 nperiods_combo.set_sensitive (false);
847 start_stop_button.set_sensitive(true);
848 start_stop_button.show();
849 if (ARDOUR::AudioEngine::instance()->running()) {
850 start_stop_button.set_text("Stop");
851 update_devices_button.set_sensitive(false);
852 use_buffered_io_button.set_sensitive(false);
854 if (backend->can_request_update_devices()) {
855 update_devices_button.show();
857 update_devices_button.hide();
859 if (backend->can_use_buffered_io()) {
860 use_buffered_io_button.show();
862 use_buffered_io_button.hide();
864 start_stop_button.set_text("Start");
865 update_devices_button.set_sensitive(true);
866 use_buffered_io_button.set_sensitive(true);
869 update_devices_button.set_sensitive(false);
870 update_devices_button.hide();
871 use_buffered_io_button.set_sensitive(false);
872 use_buffered_io_button.hide();
873 start_stop_button.set_sensitive(false);
874 start_stop_button.hide();
877 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
878 input_device_combo.set_sensitive (false);
879 output_device_combo.set_sensitive (false);
880 device_combo.set_sensitive (false);
881 driver_combo.set_sensitive (false);
883 input_device_combo.set_sensitive (true);
884 output_device_combo.set_sensitive (true);
885 device_combo.set_sensitive (true);
886 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
887 driver_combo.set_sensitive (true);
889 driver_combo.set_sensitive (false);
895 EngineControl::setup_midi_tab_for_jack ()
900 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
902 device->input_latency = a->get_value();
904 device->output_latency = a->get_value();
909 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
910 b->set_active (!b->get_active());
911 device->enabled = b->get_active();
912 refresh_midi_display(device->name);
916 EngineControl::refresh_midi_display (std::string focus)
918 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
922 AttachOptions xopt = AttachOptions (FILL|EXPAND);
925 Gtkmm2ext::container_clear (midi_device_table);
927 midi_device_table.set_spacings (6);
929 l = manage (new Label);
930 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
931 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
932 l->set_alignment (0.5, 0.5);
936 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
937 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
938 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
939 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
941 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
942 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
943 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
944 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
947 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
952 bool enabled = (*p)->enabled;
954 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
955 m->set_name ("midi device");
956 m->set_can_focus (Gtk::CAN_FOCUS);
957 m->add_events (Gdk::BUTTON_RELEASE_MASK);
958 m->set_active (enabled);
959 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
960 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
961 if ((*p)->name == focus) {
965 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
966 s = manage (new Gtk::SpinButton (*a));
967 a->set_value ((*p)->input_latency);
968 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
969 s->set_sensitive (_can_set_midi_latencies && enabled);
970 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
972 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
973 s = manage (new Gtk::SpinButton (*a));
974 a->set_value ((*p)->output_latency);
975 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
976 s->set_sensitive (_can_set_midi_latencies && enabled);
977 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
979 b = manage (new Button (_("Calibrate")));
980 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
981 b->set_sensitive (_can_set_midi_latencies && enabled);
982 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
989 EngineControl::backend_changed ()
991 SignalBlocker blocker (*this, "backend_changed");
992 string backend_name = backend_combo.get_active_text();
993 boost::shared_ptr<ARDOUR::AudioBackend> backend;
995 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
996 /* eh? setting the backend failed... how ? */
997 /* A: stale config contains a backend that does not exist in current build */
1001 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1003 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1006 setup_midi_tab_for_backend ();
1007 _midi_devices.clear();
1009 if (backend->requires_driver_selection()) {
1010 if (set_driver_popdown_strings ()) {
1014 /* this will change the device text which will cause a call to
1015 * device changed which will set up parameters
1020 update_midi_options ();
1022 connect_disconnect_button.hide();
1024 midi_option_changed();
1026 started_at_least_once = false;
1028 /* changing the backend implies stopping the engine
1029 * ARDOUR::AudioEngine() may or may not emit this signal
1030 * depending on previous engine state
1032 engine_stopped (); // set "active/inactive"
1034 if (!_have_control) {
1035 // set settings from backend that we do have control over
1036 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1039 if (_have_control && !ignore_changes) {
1040 // set driver & devices
1041 State state = get_matching_state (backend_combo.get_active_text());
1043 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1044 set_current_state (state);
1048 if (!ignore_changes) {
1049 maybe_display_saved_state ();
1054 EngineControl::update_midi_options ()
1056 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1057 vector<string> midi_options = backend->enumerate_midi_options();
1059 if (midi_options.size() == 1) {
1060 /* only contains the "none" option */
1061 midi_option_combo.set_sensitive (false);
1063 if (_have_control) {
1064 set_popdown_strings (midi_option_combo, midi_options);
1065 midi_option_combo.set_active_text (midi_options.front());
1066 midi_option_combo.set_sensitive (true);
1068 midi_option_combo.set_sensitive (false);
1074 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1076 if (ARDOUR::Profile->get_mixbus()) {
1080 uint32_t cnt = (uint32_t) sb->get_value();
1082 sb->set_text (_("all available channels"));
1085 snprintf (buf, sizeof (buf), "%d", cnt);
1091 // @return true if there are drivers available
1093 EngineControl::set_driver_popdown_strings ()
1095 DEBUG_ECONTROL ("set_driver_popdown_strings");
1096 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1097 vector<string> drivers = backend->enumerate_drivers();
1099 if (drivers.empty ()) {
1100 // This is an error...?
1104 string current_driver = backend->driver_name ();
1106 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1108 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1111 current_driver = drivers.front ();
1114 set_popdown_strings (driver_combo, drivers);
1116 string_compose ("driver_combo.set_active_text: %1", current_driver));
1117 driver_combo.set_active_text (current_driver);
1122 EngineControl::get_default_device(const string& current_device_name,
1123 const vector<string>& available_devices)
1125 // If the current device is available, use it as default
1126 if (std::find (available_devices.begin (),
1127 available_devices.end (),
1128 current_device_name) != available_devices.end ()) {
1130 return current_device_name;
1133 using namespace ARDOUR;
1135 string default_device_name =
1136 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1138 vector<string>::const_iterator i;
1140 // If there is a "Default" device available, use it
1141 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1142 if (*i == default_device_name) {
1147 string none_device_name =
1148 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1150 // Use the first device that isn't "None"
1151 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1152 if (*i != none_device_name) {
1157 // Use "None" if there are no other available
1158 return available_devices.front();
1161 // @return true if there are devices available
1163 EngineControl::set_device_popdown_strings ()
1165 DEBUG_ECONTROL ("set_device_popdown_strings");
1166 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1167 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1169 /* NOTE: Ardour currently does not display the "available" field of the
1172 * Doing so would require a different GUI widget than the combo
1173 * box/popdown that we currently use, since it has no way to list
1174 * items that are not selectable. Something more like a popup menu,
1175 * which could have unselectable items, would be appropriate.
1178 vector<string> available_devices;
1180 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1181 available_devices.push_back (i->name);
1184 if (available_devices.empty ()) {
1188 set_popdown_strings (device_combo, available_devices);
1190 std::string default_device =
1191 get_default_device(backend->device_name(), available_devices);
1194 string_compose ("set device_combo active text: %1", default_device));
1196 device_combo.set_active_text(default_device);
1200 // @return true if there are input devices available
1202 EngineControl::set_input_device_popdown_strings ()
1204 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1205 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1206 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1208 vector<string> available_devices;
1210 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1211 available_devices.push_back (i->name);
1214 if (available_devices.empty()) {
1218 set_popdown_strings (input_device_combo, available_devices);
1220 std::string default_device =
1221 get_default_device(backend->input_device_name(), available_devices);
1224 string_compose ("set input_device_combo active text: %1", default_device));
1225 input_device_combo.set_active_text(default_device);
1229 // @return true if there are output devices available
1231 EngineControl::set_output_device_popdown_strings ()
1233 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1234 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1235 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1237 vector<string> available_devices;
1239 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1240 available_devices.push_back (i->name);
1243 if (available_devices.empty()) {
1247 set_popdown_strings (output_device_combo, available_devices);
1249 std::string default_device =
1250 get_default_device(backend->output_device_name(), available_devices);
1253 string_compose ("set output_device_combo active text: %1", default_device));
1254 output_device_combo.set_active_text(default_device);
1259 EngineControl::list_devices ()
1261 DEBUG_ECONTROL ("list_devices");
1262 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1265 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1267 bool devices_available = false;
1269 if (backend->use_separate_input_and_output_devices ()) {
1270 bool input_devices_available = set_input_device_popdown_strings ();
1271 bool output_devices_available = set_output_device_popdown_strings ();
1272 devices_available = input_devices_available || output_devices_available;
1274 devices_available = set_device_popdown_strings ();
1277 if (devices_available) {
1280 device_combo.clear();
1281 input_device_combo.clear();
1282 output_device_combo.clear();
1284 update_sensitivity ();
1288 EngineControl::driver_changed ()
1290 SignalBlocker blocker (*this, "driver_changed");
1291 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1294 backend->set_driver (driver_combo.get_active_text());
1297 // TODO load LRU device(s) for backend + driver combo
1299 if (!ignore_changes) {
1300 maybe_display_saved_state ();
1305 EngineControl::get_sample_rates_for_all_devices ()
1307 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1308 ARDOUR::AudioEngine::instance ()->current_backend ();
1309 vector<float> all_rates;
1311 if (backend->use_separate_input_and_output_devices ()) {
1312 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1314 all_rates = backend->available_sample_rates (get_device_name ());
1320 EngineControl::get_default_sample_rates ()
1322 vector<float> rates;
1323 rates.push_back (8000.0f);
1324 rates.push_back (16000.0f);
1325 rates.push_back (32000.0f);
1326 rates.push_back (44100.0f);
1327 rates.push_back (48000.0f);
1328 rates.push_back (88200.0f);
1329 rates.push_back (96000.0f);
1330 rates.push_back (192000.0f);
1331 rates.push_back (384000.0f);
1336 EngineControl::set_samplerate_popdown_strings ()
1338 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1339 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1344 if (_have_control) {
1345 sr = get_sample_rates_for_all_devices ();
1347 sr = get_default_sample_rates ();
1350 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1351 s.push_back (rate_as_string (*x));
1352 if (*x == _desired_sample_rate) {
1357 set_popdown_strings (sample_rate_combo, s);
1360 if (ARDOUR::AudioEngine::instance()->running()) {
1361 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1363 else if (desired.empty ()) {
1364 float new_active_sr = backend->default_sample_rate ();
1366 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1367 new_active_sr = sr.front ();
1370 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1372 sample_rate_combo.set_active_text (desired);
1376 update_sensitivity ();
1380 EngineControl::get_buffer_sizes_for_all_devices ()
1382 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1383 ARDOUR::AudioEngine::instance ()->current_backend ();
1384 vector<uint32_t> all_sizes;
1386 if (backend->use_separate_input_and_output_devices ()) {
1387 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1389 all_sizes = backend->available_buffer_sizes (get_device_name ());
1395 EngineControl::get_default_buffer_sizes ()
1397 vector<uint32_t> sizes;
1398 sizes.push_back (8);
1399 sizes.push_back (16);
1400 sizes.push_back (32);
1401 sizes.push_back (64);
1402 sizes.push_back (128);
1403 sizes.push_back (256);
1404 sizes.push_back (512);
1405 sizes.push_back (1024);
1406 sizes.push_back (2048);
1407 sizes.push_back (4096);
1408 sizes.push_back (8192);
1413 EngineControl::set_buffersize_popdown_strings ()
1415 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1416 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1417 vector<uint32_t> bs;
1420 if (_have_control) {
1421 bs = get_buffer_sizes_for_all_devices ();
1422 } else if (backend->can_change_buffer_size_when_running()) {
1423 bs = get_default_buffer_sizes ();
1426 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1427 s.push_back (bufsize_as_string (*x));
1430 uint32_t previous_size = 0;
1431 if (!buffer_size_combo.get_active_text().empty()) {
1432 previous_size = get_buffer_size ();
1435 set_popdown_strings (buffer_size_combo, s);
1439 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1440 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1443 buffer_size_combo.set_active_text(s.front());
1445 uint32_t period = backend->buffer_size();
1446 if (0 == period && backend->use_separate_input_and_output_devices()) {
1447 period = backend->default_buffer_size(get_input_device_name());
1449 if (0 == period && backend->use_separate_input_and_output_devices()) {
1450 period = backend->default_buffer_size(get_output_device_name());
1452 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1453 period = backend->default_buffer_size(get_device_name());
1456 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1458 show_buffer_duration ();
1460 update_sensitivity ();
1464 EngineControl::set_nperiods_popdown_strings ()
1466 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1467 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1468 vector<uint32_t> np;
1471 if (backend->can_set_period_size()) {
1472 np = backend->available_period_sizes (get_driver());
1475 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1476 s.push_back (nperiods_as_string (*x));
1479 set_popdown_strings (nperiods_combo, s);
1482 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1485 update_sensitivity ();
1489 EngineControl::device_changed ()
1491 SignalBlocker blocker (*this, "device_changed");
1492 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1495 string device_name_in;
1496 string device_name_out; // only used if backend support separate I/O devices
1498 if (backend->use_separate_input_and_output_devices()) {
1499 device_name_in = get_input_device_name ();
1500 device_name_out = get_output_device_name ();
1502 device_name_in = get_device_name ();
1505 /* we set the backend-device to query various device related intormation.
1506 * This has the side effect that backend->device_name() will match
1507 * the device_name and 'change_device' will never be true.
1508 * so work around this by setting...
1510 if (backend->use_separate_input_and_output_devices()) {
1511 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1512 queue_device_changed = true;
1515 if (device_name_in != backend->device_name()) {
1516 queue_device_changed = true;
1520 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1521 if (backend->use_separate_input_and_output_devices()) {
1522 backend->set_input_device_name (device_name_in);
1523 backend->set_output_device_name (device_name_out);
1525 backend->set_device_name(device_name_in);
1529 /* don't allow programmatic change to combos to cause a
1530 recursive call to this method.
1532 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1534 set_samplerate_popdown_strings ();
1535 set_buffersize_popdown_strings ();
1536 set_nperiods_popdown_strings ();
1538 /* TODO set min + max channel counts here */
1540 manage_control_app_sensitivity ();
1543 /* pick up any saved state for this device */
1545 if (!ignore_changes) {
1546 maybe_display_saved_state ();
1551 EngineControl::input_device_changed ()
1553 DEBUG_ECONTROL ("input_device_changed");
1555 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1556 if (backend && backend->match_input_output_devices_or_none ()) {
1557 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1559 if (get_output_device_name () != dev_none
1560 && get_input_device_name () != dev_none
1561 && get_input_device_name () != get_output_device_name ()) {
1562 block_changed_signals ();
1563 if (contains_value (output_device_combo, get_input_device_name ())) {
1564 output_device_combo.set_active_text (get_input_device_name ());
1566 assert (contains_value (output_device_combo, dev_none));
1567 output_device_combo.set_active_text (dev_none);
1569 unblock_changed_signals ();
1576 EngineControl::output_device_changed ()
1578 DEBUG_ECONTROL ("output_device_changed");
1579 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1580 if (backend && backend->match_input_output_devices_or_none ()) {
1581 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1583 if (get_input_device_name () != dev_none
1584 && get_input_device_name () != dev_none
1585 && get_input_device_name () != get_output_device_name ()) {
1586 block_changed_signals ();
1587 if (contains_value (input_device_combo, get_output_device_name ())) {
1588 input_device_combo.set_active_text (get_output_device_name ());
1590 assert (contains_value (input_device_combo, dev_none));
1591 input_device_combo.set_active_text (dev_none);
1593 unblock_changed_signals ();
1600 EngineControl::bufsize_as_string (uint32_t sz)
1602 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1606 EngineControl::nperiods_as_string (uint32_t np)
1609 snprintf (buf, sizeof (buf), "%u", np);
1615 EngineControl::sample_rate_changed ()
1617 DEBUG_ECONTROL ("sample_rate_changed");
1618 /* reset the strings for buffer size to show the correct msec value
1619 (reflecting the new sample rate).
1622 show_buffer_duration ();
1627 EngineControl::buffer_size_changed ()
1629 DEBUG_ECONTROL ("buffer_size_changed");
1630 show_buffer_duration ();
1634 EngineControl::nperiods_changed ()
1636 DEBUG_ECONTROL ("nperiods_changed");
1637 show_buffer_duration ();
1641 EngineControl::show_buffer_duration ()
1643 DEBUG_ECONTROL ("show_buffer_duration");
1644 /* buffer sizes - convert from just samples to samples + msecs for
1645 * the displayed string
1648 string bs_text = buffer_size_combo.get_active_text ();
1649 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1650 uint32_t rate = get_rate();
1652 /* Except for ALSA and Dummy backends, we don't know the number of periods
1653 * per cycle and settings.
1655 * jack1 vs jack2 have different default latencies since jack2 start
1656 * in async-mode unless --sync is given which adds an extra cycle
1657 * of latency. The value is not known if jackd is started externally..
1659 * So just display the period size, that's also what
1660 * ARDOUR_UI::update_sample_rate() does for the status bar.
1661 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1662 * but still, that's the buffer period, not [round-trip] latency)
1665 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1666 buffer_size_duration_label.set_text (buf);
1670 EngineControl::midi_option_changed ()
1672 DEBUG_ECONTROL ("midi_option_changed");
1673 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1676 backend->set_midi_option (get_midi_option());
1678 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1680 //_midi_devices.clear(); // TODO merge with state-saved settings..
1681 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1682 std::vector<MidiDeviceSettings> new_devices;
1684 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1685 MidiDeviceSettings mds = find_midi_device (i->name);
1686 if (i->available && !mds) {
1687 uint32_t input_latency = 0;
1688 uint32_t output_latency = 0;
1689 if (_can_set_midi_latencies) {
1690 input_latency = backend->systemic_midi_input_latency (i->name);
1691 output_latency = backend->systemic_midi_output_latency (i->name);
1693 bool enabled = backend->midi_device_enabled (i->name);
1694 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1695 new_devices.push_back (ptr);
1696 } else if (i->available) {
1697 new_devices.push_back (mds);
1700 _midi_devices = new_devices;
1702 if (_midi_devices.empty()) {
1703 midi_devices_button.hide ();
1705 midi_devices_button.show ();
1710 EngineControl::parameter_changed ()
1714 EngineControl::State
1715 EngineControl::get_matching_state (const string& backend)
1717 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1718 if ((*i)->backend == backend) {
1725 EngineControl::State
1726 EngineControl::get_matching_state (
1727 const string& backend,
1728 const string& driver,
1729 const string& device)
1731 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1732 if ((*i)->backend == backend &&
1733 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1741 EngineControl::State
1742 EngineControl::get_matching_state (
1743 const string& backend,
1744 const string& driver,
1745 const string& input_device,
1746 const string& output_device)
1748 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1749 if ((*i)->backend == backend &&
1750 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1758 EngineControl::State
1759 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1761 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1764 if (backend->use_separate_input_and_output_devices ()) {
1765 return get_matching_state (backend_combo.get_active_text(),
1766 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1767 input_device_combo.get_active_text(),
1768 output_device_combo.get_active_text());
1770 return get_matching_state (backend_combo.get_active_text(),
1771 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1772 device_combo.get_active_text());
1776 return get_matching_state (backend_combo.get_active_text(),
1778 device_combo.get_active_text());
1781 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1782 const EngineControl::State& state2)
1784 if (state1->backend == state2->backend &&
1785 state1->driver == state2->driver &&
1786 state1->device == state2->device &&
1787 state1->input_device == state2->input_device &&
1788 state1->output_device == state2->output_device) {
1795 EngineControl::state_sort_cmp (const State &a, const State &b) {
1799 else if (b->active) {
1803 return a->lru < b->lru;
1807 EngineControl::State
1808 EngineControl::save_state ()
1812 if (!_have_control) {
1813 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1815 state->lru = time (NULL) ;
1818 state.reset(new StateStruct);
1819 state->backend = get_backend ();
1821 state.reset(new StateStruct);
1822 store_state (state);
1825 for (StateList::iterator i = states.begin(); i != states.end();) {
1826 if (equivalent_states (*i, state)) {
1827 i = states.erase(i);
1833 states.push_back (state);
1835 states.sort (state_sort_cmp);
1841 EngineControl::store_state (State state)
1843 state->backend = get_backend ();
1844 state->driver = get_driver ();
1845 state->device = get_device_name ();
1846 state->input_device = get_input_device_name ();
1847 state->output_device = get_output_device_name ();
1848 state->sample_rate = get_rate ();
1849 state->buffer_size = get_buffer_size ();
1850 state->n_periods = get_nperiods ();
1851 state->input_latency = get_input_latency ();
1852 state->output_latency = get_output_latency ();
1853 state->input_channels = get_input_channels ();
1854 state->output_channels = get_output_channels ();
1855 state->midi_option = get_midi_option ();
1856 state->midi_devices = _midi_devices;
1857 state->use_buffered_io = get_use_buffered_io ();
1858 state->lru = time (NULL) ;
1862 EngineControl::maybe_display_saved_state ()
1864 if (!_have_control) {
1868 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1871 DEBUG_ECONTROL ("Restoring saved state");
1872 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1874 if (!_desired_sample_rate) {
1875 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1877 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1879 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1880 /* call this explicitly because we're ignoring changes to
1881 the controls at this point.
1883 show_buffer_duration ();
1884 input_latency.set_value (state->input_latency);
1885 output_latency.set_value (state->output_latency);
1887 use_buffered_io_button.set_active (state->use_buffered_io);
1889 if (!state->midi_option.empty()) {
1890 midi_option_combo.set_active_text (state->midi_option);
1891 _midi_devices = state->midi_devices;
1894 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1899 EngineControl::get_state ()
1903 XMLNode* root = new XMLNode ("AudioMIDISetup");
1906 if (!states.empty()) {
1907 XMLNode* state_nodes = new XMLNode ("EngineStates");
1909 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1911 XMLNode* node = new XMLNode ("State");
1913 node->add_property ("backend", (*i)->backend);
1914 node->add_property ("driver", (*i)->driver);
1915 node->add_property ("device", (*i)->device);
1916 node->add_property ("input-device", (*i)->input_device);
1917 node->add_property ("output-device", (*i)->output_device);
1918 node->add_property ("sample-rate", (*i)->sample_rate);
1919 node->add_property ("buffer-size", (*i)->buffer_size);
1920 node->add_property ("n-periods", (*i)->n_periods);
1921 node->add_property ("input-latency", (*i)->input_latency);
1922 node->add_property ("output-latency", (*i)->output_latency);
1923 node->add_property ("input-channels", (*i)->input_channels);
1924 node->add_property ("output-channels", (*i)->output_channels);
1925 node->add_property ("active", (*i)->active ? "yes" : "no");
1926 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1927 node->add_property ("midi-option", (*i)->midi_option);
1928 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1930 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1931 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1932 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1933 midi_device_stuff->add_property (X_("name"), (*p)->name);
1934 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1935 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1936 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1937 midi_devices->add_child_nocopy (*midi_device_stuff);
1939 node->add_child_nocopy (*midi_devices);
1941 state_nodes->add_child_nocopy (*node);
1944 root->add_child_nocopy (*state_nodes);
1951 EngineControl::set_default_state ()
1953 vector<string> backend_names;
1954 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1956 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1957 backend_names.push_back ((*b)->name);
1959 backend_combo.set_active_text (backend_names.front());
1961 // We could set default backends per platform etc here
1967 EngineControl::set_state (const XMLNode& root)
1969 XMLNodeList clist, cclist;
1970 XMLNodeConstIterator citer, cciter;
1971 XMLNode const * child;
1972 XMLNode const * grandchild;
1973 XMLProperty const * prop = NULL;
1975 if (root.name() != "AudioMIDISetup") {
1979 clist = root.children();
1983 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1987 if (child->name() != "EngineStates") {
1991 cclist = child->children();
1993 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1994 State state (new StateStruct);
1996 grandchild = *cciter;
1998 if (grandchild->name() != "State") {
2002 if ((prop = grandchild->property ("backend")) == 0) {
2005 state->backend = prop->value ();
2007 if ((prop = grandchild->property ("driver")) == 0) {
2010 state->driver = prop->value ();
2012 if ((prop = grandchild->property ("device")) == 0) {
2015 state->device = prop->value ();
2017 if ((prop = grandchild->property ("input-device")) == 0) {
2020 state->input_device = prop->value ();
2022 if ((prop = grandchild->property ("output-device")) == 0) {
2025 state->output_device = prop->value ();
2027 if ((prop = grandchild->property ("sample-rate")) == 0) {
2030 state->sample_rate = atof (prop->value ());
2032 if ((prop = grandchild->property ("buffer-size")) == 0) {
2035 state->buffer_size = atoi (prop->value ());
2037 if ((prop = grandchild->property ("n-periods")) == 0) {
2038 // optional (new value in 4.5)
2039 state->n_periods = 0;
2041 state->n_periods = atoi (prop->value ());
2044 if ((prop = grandchild->property ("input-latency")) == 0) {
2047 state->input_latency = atoi (prop->value ());
2049 if ((prop = grandchild->property ("output-latency")) == 0) {
2052 state->output_latency = atoi (prop->value ());
2054 if ((prop = grandchild->property ("input-channels")) == 0) {
2057 state->input_channels = atoi (prop->value ());
2059 if ((prop = grandchild->property ("output-channels")) == 0) {
2062 state->output_channels = atoi (prop->value ());
2064 if ((prop = grandchild->property ("active")) == 0) {
2067 state->active = string_is_affirmative (prop->value ());
2069 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2072 state->use_buffered_io = string_is_affirmative (prop->value ());
2074 if ((prop = grandchild->property ("midi-option")) == 0) {
2077 state->midi_option = prop->value ();
2079 state->midi_devices.clear();
2081 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2082 const XMLNodeList mnc = midinode->children();
2083 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2084 if ((*n)->property (X_("name")) == 0
2085 || (*n)->property (X_("enabled")) == 0
2086 || (*n)->property (X_("input-latency")) == 0
2087 || (*n)->property (X_("output-latency")) == 0
2092 MidiDeviceSettings ptr (new MidiDeviceSetting(
2093 (*n)->property (X_("name"))->value (),
2094 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2095 atoi ((*n)->property (X_("input-latency"))->value ()),
2096 atoi ((*n)->property (X_("output-latency"))->value ())
2098 state->midi_devices.push_back (ptr);
2102 if ((prop = grandchild->property ("lru"))) {
2103 state->lru = atoi (prop->value ());
2107 /* remove accumulated duplicates (due to bug in ealier version)
2108 * this can be removed again before release
2110 for (StateList::iterator i = states.begin(); i != states.end();) {
2111 if ((*i)->backend == state->backend &&
2112 (*i)->driver == state->driver &&
2113 (*i)->device == state->device) {
2114 i = states.erase(i);
2121 states.push_back (state);
2125 /* now see if there was an active state and switch the setup to it */
2127 // purge states of backend that are not available in this built
2128 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2129 vector<std::string> backend_names;
2131 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2132 backend_names.push_back((*i)->name);
2134 for (StateList::iterator i = states.begin(); i != states.end();) {
2135 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2136 i = states.erase(i);
2142 states.sort (state_sort_cmp);
2144 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2147 return set_current_state (*i);
2154 EngineControl::set_current_state (const State& state)
2156 DEBUG_ECONTROL ("set_current_state");
2158 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2160 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2161 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2162 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2163 // this shouldn't happen as the invalid backend names should have been
2164 // removed from the list of states.
2168 // now reflect the change in the backend in the GUI so backend_changed will
2169 // do the right thing
2170 backend_combo.set_active_text (state->backend);
2172 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2174 // we don't have control don't restore state
2179 if (!state->driver.empty ()) {
2180 if (!backend->requires_driver_selection ()) {
2181 DEBUG_ECONTROL ("Backend should require driver selection");
2182 // A backend has changed from having driver selection to not having
2183 // it or someone has been manually editing a config file and messed
2188 if (backend->set_driver (state->driver) != 0) {
2189 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2190 // Driver names for a backend have changed and the name in the
2191 // config file is now invalid or support for driver is no longer
2192 // included in the backend
2195 // no need to set the driver_combo as backend_changed will use
2196 // backend->driver_name to set the active driver
2199 if (!state->device.empty ()) {
2200 if (backend->set_device_name (state->device) != 0) {
2202 string_compose ("Unable to set device name %1", state->device));
2203 // device is no longer available on the system
2206 // no need to set active device as it will be picked up in
2207 // via backend_changed ()/set_device_popdown_strings
2210 // backend supports separate input/output devices
2211 if (backend->set_input_device_name (state->input_device) != 0) {
2212 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2213 state->input_device));
2214 // input device is no longer available on the system
2218 if (backend->set_output_device_name (state->output_device) != 0) {
2219 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2220 state->input_device));
2221 // output device is no longer available on the system
2224 // no need to set active devices as it will be picked up in via
2225 // backend_changed ()/set_*_device_popdown_strings
2230 // Now restore the state of the rest of the controls
2232 // We don't use a SignalBlocker as set_current_state is currently only
2233 // called from set_state before any signals are connected. If at some point
2234 // a more general named state mechanism is implemented and
2235 // set_current_state is called while signals are connected then a
2236 // SignalBlocker will need to be instantiated before setting these.
2238 device_combo.set_active_text (state->device);
2239 input_device_combo.set_active_text (state->input_device);
2240 output_device_combo.set_active_text (state->output_device);
2241 if (!_desired_sample_rate) {
2242 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2244 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2245 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2246 input_latency.set_value (state->input_latency);
2247 output_latency.set_value (state->output_latency);
2248 midi_option_combo.set_active_text (state->midi_option);
2249 use_buffered_io_button.set_active (state->use_buffered_io);
2254 EngineControl::push_state_to_backend (bool start)
2256 DEBUG_ECONTROL ("push_state_to_backend");
2257 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2258 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2264 /* figure out what is going to change */
2266 bool restart_required = false;
2267 bool was_running = ARDOUR::AudioEngine::instance()->running();
2268 bool change_driver = false;
2269 bool change_device = false;
2270 bool change_rate = false;
2271 bool change_bufsize = false;
2272 bool change_nperiods = false;
2273 bool change_latency = false;
2274 bool change_channels = false;
2275 bool change_midi = false;
2276 bool change_buffered_io = false;
2278 uint32_t ochan = get_output_channels ();
2279 uint32_t ichan = get_input_channels ();
2281 if (_have_control) {
2283 if (started_at_least_once) {
2285 /* we can control the backend */
2287 if (backend->requires_driver_selection()) {
2288 if (get_driver() != backend->driver_name()) {
2289 change_driver = true;
2293 if (backend->use_separate_input_and_output_devices()) {
2294 if (get_input_device_name() != backend->input_device_name()) {
2295 change_device = true;
2297 if (get_output_device_name() != backend->output_device_name()) {
2298 change_device = true;
2301 if (get_device_name() != backend->device_name()) {
2302 change_device = true;
2306 if (queue_device_changed) {
2307 change_device = true;
2310 if (get_rate() != backend->sample_rate()) {
2314 if (get_buffer_size() != backend->buffer_size()) {
2315 change_bufsize = true;
2318 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2319 && get_nperiods() != backend->period_size()) {
2320 change_nperiods = true;
2323 if (get_midi_option() != backend->midi_option()) {
2327 if (backend->can_use_buffered_io()) {
2328 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2329 change_buffered_io = true;
2333 /* zero-requested channels means "all available" */
2336 ichan = backend->input_channels();
2340 ochan = backend->output_channels();
2343 if (ichan != backend->input_channels()) {
2344 change_channels = true;
2347 if (ochan != backend->output_channels()) {
2348 change_channels = true;
2351 if (get_input_latency() != backend->systemic_input_latency() ||
2352 get_output_latency() != backend->systemic_output_latency()) {
2353 change_latency = true;
2356 /* backend never started, so we have to force a group
2359 change_device = true;
2360 if (backend->requires_driver_selection()) {
2361 change_driver = true;
2364 change_bufsize = true;
2365 change_channels = true;
2366 change_latency = true;
2368 change_buffered_io = backend->can_use_buffered_io();
2369 change_channels = true;
2370 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2375 /* we have no control over the backend, meaning that we can
2376 * only possibly change sample rate and buffer size.
2380 if (get_rate() != backend->sample_rate()) {
2381 change_bufsize = true;
2384 if (get_buffer_size() != backend->buffer_size()) {
2385 change_bufsize = true;
2389 queue_device_changed = false;
2391 if (!_have_control) {
2393 /* We do not have control over the backend, so the best we can
2394 * do is try to change the sample rate and/or bufsize and get
2398 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2402 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2407 backend->set_sample_rate (get_rate());
2410 if (change_bufsize) {
2411 backend->set_buffer_size (get_buffer_size());
2415 if (ARDOUR::AudioEngine::instance()->start ()) {
2416 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2426 /* determine if we need to stop the backend before changing parameters */
2428 if (change_driver || change_device || change_channels || change_nperiods ||
2429 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2430 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2431 change_midi || change_buffered_io ||
2432 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2433 restart_required = true;
2435 restart_required = false;
2440 if (restart_required) {
2441 if (ARDOUR::AudioEngine::instance()->stop()) {
2447 if (change_driver && backend->set_driver (get_driver())) {
2448 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2451 if (backend->use_separate_input_and_output_devices()) {
2452 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2453 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2456 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2457 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2461 if (change_device && backend->set_device_name (get_device_name())) {
2462 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2466 if (change_rate && backend->set_sample_rate (get_rate())) {
2467 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2470 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2471 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2474 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2475 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2479 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2480 if (backend->set_input_channels (get_input_channels())) {
2481 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2484 if (backend->set_output_channels (get_output_channels())) {
2485 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2489 if (change_latency) {
2490 if (backend->set_systemic_input_latency (get_input_latency())) {
2491 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2494 if (backend->set_systemic_output_latency (get_output_latency())) {
2495 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2501 backend->set_midi_option (get_midi_option());
2504 if (change_buffered_io) {
2505 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2509 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2510 if (_measure_midi) {
2511 if (*p == _measure_midi) {
2512 backend->set_midi_device_enabled ((*p)->name, true);
2514 backend->set_midi_device_enabled ((*p)->name, false);
2516 if (backend->can_change_systemic_latency_when_running ()) {
2517 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2518 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2522 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2523 if (backend->can_set_systemic_midi_latencies()) {
2524 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2525 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2530 if (start || (was_running && restart_required)) {
2531 if (ARDOUR::AudioEngine::instance()->start()) {
2542 EngineControl::post_push ()
2544 /* get a pointer to the current state object, creating one if
2548 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2551 state = save_state ();
2557 states.sort (state_sort_cmp);
2561 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2562 (*i)->active = false;
2565 /* mark this one active (to be used next time the dialog is
2569 state->active = true;
2571 if (_have_control) { // XXX
2572 manage_control_app_sensitivity ();
2575 /* schedule a redisplay of MIDI ports */
2576 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2581 EngineControl::get_rate () const
2583 float r = atof (sample_rate_combo.get_active_text ());
2584 /* the string may have been translated with an abbreviation for
2585 * thousands, so use a crude heuristic to fix this.
2595 EngineControl::get_buffer_size () const
2597 string txt = buffer_size_combo.get_active_text ();
2600 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2601 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2602 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2610 EngineControl::get_nperiods () const
2612 string txt = nperiods_combo.get_active_text ();
2613 return atoi (txt.c_str());
2617 EngineControl::get_midi_option () const
2619 return midi_option_combo.get_active_text();
2623 EngineControl::get_use_buffered_io () const
2625 return use_buffered_io_button.get_active();
2629 EngineControl::get_input_channels() const
2631 if (ARDOUR::Profile->get_mixbus()) {
2632 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2633 if (!backend) return 0;
2634 return backend->input_channels();
2636 return (uint32_t) input_channels_adjustment.get_value();
2640 EngineControl::get_output_channels() const
2642 if (ARDOUR::Profile->get_mixbus()) {
2643 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2644 if (!backend) return 0;
2645 return backend->input_channels();
2647 return (uint32_t) output_channels_adjustment.get_value();
2651 EngineControl::get_input_latency() const
2653 return (uint32_t) input_latency_adjustment.get_value();
2657 EngineControl::get_output_latency() const
2659 return (uint32_t) output_latency_adjustment.get_value();
2663 EngineControl::get_backend () const
2665 return backend_combo.get_active_text ();
2669 EngineControl::get_driver () const
2671 if (driver_combo.get_parent()) {
2672 return driver_combo.get_active_text ();
2679 EngineControl::get_device_name () const
2681 return device_combo.get_active_text ();
2685 EngineControl::get_input_device_name () const
2687 return input_device_combo.get_active_text ();
2691 EngineControl::get_output_device_name () const
2693 return output_device_combo.get_active_text ();
2697 EngineControl::control_app_button_clicked ()
2699 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2705 backend->launch_control_app ();
2709 EngineControl::start_stop_button_clicked ()
2711 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2717 if (ARDOUR::AudioEngine::instance()->running()) {
2718 ARDOUR::AudioEngine::instance()->stop ();
2720 if (!ARDOUR_UI::instance()->session_loaded) {
2724 if (!ARDOUR_UI::instance()->session_loaded) {
2725 ArdourDialog::on_response (RESPONSE_OK);
2726 if (Splash::instance()) {
2727 Splash::instance()->pop_front ();
2734 EngineControl::update_devices_button_clicked ()
2736 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2742 if (backend->update_devices()) {
2743 device_list_changed ();
2748 EngineControl::use_buffered_io_button_clicked ()
2750 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2756 bool set_buffered_io = !use_buffered_io_button.get_active();
2757 use_buffered_io_button.set_active (set_buffered_io);
2758 backend->set_use_buffered_io (set_buffered_io);
2762 EngineControl::manage_control_app_sensitivity ()
2764 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2770 string appname = backend->control_app_name();
2772 if (appname.empty()) {
2773 control_app_button.set_sensitive (false);
2775 control_app_button.set_sensitive (true);
2780 EngineControl::set_desired_sample_rate (uint32_t sr)
2782 _desired_sample_rate = sr;
2783 if (ARDOUR::AudioEngine::instance ()->running ()
2784 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2791 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2793 if (page_num == 0) {
2794 _measure_midi.reset();
2795 update_sensitivity ();
2798 if (page_num == midi_tab) {
2800 refresh_midi_display ();
2803 if (page_num == latency_tab) {
2806 if (ARDOUR::AudioEngine::instance()->running()) {
2811 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2813 /* save any existing latency values */
2815 uint32_t il = (uint32_t) input_latency.get_value ();
2816 uint32_t ol = (uint32_t) input_latency.get_value ();
2818 /* reset to zero so that our new test instance
2819 will be clean of any existing latency measures.
2821 NB. this should really be done by the backend
2822 when stated for latency measurement.
2825 input_latency.set_value (0);
2826 output_latency.set_value (0);
2828 push_state_to_backend (false);
2832 input_latency.set_value (il);
2833 output_latency.set_value (ol);
2836 // This should be done in push_state_to_backend()
2837 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2838 disable_latency_tab ();
2841 enable_latency_tab ();
2845 end_latency_detection ();
2846 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2851 /* latency measurement */
2854 EngineControl::check_audio_latency_measurement ()
2856 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2858 if (mtdm->resolve () < 0) {
2859 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2863 if (mtdm->get_peak () > 0.707f) {
2864 // get_peak() resets the peak-hold in the detector.
2865 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2866 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2870 if (mtdm->err () > 0.3) {
2876 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2878 if (sample_rate == 0) {
2879 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2880 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2884 int frames_total = mtdm->del();
2885 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2887 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2888 _("Detected roundtrip latency: "),
2889 frames_total, frames_total * 1000.0f/sample_rate,
2890 _("Systemic latency: "),
2891 extra, extra * 1000.0f/sample_rate);
2895 if (mtdm->err () > 0.2) {
2897 strcat (buf, _("(signal detection error)"));
2903 strcat (buf, _("(inverted - bad wiring)"));
2907 lm_results.set_markup (string_compose (results_markup, buf));
2910 have_lm_results = true;
2911 end_latency_detection ();
2912 lm_use_button.set_sensitive (true);
2920 EngineControl::check_midi_latency_measurement ()
2922 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2924 if (!mididm->have_signal () || mididm->latency () == 0) {
2925 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2930 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2932 if (sample_rate == 0) {
2933 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2934 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2938 ARDOUR::framecnt_t frames_total = mididm->latency();
2939 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2940 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2941 _("Detected roundtrip latency: "),
2942 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2943 _("Systemic latency: "),
2944 extra, extra * 1000.0f / sample_rate);
2948 if (!mididm->ok ()) {
2950 strcat (buf, _("(averaging)"));
2954 if (mididm->deviation () > 50.0) {
2956 strcat (buf, _("(too large jitter)"));
2958 } else if (mididm->deviation () > 10.0) {
2960 strcat (buf, _("(large jitter)"));
2964 have_lm_results = true;
2965 end_latency_detection ();
2966 lm_use_button.set_sensitive (true);
2967 lm_results.set_markup (string_compose (results_markup, buf));
2969 } else if (mididm->processed () > 400) {
2970 have_lm_results = false;
2971 end_latency_detection ();
2972 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2976 lm_results.set_markup (string_compose (results_markup, buf));
2982 EngineControl::start_latency_detection ()
2984 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2985 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2987 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2988 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2989 if (_measure_midi) {
2990 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2992 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2994 lm_measure_label.set_text (_("Cancel"));
2995 have_lm_results = false;
2996 lm_use_button.set_sensitive (false);
2997 lm_input_channel_combo.set_sensitive (false);
2998 lm_output_channel_combo.set_sensitive (false);
3004 EngineControl::end_latency_detection ()
3006 latency_timeout.disconnect ();
3007 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3008 lm_measure_label.set_text (_("Measure"));
3009 if (!have_lm_results) {
3010 lm_use_button.set_sensitive (false);
3012 lm_input_channel_combo.set_sensitive (true);
3013 lm_output_channel_combo.set_sensitive (true);
3018 EngineControl::latency_button_clicked ()
3021 start_latency_detection ();
3023 end_latency_detection ();
3028 EngineControl::latency_back_button_clicked ()
3030 ARDOUR::AudioEngine::instance()->stop(true);
3031 notebook.set_current_page(0);
3035 EngineControl::use_latency_button_clicked ()
3037 if (_measure_midi) {
3038 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3042 ARDOUR::framecnt_t frames_total = mididm->latency();
3043 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3044 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3045 _measure_midi->input_latency = one_way;
3046 _measure_midi->output_latency = one_way;
3047 notebook.set_current_page (midi_tab);
3049 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3055 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3056 one_way = std::max (0., one_way);
3058 input_latency_adjustment.set_value (one_way);
3059 output_latency_adjustment.set_value (one_way);
3061 /* back to settings page */
3062 notebook.set_current_page (0);
3067 EngineControl::on_delete_event (GdkEventAny* ev)
3069 if (notebook.get_current_page() == 2) {
3070 /* currently on latency tab - be sure to clean up */
3071 end_latency_detection ();
3073 return ArdourDialog::on_delete_event (ev);
3077 EngineControl::engine_running ()
3079 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3082 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3083 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3085 if (backend->can_set_period_size ()) {
3086 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3089 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3090 connect_disconnect_button.show();
3092 started_at_least_once = true;
3093 if (_have_control) {
3094 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3096 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3098 update_sensitivity();
3102 EngineControl::engine_stopped ()
3104 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3107 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3108 connect_disconnect_button.show();
3110 if (_have_control) {
3111 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3113 engine_status.set_markup(X_(""));
3116 update_sensitivity();
3120 EngineControl::device_list_changed ()
3122 if (ignore_device_changes) {
3125 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3127 midi_option_changed();
3131 EngineControl::connect_disconnect_click()
3133 if (ARDOUR::AudioEngine::instance()->running()) {
3136 if (!ARDOUR_UI::instance()->session_loaded) {
3140 if (!ARDOUR_UI::instance()->session_loaded) {
3141 ArdourDialog::on_response (RESPONSE_OK);
3142 if (Splash::instance()) {
3143 Splash::instance()->pop_front ();
3150 EngineControl::calibrate_audio_latency ()
3152 _measure_midi.reset ();
3153 have_lm_results = false;
3154 lm_use_button.set_sensitive (false);
3155 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3156 notebook.set_current_page (latency_tab);
3160 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3163 have_lm_results = false;
3164 lm_use_button.set_sensitive (false);
3165 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3166 notebook.set_current_page (latency_tab);
3170 EngineControl::configure_midi_devices ()
3172 notebook.set_current_page (midi_tab);