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"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
91 , lm_measure_label (_("Measure"))
92 , lm_use_button (_("Use results"))
93 , lm_back_button (_("Back to settings ... (ignore results)"))
94 , lm_button_audio (_("Calibrate Audio"))
96 , have_lm_results (false)
98 , midi_back_button (_("Back to settings"))
100 , ignore_device_changes (0)
101 , _desired_sample_rate (0)
102 , started_at_least_once (false)
103 , queue_device_changed (false)
104 , _have_control (true)
107 using namespace Notebook_Helpers;
108 vector<string> backend_names;
110 AttachOptions xopt = AttachOptions (FILL|EXPAND);
113 set_name (X_("AudioMIDISetup"));
115 /* the backend combo is the one thing that is ALWAYS visible */
117 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
119 if (backends.empty()) {
120 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));
122 throw failed_constructor ();
125 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
126 backend_names.push_back ((*b)->name);
129 set_popdown_strings (backend_combo, backend_names);
131 /* setup basic packing characteristics for the table used on the main
132 * tab of the notebook
135 basic_packer.set_spacings (6);
136 basic_packer.set_border_width (12);
137 basic_packer.set_homogeneous (false);
141 basic_hbox.pack_start (basic_packer, false, false);
143 /* latency measurement tab */
145 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
148 lm_table.set_row_spacings (12);
149 lm_table.set_col_spacings (6);
150 lm_table.set_homogeneous (false);
152 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
155 lm_preamble.set_width_chars (60);
156 lm_preamble.set_line_wrap (true);
157 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
159 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162 Gtk::Label* preamble;
163 preamble = manage (new Label);
164 preamble->set_width_chars (60);
165 preamble->set_line_wrap (true);
166 preamble->set_markup (_("Select two channels below and connect them using a cable."));
168 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
171 label = manage (new Label (_("Output channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_output_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
179 label = manage (new Label (_("Input channel")));
180 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
182 misc_align = manage (new Alignment (0.0, 0.5));
183 misc_align->add (lm_input_channel_combo);
184 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
187 lm_measure_label.set_padding (10, 10);
188 lm_measure_button.add (lm_measure_label);
189 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
190 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
191 lm_back_button_signal = lm_back_button.signal_clicked().connect(
192 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
194 lm_use_button.set_sensitive (false);
196 /* Increase the default spacing around the labels of these three
202 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
203 l->set_padding (10, 10);
206 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
207 l->set_padding (10, 10);
210 preamble = manage (new Label);
211 preamble->set_width_chars (60);
212 preamble->set_line_wrap (true);
213 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
214 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 preamble = manage (new Label);
218 preamble->set_width_chars (60);
219 preamble->set_line_wrap (true);
220 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
221 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 ++row; // skip a row in the table
224 ++row; // skip a row in the table
226 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 ++row; // skip a row in the table
229 ++row; // skip a row in the table
231 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
237 lm_vbox.set_border_width (12);
238 lm_vbox.pack_start (lm_table, false, false);
240 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
244 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
245 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
246 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
247 notebook.set_border_width (12);
249 notebook.set_show_tabs (false);
250 notebook.show_all ();
252 notebook.set_name ("SettingsNotebook");
254 /* packup the notebook */
256 get_vbox()->set_border_width (12);
257 get_vbox()->pack_start (notebook);
259 /* need a special function to print "all available channels" when the
260 * channel counts hit zero.
263 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
264 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
266 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
267 midi_devices_button.set_name ("generic button");
268 midi_devices_button.set_can_focus(true);
270 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
271 control_app_button.set_name ("generic button");
272 control_app_button.set_can_focus(true);
273 manage_control_app_sensitivity ();
275 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
276 start_stop_button.set_sensitive (false);
277 start_stop_button.set_name ("generic button");
278 start_stop_button.set_can_focus(true);
280 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
281 update_devices_button.set_sensitive (false);
282 update_devices_button.set_name ("generic button");
283 update_devices_button.set_can_focus(true);
285 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
286 use_buffered_io_button.set_sensitive (false);
287 use_buffered_io_button.set_name ("generic button");
288 use_buffered_io_button.set_can_focus(true);
290 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
291 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
293 /* Pick up any existing audio setup configuration, if appropriate */
295 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
297 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
298 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
299 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
300 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
303 if (!set_state (*audio_setup)) {
304 set_default_state ();
307 set_default_state ();
310 update_sensitivity ();
311 connect_changed_signals ();
313 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
315 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
317 connect_disconnect_button.set_no_show_all();
318 use_buffered_io_button.set_no_show_all();
319 update_devices_button.set_no_show_all();
320 start_stop_button.set_no_show_all();
321 midi_devices_button.set_no_show_all();
325 EngineControl::connect_changed_signals ()
327 backend_combo_connection = backend_combo.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::backend_changed));
329 driver_combo_connection = driver_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::driver_changed));
331 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
333 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
335 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
337 device_combo_connection = device_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::device_changed));
339 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
342 input_device_combo_connection = input_device_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::input_device_changed));
344 output_device_combo_connection = output_device_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::output_device_changed));
347 input_latency_connection = input_latency.signal_changed ().connect (
348 sigc::mem_fun (*this, &EngineControl::parameter_changed));
349 output_latency_connection = output_latency.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::parameter_changed));
351 input_channels_connection = input_channels.signal_changed ().connect (
352 sigc::mem_fun (*this, &EngineControl::parameter_changed));
353 output_channels_connection = output_channels.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::parameter_changed));
358 EngineControl::block_changed_signals ()
360 if (block_signals++ == 0) {
361 DEBUG_ECONTROL ("Blocking changed signals");
362 backend_combo_connection.block ();
363 driver_combo_connection.block ();
364 sample_rate_combo_connection.block ();
365 buffer_size_combo_connection.block ();
366 nperiods_combo_connection.block ();
367 device_combo_connection.block ();
368 input_device_combo_connection.block ();
369 output_device_combo_connection.block ();
370 midi_option_combo_connection.block ();
371 input_latency_connection.block ();
372 output_latency_connection.block ();
373 input_channels_connection.block ();
374 output_channels_connection.block ();
379 EngineControl::unblock_changed_signals ()
381 if (--block_signals == 0) {
382 DEBUG_ECONTROL ("Unblocking changed signals");
383 backend_combo_connection.unblock ();
384 driver_combo_connection.unblock ();
385 sample_rate_combo_connection.unblock ();
386 buffer_size_combo_connection.unblock ();
387 nperiods_combo_connection.unblock ();
388 device_combo_connection.unblock ();
389 input_device_combo_connection.unblock ();
390 output_device_combo_connection.unblock ();
391 midi_option_combo_connection.unblock ();
392 input_latency_connection.unblock ();
393 output_latency_connection.unblock ();
394 input_channels_connection.unblock ();
395 output_channels_connection.unblock ();
399 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
400 const std::string& reason)
401 : ec (engine_control)
404 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
405 ec.block_changed_signals ();
408 EngineControl::SignalBlocker::~SignalBlocker ()
410 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
411 ec.unblock_changed_signals ();
415 EngineControl::on_show ()
417 ArdourDialog::on_show ();
418 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
419 // re-check _have_control (jackd running) see #6041
423 ok_button->grab_focus();
427 EngineControl::try_autostart ()
429 if (!start_stop_button.get_sensitive()) {
432 if (ARDOUR::AudioEngine::instance()->running()) {
435 return start_engine ();
439 EngineControl::start_engine ()
441 if (push_state_to_backend(true) != 0) {
442 MessageDialog msg(*this,
443 ARDOUR::AudioEngine::instance()->get_last_backend_error());
451 EngineControl::stop_engine (bool for_latency)
453 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
454 MessageDialog msg(*this,
455 ARDOUR::AudioEngine::instance()->get_last_backend_error());
463 EngineControl::on_response (int response_id)
465 ArdourDialog::on_response (response_id);
467 switch (response_id) {
470 if (!start_engine()) {
474 #ifdef PLATFORM_WINDOWS
476 // But if there's no session open, this can produce
477 // a long gap when nothing appears to be happening.
478 // Let's show the splash image while we're waiting.
479 if (!ARDOUR_COMMAND_LINE::no_splash) {
480 if (ARDOUR_UI::instance()) {
481 if (!ARDOUR_UI::instance()->session_loaded) {
482 ARDOUR_UI::instance()->show_splash();
488 case RESPONSE_DELETE_EVENT: {
490 ev.type = GDK_BUTTON_PRESS;
492 on_delete_event((GdkEventAny*)&ev);
495 case RESPONSE_CANCEL:
496 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
497 ARDOUR_UI::instance()->check_audioengine(*this);
506 EngineControl::build_notebook ()
509 AttachOptions xopt = AttachOptions (FILL|EXPAND);
511 /* clear the table */
513 Gtkmm2ext::container_clear (basic_vbox);
514 Gtkmm2ext::container_clear (basic_packer);
516 if (control_app_button.get_parent()) {
517 control_app_button.get_parent()->remove (control_app_button);
520 label = manage (left_aligned_label (_("Audio System:")));
521 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
522 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
524 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
525 engine_status.show();
527 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
528 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
529 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
531 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
532 lm_button_audio.set_name ("generic button");
533 lm_button_audio.set_can_focus(true);
536 build_full_control_notebook ();
538 build_no_control_notebook ();
541 basic_vbox.pack_start (basic_hbox, false, false);
544 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
545 basic_vbox.show_all ();
550 EngineControl::build_full_control_notebook ()
552 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
555 using namespace Notebook_Helpers;
557 vector<string> strings;
558 AttachOptions xopt = AttachOptions (FILL|EXPAND);
559 int row = 1; // row zero == backend combo
561 /* start packing it up */
563 if (backend->requires_driver_selection()) {
564 label = manage (left_aligned_label (_("Driver:")));
565 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
570 if (backend->use_separate_input_and_output_devices()) {
571 label = manage (left_aligned_label (_("Input Device:")));
572 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
575 label = manage (left_aligned_label (_("Output Device:")));
576 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
577 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
579 // reset so it isn't used in state comparisons
580 device_combo.set_active_text ("");
582 label = manage (left_aligned_label (_("Device:")));
583 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
584 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
586 // reset these so they don't get used in state comparisons
587 input_device_combo.set_active_text ("");
588 output_device_combo.set_active_text ("");
591 label = manage (left_aligned_label (_("Sample rate:")));
592 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
593 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
597 label = manage (left_aligned_label (_("Buffer size:")));
598 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
599 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
600 buffer_size_duration_label.set_alignment (0.0); /* left-align */
601 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
603 int ctrl_btn_span = 1;
604 if (backend->can_set_period_size ()) {
606 label = manage (left_aligned_label (_("Periods:")));
607 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
608 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
612 /* button spans 2 or 3 rows */
614 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
617 input_channels.set_name ("InputChannels");
618 input_channels.set_flags (Gtk::CAN_FOCUS);
619 input_channels.set_digits (0);
620 input_channels.set_wrap (false);
621 output_channels.set_editable (true);
623 if (!ARDOUR::Profile->get_mixbus()) {
624 label = manage (left_aligned_label (_("Input Channels:")));
625 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
626 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
630 output_channels.set_name ("OutputChannels");
631 output_channels.set_flags (Gtk::CAN_FOCUS);
632 output_channels.set_digits (0);
633 output_channels.set_wrap (false);
634 output_channels.set_editable (true);
636 if (!ARDOUR::Profile->get_mixbus()) {
637 label = manage (left_aligned_label (_("Output Channels:")));
638 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
639 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
643 input_latency.set_name ("InputLatency");
644 input_latency.set_flags (Gtk::CAN_FOCUS);
645 input_latency.set_digits (0);
646 input_latency.set_wrap (false);
647 input_latency.set_editable (true);
649 label = manage (left_aligned_label (_("Hardware input latency:")));
650 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
651 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
652 label = manage (left_aligned_label (_("samples")));
653 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
656 output_latency.set_name ("OutputLatency");
657 output_latency.set_flags (Gtk::CAN_FOCUS);
658 output_latency.set_digits (0);
659 output_latency.set_wrap (false);
660 output_latency.set_editable (true);
662 label = manage (left_aligned_label (_("Hardware output latency:")));
663 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
664 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
665 label = manage (left_aligned_label (_("samples")));
666 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
668 /* button spans 2 rows */
670 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
673 label = manage (left_aligned_label (_("MIDI System:")));
674 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
675 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
676 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
681 EngineControl::build_no_control_notebook ()
683 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
686 using namespace Notebook_Helpers;
688 vector<string> strings;
689 AttachOptions xopt = AttachOptions (FILL|EXPAND);
690 int row = 1; // row zero == backend combo
691 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
693 label = manage (new Label);
694 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
695 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
698 if (backend->can_change_sample_rate_when_running()) {
699 label = manage (left_aligned_label (_("Sample rate:")));
700 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
701 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
705 if (backend->can_change_buffer_size_when_running()) {
706 label = manage (left_aligned_label (_("Buffer size:")));
707 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
708 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
709 buffer_size_duration_label.set_alignment (0.0); /* left-align */
710 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
714 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
718 EngineControl::~EngineControl ()
720 ignore_changes = true;
724 EngineControl::disable_latency_tab ()
726 vector<string> empty;
727 set_popdown_strings (lm_output_channel_combo, empty);
728 set_popdown_strings (lm_input_channel_combo, empty);
729 lm_measure_button.set_sensitive (false);
730 lm_use_button.set_sensitive (false);
734 EngineControl::enable_latency_tab ()
736 vector<string> outputs;
737 vector<string> inputs;
739 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
740 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
741 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
743 if (!ARDOUR::AudioEngine::instance()->running()) {
744 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
745 notebook.set_current_page (0);
749 else if (inputs.empty() || outputs.empty()) {
750 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
751 notebook.set_current_page (0);
756 lm_back_button_signal.disconnect();
758 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
761 lm_back_button_signal = lm_back_button.signal_clicked().connect(
762 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
766 set_popdown_strings (lm_output_channel_combo, outputs);
767 lm_output_channel_combo.set_active_text (outputs.front());
768 lm_output_channel_combo.set_sensitive (true);
770 set_popdown_strings (lm_input_channel_combo, inputs);
771 lm_input_channel_combo.set_active_text (inputs.front());
772 lm_input_channel_combo.set_sensitive (true);
774 lm_measure_button.set_sensitive (true);
778 EngineControl::setup_midi_tab_for_backend ()
780 string backend = backend_combo.get_active_text ();
782 Gtkmm2ext::container_clear (midi_vbox);
784 midi_vbox.set_border_width (12);
785 midi_device_table.set_border_width (12);
787 if (backend == "JACK") {
788 setup_midi_tab_for_jack ();
791 midi_vbox.pack_start (midi_device_table, true, true);
792 midi_vbox.pack_start (midi_back_button, false, false);
793 midi_vbox.show_all ();
797 EngineControl::update_sensitivity ()
799 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
801 ok_button->set_sensitive (false);
802 start_stop_button.set_sensitive (false);
807 size_t devices_available = 0;
809 if (backend->use_separate_input_and_output_devices ()) {
810 devices_available += get_popdown_string_count (input_device_combo);
811 devices_available += get_popdown_string_count (output_device_combo);
813 devices_available += get_popdown_string_count (device_combo);
816 if (devices_available == 0) {
818 input_latency.set_sensitive (false);
819 output_latency.set_sensitive (false);
820 input_channels.set_sensitive (false);
821 output_channels.set_sensitive (false);
823 input_latency.set_sensitive (true);
824 output_latency.set_sensitive (true);
825 input_channels.set_sensitive (true);
826 output_channels.set_sensitive (true);
829 if (get_popdown_string_count (buffer_size_combo) > 0) {
830 if (!ARDOUR::AudioEngine::instance()->running()) {
831 buffer_size_combo.set_sensitive (valid);
832 } else if (backend->can_change_sample_rate_when_running()) {
833 buffer_size_combo.set_sensitive (valid || !_have_control);
837 * Currently there is no way to manually stop the
838 * engine in order to re-configure it.
839 * This needs to remain sensitive for now.
841 * (it's also handy to implicily
842 * re-start the engine)
844 buffer_size_combo.set_sensitive (true);
846 buffer_size_combo.set_sensitive (false);
850 buffer_size_combo.set_sensitive (false);
854 if (get_popdown_string_count (sample_rate_combo) > 0) {
855 bool allow_to_set_rate = false;
856 if (!ARDOUR::AudioEngine::instance()->running()) {
857 if (!ARDOUR_UI::instance()->session_loaded) {
858 // engine is not running, no session loaded -> anything goes.
859 allow_to_set_rate = true;
860 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
861 // only allow to change if the current setting is not the native session rate.
862 allow_to_set_rate = true;
865 sample_rate_combo.set_sensitive (allow_to_set_rate);
867 sample_rate_combo.set_sensitive (false);
871 if (get_popdown_string_count (nperiods_combo) > 0) {
872 if (!ARDOUR::AudioEngine::instance()->running()) {
873 nperiods_combo.set_sensitive (true);
875 nperiods_combo.set_sensitive (false);
878 nperiods_combo.set_sensitive (false);
882 start_stop_button.set_sensitive(true);
883 start_stop_button.show();
884 if (ARDOUR::AudioEngine::instance()->running()) {
885 start_stop_button.set_text("Stop");
886 update_devices_button.set_sensitive(false);
887 use_buffered_io_button.set_sensitive(false);
889 if (backend->can_request_update_devices()) {
890 update_devices_button.show();
892 update_devices_button.hide();
894 if (backend->can_use_buffered_io()) {
895 use_buffered_io_button.show();
897 use_buffered_io_button.hide();
899 start_stop_button.set_text("Start");
900 update_devices_button.set_sensitive(true);
901 use_buffered_io_button.set_sensitive(true);
904 update_devices_button.set_sensitive(false);
905 update_devices_button.hide();
906 use_buffered_io_button.set_sensitive(false);
907 use_buffered_io_button.hide();
908 start_stop_button.set_sensitive(false);
909 start_stop_button.hide();
912 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
913 input_device_combo.set_sensitive (false);
914 output_device_combo.set_sensitive (false);
915 device_combo.set_sensitive (false);
916 driver_combo.set_sensitive (false);
918 input_device_combo.set_sensitive (true);
919 output_device_combo.set_sensitive (true);
920 device_combo.set_sensitive (true);
921 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
922 driver_combo.set_sensitive (true);
924 driver_combo.set_sensitive (false);
928 if (valid || !_have_control) {
929 ok_button->set_sensitive (true);
931 ok_button->set_sensitive (false);
936 EngineControl::setup_midi_tab_for_jack ()
941 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
943 device->input_latency = a->get_value();
945 device->output_latency = a->get_value();
950 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
951 b->set_active (!b->get_active());
952 device->enabled = b->get_active();
953 refresh_midi_display(device->name);
957 EngineControl::refresh_midi_display (std::string focus)
959 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
963 AttachOptions xopt = AttachOptions (FILL|EXPAND);
966 Gtkmm2ext::container_clear (midi_device_table);
968 midi_device_table.set_spacings (6);
970 l = manage (new Label);
971 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
972 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
973 l->set_alignment (0.5, 0.5);
977 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
978 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
979 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
980 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
982 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
983 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
984 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
985 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
988 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
993 bool enabled = (*p)->enabled;
995 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
996 m->set_name ("midi device");
997 m->set_can_focus (Gtk::CAN_FOCUS);
998 m->add_events (Gdk::BUTTON_RELEASE_MASK);
999 m->set_active (enabled);
1000 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
1001 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
1002 if ((*p)->name == focus) {
1006 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1007 s = manage (new Gtk::SpinButton (*a));
1008 a->set_value ((*p)->input_latency);
1009 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1010 s->set_sensitive (_can_set_midi_latencies && enabled);
1011 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1013 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1014 s = manage (new Gtk::SpinButton (*a));
1015 a->set_value ((*p)->output_latency);
1016 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1017 s->set_sensitive (_can_set_midi_latencies && enabled);
1018 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1020 b = manage (new Button (_("Calibrate")));
1021 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1022 b->set_sensitive (_can_set_midi_latencies && enabled);
1023 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1030 EngineControl::backend_changed ()
1032 SignalBlocker blocker (*this, "backend_changed");
1033 string backend_name = backend_combo.get_active_text();
1034 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1036 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1037 /* eh? setting the backend failed... how ? */
1038 /* A: stale config contains a backend that does not exist in current build */
1042 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1044 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1047 setup_midi_tab_for_backend ();
1048 _midi_devices.clear();
1050 if (backend->requires_driver_selection()) {
1051 if (set_driver_popdown_strings ()) {
1055 /* this will change the device text which will cause a call to
1056 * device changed which will set up parameters
1061 update_midi_options ();
1063 connect_disconnect_button.hide();
1065 midi_option_changed();
1067 started_at_least_once = false;
1069 /* changing the backend implies stopping the engine
1070 * ARDOUR::AudioEngine() may or may not emit this signal
1071 * depending on previous engine state
1073 engine_stopped (); // set "active/inactive"
1075 if (!_have_control) {
1076 // set settings from backend that we do have control over
1077 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1080 if (_have_control && !ignore_changes) {
1081 // set driver & devices
1082 State state = get_matching_state (backend_combo.get_active_text());
1084 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1085 set_current_state (state);
1089 if (!ignore_changes) {
1090 maybe_display_saved_state ();
1095 EngineControl::update_midi_options ()
1097 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1098 vector<string> midi_options = backend->enumerate_midi_options();
1100 if (midi_options.size() == 1) {
1101 /* only contains the "none" option */
1102 midi_option_combo.set_sensitive (false);
1104 if (_have_control) {
1105 set_popdown_strings (midi_option_combo, midi_options);
1106 midi_option_combo.set_active_text (midi_options.front());
1107 midi_option_combo.set_sensitive (true);
1109 midi_option_combo.set_sensitive (false);
1115 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1117 if (ARDOUR::Profile->get_mixbus()) {
1121 uint32_t cnt = (uint32_t) sb->get_value();
1123 sb->set_text (_("all available channels"));
1126 snprintf (buf, sizeof (buf), "%d", cnt);
1132 // @return true if there are drivers available
1134 EngineControl::set_driver_popdown_strings ()
1136 DEBUG_ECONTROL ("set_driver_popdown_strings");
1137 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1138 vector<string> drivers = backend->enumerate_drivers();
1140 if (drivers.empty ()) {
1141 // This is an error...?
1145 string current_driver = backend->driver_name ();
1147 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1149 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1152 current_driver = drivers.front ();
1155 set_popdown_strings (driver_combo, drivers);
1157 string_compose ("driver_combo.set_active_text: %1", current_driver));
1158 driver_combo.set_active_text (current_driver);
1163 EngineControl::get_default_device(const string& current_device_name,
1164 const vector<string>& available_devices)
1166 // If the current device is available, use it as default
1167 if (std::find (available_devices.begin (),
1168 available_devices.end (),
1169 current_device_name) != available_devices.end ()) {
1171 return current_device_name;
1174 using namespace ARDOUR;
1176 string default_device_name =
1177 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1179 vector<string>::const_iterator i;
1181 // If there is a "Default" device available, use it
1182 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1183 if (*i == default_device_name) {
1188 string none_device_name =
1189 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1191 // Use the first device that isn't "None"
1192 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1193 if (*i != none_device_name) {
1198 // Use "None" if there are no other available
1199 return available_devices.front();
1202 // @return true if there are devices available
1204 EngineControl::set_device_popdown_strings ()
1206 DEBUG_ECONTROL ("set_device_popdown_strings");
1207 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1208 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1210 /* NOTE: Ardour currently does not display the "available" field of the
1213 * Doing so would require a different GUI widget than the combo
1214 * box/popdown that we currently use, since it has no way to list
1215 * items that are not selectable. Something more like a popup menu,
1216 * which could have unselectable items, would be appropriate.
1219 vector<string> available_devices;
1221 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1222 available_devices.push_back (i->name);
1225 if (available_devices.empty ()) {
1229 set_popdown_strings (device_combo, available_devices);
1231 std::string default_device =
1232 get_default_device(backend->device_name(), available_devices);
1235 string_compose ("set device_combo active text: %1", default_device));
1237 device_combo.set_active_text(default_device);
1241 // @return true if there are input devices available
1243 EngineControl::set_input_device_popdown_strings ()
1245 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1246 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1247 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1249 vector<string> available_devices;
1251 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1252 available_devices.push_back (i->name);
1255 if (available_devices.empty()) {
1259 set_popdown_strings (input_device_combo, available_devices);
1261 std::string default_device =
1262 get_default_device(backend->input_device_name(), available_devices);
1265 string_compose ("set input_device_combo active text: %1", default_device));
1266 input_device_combo.set_active_text(default_device);
1270 // @return true if there are output devices available
1272 EngineControl::set_output_device_popdown_strings ()
1274 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1275 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1276 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1278 vector<string> available_devices;
1280 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1281 available_devices.push_back (i->name);
1284 if (available_devices.empty()) {
1288 set_popdown_strings (output_device_combo, available_devices);
1290 std::string default_device =
1291 get_default_device(backend->output_device_name(), available_devices);
1294 string_compose ("set output_device_combo active text: %1", default_device));
1295 output_device_combo.set_active_text(default_device);
1300 EngineControl::list_devices ()
1302 DEBUG_ECONTROL ("list_devices");
1303 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1306 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1308 bool devices_available = false;
1310 if (backend->use_separate_input_and_output_devices ()) {
1311 bool input_devices_available = set_input_device_popdown_strings ();
1312 bool output_devices_available = set_output_device_popdown_strings ();
1313 devices_available = input_devices_available || output_devices_available;
1315 devices_available = set_device_popdown_strings ();
1318 if (devices_available) {
1321 device_combo.clear();
1322 input_device_combo.clear();
1323 output_device_combo.clear();
1325 update_sensitivity ();
1329 EngineControl::driver_changed ()
1331 SignalBlocker blocker (*this, "driver_changed");
1332 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1335 backend->set_driver (driver_combo.get_active_text());
1338 // TODO load LRU device(s) for backend + driver combo
1340 if (!ignore_changes) {
1341 maybe_display_saved_state ();
1346 EngineControl::get_sample_rates_for_all_devices ()
1348 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1349 ARDOUR::AudioEngine::instance ()->current_backend ();
1350 vector<float> all_rates;
1352 if (backend->use_separate_input_and_output_devices ()) {
1353 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1355 all_rates = backend->available_sample_rates (get_device_name ());
1361 EngineControl::get_default_sample_rates ()
1363 vector<float> rates;
1364 rates.push_back (8000.0f);
1365 rates.push_back (16000.0f);
1366 rates.push_back (32000.0f);
1367 rates.push_back (44100.0f);
1368 rates.push_back (48000.0f);
1369 rates.push_back (88200.0f);
1370 rates.push_back (96000.0f);
1371 rates.push_back (192000.0f);
1372 rates.push_back (384000.0f);
1377 EngineControl::set_samplerate_popdown_strings ()
1379 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1380 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1385 if (_have_control) {
1386 sr = get_sample_rates_for_all_devices ();
1388 sr = get_default_sample_rates ();
1391 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1392 s.push_back (rate_as_string (*x));
1393 if (*x == _desired_sample_rate) {
1398 set_popdown_strings (sample_rate_combo, s);
1401 if (ARDOUR::AudioEngine::instance()->running()) {
1402 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1404 else if (desired.empty ()) {
1405 float new_active_sr = backend->default_sample_rate ();
1407 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1408 new_active_sr = sr.front ();
1411 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1413 sample_rate_combo.set_active_text (desired);
1417 update_sensitivity ();
1421 EngineControl::get_buffer_sizes_for_all_devices ()
1423 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1424 ARDOUR::AudioEngine::instance ()->current_backend ();
1425 vector<uint32_t> all_sizes;
1427 if (backend->use_separate_input_and_output_devices ()) {
1428 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1430 all_sizes = backend->available_buffer_sizes (get_device_name ());
1436 EngineControl::get_default_buffer_sizes ()
1438 vector<uint32_t> sizes;
1439 sizes.push_back (8);
1440 sizes.push_back (16);
1441 sizes.push_back (32);
1442 sizes.push_back (64);
1443 sizes.push_back (128);
1444 sizes.push_back (256);
1445 sizes.push_back (512);
1446 sizes.push_back (1024);
1447 sizes.push_back (2048);
1448 sizes.push_back (4096);
1449 sizes.push_back (8192);
1454 EngineControl::set_buffersize_popdown_strings ()
1456 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1457 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1458 vector<uint32_t> bs;
1461 if (_have_control) {
1462 bs = get_buffer_sizes_for_all_devices ();
1463 } else if (backend->can_change_buffer_size_when_running()) {
1464 bs = get_default_buffer_sizes ();
1467 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1468 s.push_back (bufsize_as_string (*x));
1471 uint32_t previous_size = 0;
1472 if (!buffer_size_combo.get_active_text().empty()) {
1473 previous_size = get_buffer_size ();
1476 set_popdown_strings (buffer_size_combo, s);
1480 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1481 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1484 buffer_size_combo.set_active_text(s.front());
1486 uint32_t period = backend->buffer_size();
1487 if (0 == period && backend->use_separate_input_and_output_devices()) {
1488 period = backend->default_buffer_size(get_input_device_name());
1490 if (0 == period && backend->use_separate_input_and_output_devices()) {
1491 period = backend->default_buffer_size(get_output_device_name());
1493 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1494 period = backend->default_buffer_size(get_device_name());
1497 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1499 show_buffer_duration ();
1501 update_sensitivity ();
1505 EngineControl::set_nperiods_popdown_strings ()
1507 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1508 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1509 vector<uint32_t> np;
1512 if (backend->can_set_period_size()) {
1513 np = backend->available_period_sizes (get_driver());
1516 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1517 s.push_back (nperiods_as_string (*x));
1520 set_popdown_strings (nperiods_combo, s);
1523 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1526 update_sensitivity ();
1530 EngineControl::device_changed ()
1532 SignalBlocker blocker (*this, "device_changed");
1533 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1536 string device_name_in;
1537 string device_name_out; // only used if backend support separate I/O devices
1539 if (backend->use_separate_input_and_output_devices()) {
1540 device_name_in = get_input_device_name ();
1541 device_name_out = get_output_device_name ();
1543 device_name_in = get_device_name ();
1546 /* we set the backend-device to query various device related intormation.
1547 * This has the side effect that backend->device_name() will match
1548 * the device_name and 'change_device' will never be true.
1549 * so work around this by setting...
1551 if (backend->use_separate_input_and_output_devices()) {
1552 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1553 queue_device_changed = true;
1556 if (device_name_in != backend->device_name()) {
1557 queue_device_changed = true;
1561 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1562 if (backend->use_separate_input_and_output_devices()) {
1563 backend->set_input_device_name (device_name_in);
1564 backend->set_output_device_name (device_name_out);
1566 backend->set_device_name(device_name_in);
1570 /* don't allow programmatic change to combos to cause a
1571 recursive call to this method.
1573 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1575 set_samplerate_popdown_strings ();
1576 set_buffersize_popdown_strings ();
1577 set_nperiods_popdown_strings ();
1579 /* TODO set min + max channel counts here */
1581 manage_control_app_sensitivity ();
1584 /* pick up any saved state for this device */
1586 if (!ignore_changes) {
1587 maybe_display_saved_state ();
1592 EngineControl::input_device_changed ()
1594 DEBUG_ECONTROL ("input_device_changed");
1596 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1597 if (backend && backend->match_input_output_devices_or_none ()) {
1598 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1600 if (get_output_device_name () != dev_none
1601 && get_input_device_name () != dev_none
1602 && get_input_device_name () != get_output_device_name ()) {
1603 block_changed_signals ();
1604 if (contains_value (output_device_combo, get_input_device_name ())) {
1605 output_device_combo.set_active_text (get_input_device_name ());
1607 assert (contains_value (output_device_combo, dev_none));
1608 output_device_combo.set_active_text (dev_none);
1610 unblock_changed_signals ();
1617 EngineControl::output_device_changed ()
1619 DEBUG_ECONTROL ("output_device_changed");
1620 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1621 if (backend && backend->match_input_output_devices_or_none ()) {
1622 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1624 if (get_input_device_name () != dev_none
1625 && get_input_device_name () != dev_none
1626 && get_input_device_name () != get_output_device_name ()) {
1627 block_changed_signals ();
1628 if (contains_value (input_device_combo, get_output_device_name ())) {
1629 input_device_combo.set_active_text (get_output_device_name ());
1631 assert (contains_value (input_device_combo, dev_none));
1632 input_device_combo.set_active_text (dev_none);
1634 unblock_changed_signals ();
1641 EngineControl::bufsize_as_string (uint32_t sz)
1643 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1647 EngineControl::nperiods_as_string (uint32_t np)
1650 snprintf (buf, sizeof (buf), "%u", np);
1656 EngineControl::sample_rate_changed ()
1658 DEBUG_ECONTROL ("sample_rate_changed");
1659 /* reset the strings for buffer size to show the correct msec value
1660 (reflecting the new sample rate).
1663 show_buffer_duration ();
1668 EngineControl::buffer_size_changed ()
1670 DEBUG_ECONTROL ("buffer_size_changed");
1671 show_buffer_duration ();
1675 EngineControl::nperiods_changed ()
1677 DEBUG_ECONTROL ("nperiods_changed");
1678 show_buffer_duration ();
1682 EngineControl::show_buffer_duration ()
1684 DEBUG_ECONTROL ("show_buffer_duration");
1685 /* buffer sizes - convert from just samples to samples + msecs for
1686 * the displayed string
1689 string bs_text = buffer_size_combo.get_active_text ();
1690 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1691 uint32_t rate = get_rate();
1693 /* Except for ALSA and Dummy backends, we don't know the number of periods
1694 * per cycle and settings.
1696 * jack1 vs jack2 have different default latencies since jack2 start
1697 * in async-mode unless --sync is given which adds an extra cycle
1698 * of latency. The value is not known if jackd is started externally..
1700 * So just display the period size, that's also what
1701 * ARDOUR_UI::update_sample_rate() does for the status bar.
1702 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1703 * but still, that's the buffer period, not [round-trip] latency)
1706 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1707 buffer_size_duration_label.set_text (buf);
1711 EngineControl::midi_option_changed ()
1713 DEBUG_ECONTROL ("midi_option_changed");
1714 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1717 backend->set_midi_option (get_midi_option());
1719 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1721 //_midi_devices.clear(); // TODO merge with state-saved settings..
1722 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1723 std::vector<MidiDeviceSettings> new_devices;
1725 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1726 MidiDeviceSettings mds = find_midi_device (i->name);
1727 if (i->available && !mds) {
1728 uint32_t input_latency = 0;
1729 uint32_t output_latency = 0;
1730 if (_can_set_midi_latencies) {
1731 input_latency = backend->systemic_midi_input_latency (i->name);
1732 output_latency = backend->systemic_midi_output_latency (i->name);
1734 bool enabled = backend->midi_device_enabled (i->name);
1735 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1736 new_devices.push_back (ptr);
1737 } else if (i->available) {
1738 new_devices.push_back (mds);
1741 _midi_devices = new_devices;
1743 if (_midi_devices.empty()) {
1744 midi_devices_button.hide ();
1746 midi_devices_button.show ();
1751 EngineControl::parameter_changed ()
1755 EngineControl::State
1756 EngineControl::get_matching_state (const string& backend)
1758 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1759 if ((*i)->backend == backend) {
1766 EngineControl::State
1767 EngineControl::get_matching_state (
1768 const string& backend,
1769 const string& driver,
1770 const string& device)
1772 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1773 if ((*i)->backend == backend &&
1774 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1782 EngineControl::State
1783 EngineControl::get_matching_state (
1784 const string& backend,
1785 const string& driver,
1786 const string& input_device,
1787 const string& output_device)
1789 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1790 if ((*i)->backend == backend &&
1791 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1799 EngineControl::State
1800 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1802 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1805 if (backend->use_separate_input_and_output_devices ()) {
1806 return get_matching_state (backend_combo.get_active_text(),
1807 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1808 input_device_combo.get_active_text(),
1809 output_device_combo.get_active_text());
1811 return get_matching_state (backend_combo.get_active_text(),
1812 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1813 device_combo.get_active_text());
1817 return get_matching_state (backend_combo.get_active_text(),
1819 device_combo.get_active_text());
1822 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1823 const EngineControl::State& state2)
1825 if (state1->backend == state2->backend &&
1826 state1->driver == state2->driver &&
1827 state1->device == state2->device &&
1828 state1->input_device == state2->input_device &&
1829 state1->output_device == state2->output_device) {
1836 EngineControl::state_sort_cmp (const State &a, const State &b) {
1840 else if (b->active) {
1844 return a->lru < b->lru;
1848 EngineControl::State
1849 EngineControl::save_state ()
1853 if (!_have_control) {
1854 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1856 state->lru = time (NULL) ;
1859 state.reset(new StateStruct);
1860 state->backend = get_backend ();
1862 state.reset(new StateStruct);
1863 store_state (state);
1866 for (StateList::iterator i = states.begin(); i != states.end();) {
1867 if (equivalent_states (*i, state)) {
1868 i = states.erase(i);
1874 states.push_back (state);
1876 states.sort (state_sort_cmp);
1882 EngineControl::store_state (State state)
1884 state->backend = get_backend ();
1885 state->driver = get_driver ();
1886 state->device = get_device_name ();
1887 state->input_device = get_input_device_name ();
1888 state->output_device = get_output_device_name ();
1889 state->sample_rate = get_rate ();
1890 state->buffer_size = get_buffer_size ();
1891 state->n_periods = get_nperiods ();
1892 state->input_latency = get_input_latency ();
1893 state->output_latency = get_output_latency ();
1894 state->input_channels = get_input_channels ();
1895 state->output_channels = get_output_channels ();
1896 state->midi_option = get_midi_option ();
1897 state->midi_devices = _midi_devices;
1898 state->use_buffered_io = get_use_buffered_io ();
1899 state->lru = time (NULL) ;
1903 EngineControl::maybe_display_saved_state ()
1905 if (!_have_control) {
1909 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1912 DEBUG_ECONTROL ("Restoring saved state");
1913 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1915 if (!_desired_sample_rate) {
1916 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1918 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1920 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1921 /* call this explicitly because we're ignoring changes to
1922 the controls at this point.
1924 show_buffer_duration ();
1925 input_latency.set_value (state->input_latency);
1926 output_latency.set_value (state->output_latency);
1928 use_buffered_io_button.set_active (state->use_buffered_io);
1930 if (!state->midi_option.empty()) {
1931 midi_option_combo.set_active_text (state->midi_option);
1932 _midi_devices = state->midi_devices;
1935 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1940 EngineControl::get_state ()
1944 XMLNode* root = new XMLNode ("AudioMIDISetup");
1947 if (!states.empty()) {
1948 XMLNode* state_nodes = new XMLNode ("EngineStates");
1950 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1952 XMLNode* node = new XMLNode ("State");
1954 node->add_property ("backend", (*i)->backend);
1955 node->add_property ("driver", (*i)->driver);
1956 node->add_property ("device", (*i)->device);
1957 node->add_property ("input-device", (*i)->input_device);
1958 node->add_property ("output-device", (*i)->output_device);
1959 node->add_property ("sample-rate", (*i)->sample_rate);
1960 node->add_property ("buffer-size", (*i)->buffer_size);
1961 node->add_property ("n-periods", (*i)->n_periods);
1962 node->add_property ("input-latency", (*i)->input_latency);
1963 node->add_property ("output-latency", (*i)->output_latency);
1964 node->add_property ("input-channels", (*i)->input_channels);
1965 node->add_property ("output-channels", (*i)->output_channels);
1966 node->add_property ("active", (*i)->active ? "yes" : "no");
1967 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1968 node->add_property ("midi-option", (*i)->midi_option);
1969 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1971 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1972 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1973 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1974 midi_device_stuff->add_property (X_("name"), (*p)->name);
1975 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1976 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1977 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1978 midi_devices->add_child_nocopy (*midi_device_stuff);
1980 node->add_child_nocopy (*midi_devices);
1982 state_nodes->add_child_nocopy (*node);
1985 root->add_child_nocopy (*state_nodes);
1992 EngineControl::set_default_state ()
1994 vector<string> backend_names;
1995 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1997 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1998 backend_names.push_back ((*b)->name);
2000 backend_combo.set_active_text (backend_names.front());
2002 // We could set default backends per platform etc here
2008 EngineControl::set_state (const XMLNode& root)
2010 XMLNodeList clist, cclist;
2011 XMLNodeConstIterator citer, cciter;
2012 XMLNode const * child;
2013 XMLNode const * grandchild;
2014 XMLProperty const * prop = NULL;
2016 if (root.name() != "AudioMIDISetup") {
2020 clist = root.children();
2024 for (citer = clist.begin(); citer != clist.end(); ++citer) {
2028 if (child->name() != "EngineStates") {
2032 cclist = child->children();
2034 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2035 State state (new StateStruct);
2037 grandchild = *cciter;
2039 if (grandchild->name() != "State") {
2043 if ((prop = grandchild->property ("backend")) == 0) {
2046 state->backend = prop->value ();
2048 if ((prop = grandchild->property ("driver")) == 0) {
2051 state->driver = prop->value ();
2053 if ((prop = grandchild->property ("device")) == 0) {
2056 state->device = prop->value ();
2058 if ((prop = grandchild->property ("input-device")) == 0) {
2061 state->input_device = prop->value ();
2063 if ((prop = grandchild->property ("output-device")) == 0) {
2066 state->output_device = prop->value ();
2068 if ((prop = grandchild->property ("sample-rate")) == 0) {
2071 state->sample_rate = atof (prop->value ());
2073 if ((prop = grandchild->property ("buffer-size")) == 0) {
2076 state->buffer_size = atoi (prop->value ());
2078 if ((prop = grandchild->property ("n-periods")) == 0) {
2079 // optional (new value in 4.5)
2080 state->n_periods = 0;
2082 state->n_periods = atoi (prop->value ());
2085 if ((prop = grandchild->property ("input-latency")) == 0) {
2088 state->input_latency = atoi (prop->value ());
2090 if ((prop = grandchild->property ("output-latency")) == 0) {
2093 state->output_latency = atoi (prop->value ());
2095 if ((prop = grandchild->property ("input-channels")) == 0) {
2098 state->input_channels = atoi (prop->value ());
2100 if ((prop = grandchild->property ("output-channels")) == 0) {
2103 state->output_channels = atoi (prop->value ());
2105 if ((prop = grandchild->property ("active")) == 0) {
2108 state->active = string_is_affirmative (prop->value ());
2110 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2113 state->use_buffered_io = string_is_affirmative (prop->value ());
2115 if ((prop = grandchild->property ("midi-option")) == 0) {
2118 state->midi_option = prop->value ();
2120 state->midi_devices.clear();
2122 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2123 const XMLNodeList mnc = midinode->children();
2124 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2125 if ((*n)->property (X_("name")) == 0
2126 || (*n)->property (X_("enabled")) == 0
2127 || (*n)->property (X_("input-latency")) == 0
2128 || (*n)->property (X_("output-latency")) == 0
2133 MidiDeviceSettings ptr (new MidiDeviceSetting(
2134 (*n)->property (X_("name"))->value (),
2135 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2136 atoi ((*n)->property (X_("input-latency"))->value ()),
2137 atoi ((*n)->property (X_("output-latency"))->value ())
2139 state->midi_devices.push_back (ptr);
2143 if ((prop = grandchild->property ("lru"))) {
2144 state->lru = atoi (prop->value ());
2148 /* remove accumulated duplicates (due to bug in ealier version)
2149 * this can be removed again before release
2151 for (StateList::iterator i = states.begin(); i != states.end();) {
2152 if ((*i)->backend == state->backend &&
2153 (*i)->driver == state->driver &&
2154 (*i)->device == state->device) {
2155 i = states.erase(i);
2162 states.push_back (state);
2166 /* now see if there was an active state and switch the setup to it */
2168 // purge states of backend that are not available in this built
2169 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2170 vector<std::string> backend_names;
2172 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2173 backend_names.push_back((*i)->name);
2175 for (StateList::iterator i = states.begin(); i != states.end();) {
2176 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2177 i = states.erase(i);
2183 states.sort (state_sort_cmp);
2185 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2188 return set_current_state (*i);
2195 EngineControl::set_current_state (const State& state)
2197 DEBUG_ECONTROL ("set_current_state");
2199 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2201 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2202 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2203 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2204 // this shouldn't happen as the invalid backend names should have been
2205 // removed from the list of states.
2209 // now reflect the change in the backend in the GUI so backend_changed will
2210 // do the right thing
2211 backend_combo.set_active_text (state->backend);
2213 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2215 // we don't have control don't restore state
2220 if (!state->driver.empty ()) {
2221 if (!backend->requires_driver_selection ()) {
2222 DEBUG_ECONTROL ("Backend should require driver selection");
2223 // A backend has changed from having driver selection to not having
2224 // it or someone has been manually editing a config file and messed
2229 if (backend->set_driver (state->driver) != 0) {
2230 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2231 // Driver names for a backend have changed and the name in the
2232 // config file is now invalid or support for driver is no longer
2233 // included in the backend
2236 // no need to set the driver_combo as backend_changed will use
2237 // backend->driver_name to set the active driver
2240 if (!state->device.empty ()) {
2241 if (backend->set_device_name (state->device) != 0) {
2243 string_compose ("Unable to set device name %1", state->device));
2244 // device is no longer available on the system
2247 // no need to set active device as it will be picked up in
2248 // via backend_changed ()/set_device_popdown_strings
2251 // backend supports separate input/output devices
2252 if (backend->set_input_device_name (state->input_device) != 0) {
2253 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2254 state->input_device));
2255 // input device is no longer available on the system
2259 if (backend->set_output_device_name (state->output_device) != 0) {
2260 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2261 state->input_device));
2262 // output device is no longer available on the system
2265 // no need to set active devices as it will be picked up in via
2266 // backend_changed ()/set_*_device_popdown_strings
2271 // Now restore the state of the rest of the controls
2273 // We don't use a SignalBlocker as set_current_state is currently only
2274 // called from set_state before any signals are connected. If at some point
2275 // a more general named state mechanism is implemented and
2276 // set_current_state is called while signals are connected then a
2277 // SignalBlocker will need to be instantiated before setting these.
2279 device_combo.set_active_text (state->device);
2280 input_device_combo.set_active_text (state->input_device);
2281 output_device_combo.set_active_text (state->output_device);
2282 if (!_desired_sample_rate) {
2283 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2285 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2286 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2287 input_latency.set_value (state->input_latency);
2288 output_latency.set_value (state->output_latency);
2289 midi_option_combo.set_active_text (state->midi_option);
2290 use_buffered_io_button.set_active (state->use_buffered_io);
2295 EngineControl::push_state_to_backend (bool start)
2297 DEBUG_ECONTROL ("push_state_to_backend");
2298 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2299 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2305 /* figure out what is going to change */
2307 bool restart_required = false;
2308 bool was_running = ARDOUR::AudioEngine::instance()->running();
2309 bool change_driver = false;
2310 bool change_device = false;
2311 bool change_rate = false;
2312 bool change_bufsize = false;
2313 bool change_nperiods = false;
2314 bool change_latency = false;
2315 bool change_channels = false;
2316 bool change_midi = false;
2317 bool change_buffered_io = false;
2319 uint32_t ochan = get_output_channels ();
2320 uint32_t ichan = get_input_channels ();
2322 if (_have_control) {
2324 if (started_at_least_once) {
2326 /* we can control the backend */
2328 if (backend->requires_driver_selection()) {
2329 if (get_driver() != backend->driver_name()) {
2330 change_driver = true;
2334 if (backend->use_separate_input_and_output_devices()) {
2335 if (get_input_device_name() != backend->input_device_name()) {
2336 change_device = true;
2338 if (get_output_device_name() != backend->output_device_name()) {
2339 change_device = true;
2342 if (get_device_name() != backend->device_name()) {
2343 change_device = true;
2347 if (queue_device_changed) {
2348 change_device = true;
2351 if (get_rate() != backend->sample_rate()) {
2355 if (get_buffer_size() != backend->buffer_size()) {
2356 change_bufsize = true;
2359 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2360 && get_nperiods() != backend->period_size()) {
2361 change_nperiods = true;
2364 if (get_midi_option() != backend->midi_option()) {
2368 if (backend->can_use_buffered_io()) {
2369 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2370 change_buffered_io = true;
2374 /* zero-requested channels means "all available" */
2377 ichan = backend->input_channels();
2381 ochan = backend->output_channels();
2384 if (ichan != backend->input_channels()) {
2385 change_channels = true;
2388 if (ochan != backend->output_channels()) {
2389 change_channels = true;
2392 if (get_input_latency() != backend->systemic_input_latency() ||
2393 get_output_latency() != backend->systemic_output_latency()) {
2394 change_latency = true;
2397 /* backend never started, so we have to force a group
2400 change_device = true;
2401 if (backend->requires_driver_selection()) {
2402 change_driver = true;
2405 change_bufsize = true;
2406 change_channels = true;
2407 change_latency = true;
2409 change_buffered_io = backend->can_use_buffered_io();
2410 change_channels = true;
2411 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2416 /* we have no control over the backend, meaning that we can
2417 * only possibly change sample rate and buffer size.
2421 if (get_rate() != backend->sample_rate()) {
2422 change_bufsize = true;
2425 if (get_buffer_size() != backend->buffer_size()) {
2426 change_bufsize = true;
2430 queue_device_changed = false;
2432 if (!_have_control) {
2434 /* We do not have control over the backend, so the best we can
2435 * do is try to change the sample rate and/or bufsize and get
2439 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2443 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2448 backend->set_sample_rate (get_rate());
2451 if (change_bufsize) {
2452 backend->set_buffer_size (get_buffer_size());
2456 if (ARDOUR::AudioEngine::instance()->start ()) {
2457 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2467 /* determine if we need to stop the backend before changing parameters */
2469 if (change_driver || change_device || change_channels || change_nperiods ||
2470 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2471 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2472 change_midi || change_buffered_io ||
2473 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2474 restart_required = true;
2476 restart_required = false;
2481 if (restart_required) {
2482 if (ARDOUR::AudioEngine::instance()->stop()) {
2488 if (change_driver && backend->set_driver (get_driver())) {
2489 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2492 if (backend->use_separate_input_and_output_devices()) {
2493 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2494 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2497 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2498 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2502 if (change_device && backend->set_device_name (get_device_name())) {
2503 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2507 if (change_rate && backend->set_sample_rate (get_rate())) {
2508 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2511 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2512 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2515 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2516 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2520 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2521 if (backend->set_input_channels (get_input_channels())) {
2522 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2525 if (backend->set_output_channels (get_output_channels())) {
2526 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2530 if (change_latency) {
2531 if (backend->set_systemic_input_latency (get_input_latency())) {
2532 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2535 if (backend->set_systemic_output_latency (get_output_latency())) {
2536 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2542 backend->set_midi_option (get_midi_option());
2545 if (change_buffered_io) {
2546 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2550 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2551 if (_measure_midi) {
2552 if (*p == _measure_midi) {
2553 backend->set_midi_device_enabled ((*p)->name, true);
2555 backend->set_midi_device_enabled ((*p)->name, false);
2557 if (backend->can_change_systemic_latency_when_running ()) {
2558 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2559 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2563 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2564 if (backend->can_set_systemic_midi_latencies()) {
2565 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2566 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2571 if (start || (was_running && restart_required)) {
2572 if (ARDOUR::AudioEngine::instance()->start()) {
2583 EngineControl::post_push ()
2585 /* get a pointer to the current state object, creating one if
2589 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2592 state = save_state ();
2598 states.sort (state_sort_cmp);
2602 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2603 (*i)->active = false;
2606 /* mark this one active (to be used next time the dialog is
2610 state->active = true;
2612 if (_have_control) { // XXX
2613 manage_control_app_sensitivity ();
2616 /* schedule a redisplay of MIDI ports */
2617 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2622 EngineControl::get_rate () const
2624 float r = atof (sample_rate_combo.get_active_text ());
2625 /* the string may have been translated with an abbreviation for
2626 * thousands, so use a crude heuristic to fix this.
2636 EngineControl::get_buffer_size () const
2638 string txt = buffer_size_combo.get_active_text ();
2641 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2642 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2643 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2651 EngineControl::get_nperiods () const
2653 string txt = nperiods_combo.get_active_text ();
2654 return atoi (txt.c_str());
2658 EngineControl::get_midi_option () const
2660 return midi_option_combo.get_active_text();
2664 EngineControl::get_use_buffered_io () const
2666 return use_buffered_io_button.get_active();
2670 EngineControl::get_input_channels() const
2672 if (ARDOUR::Profile->get_mixbus()) {
2673 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2674 if (!backend) return 0;
2675 return backend->input_channels();
2677 return (uint32_t) input_channels_adjustment.get_value();
2681 EngineControl::get_output_channels() const
2683 if (ARDOUR::Profile->get_mixbus()) {
2684 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2685 if (!backend) return 0;
2686 return backend->input_channels();
2688 return (uint32_t) output_channels_adjustment.get_value();
2692 EngineControl::get_input_latency() const
2694 return (uint32_t) input_latency_adjustment.get_value();
2698 EngineControl::get_output_latency() const
2700 return (uint32_t) output_latency_adjustment.get_value();
2704 EngineControl::get_backend () const
2706 return backend_combo.get_active_text ();
2710 EngineControl::get_driver () const
2712 if (driver_combo.get_parent()) {
2713 return driver_combo.get_active_text ();
2720 EngineControl::get_device_name () const
2722 return device_combo.get_active_text ();
2726 EngineControl::get_input_device_name () const
2728 return input_device_combo.get_active_text ();
2732 EngineControl::get_output_device_name () const
2734 return output_device_combo.get_active_text ();
2738 EngineControl::control_app_button_clicked ()
2740 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2746 backend->launch_control_app ();
2750 EngineControl::start_stop_button_clicked ()
2752 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2758 if (ARDOUR::AudioEngine::instance()->running()) {
2759 ARDOUR::AudioEngine::instance()->stop ();
2766 EngineControl::update_devices_button_clicked ()
2768 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2774 if (backend->update_devices()) {
2775 device_list_changed ();
2780 EngineControl::use_buffered_io_button_clicked ()
2782 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2788 bool set_buffered_io = !use_buffered_io_button.get_active();
2789 use_buffered_io_button.set_active (set_buffered_io);
2790 backend->set_use_buffered_io (set_buffered_io);
2794 EngineControl::manage_control_app_sensitivity ()
2796 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2802 string appname = backend->control_app_name();
2804 if (appname.empty()) {
2805 control_app_button.set_sensitive (false);
2807 control_app_button.set_sensitive (true);
2812 EngineControl::set_desired_sample_rate (uint32_t sr)
2814 _desired_sample_rate = sr;
2815 if (ARDOUR::AudioEngine::instance ()->running ()
2816 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2823 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2825 if (page_num == 0) {
2826 cancel_button->set_sensitive (true);
2827 _measure_midi.reset();
2828 update_sensitivity ();
2830 cancel_button->set_sensitive (false);
2831 ok_button->set_sensitive (false);
2834 if (page_num == midi_tab) {
2836 refresh_midi_display ();
2839 if (page_num == latency_tab) {
2842 if (ARDOUR::AudioEngine::instance()->running()) {
2847 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2849 /* save any existing latency values */
2851 uint32_t il = (uint32_t) input_latency.get_value ();
2852 uint32_t ol = (uint32_t) input_latency.get_value ();
2854 /* reset to zero so that our new test instance
2855 will be clean of any existing latency measures.
2857 NB. this should really be done by the backend
2858 when stated for latency measurement.
2861 input_latency.set_value (0);
2862 output_latency.set_value (0);
2864 push_state_to_backend (false);
2868 input_latency.set_value (il);
2869 output_latency.set_value (ol);
2872 // This should be done in push_state_to_backend()
2873 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2874 disable_latency_tab ();
2877 enable_latency_tab ();
2881 end_latency_detection ();
2882 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2887 /* latency measurement */
2890 EngineControl::check_audio_latency_measurement ()
2892 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2894 if (mtdm->resolve () < 0) {
2895 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2899 if (mtdm->get_peak () > 0.707f) {
2900 // get_peak() resets the peak-hold in the detector.
2901 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2902 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2906 if (mtdm->err () > 0.3) {
2912 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2914 if (sample_rate == 0) {
2915 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2916 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2920 int frames_total = mtdm->del();
2921 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2923 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2924 _("Detected roundtrip latency: "),
2925 frames_total, frames_total * 1000.0f/sample_rate,
2926 _("Systemic latency: "),
2927 extra, extra * 1000.0f/sample_rate);
2931 if (mtdm->err () > 0.2) {
2933 strcat (buf, _("(signal detection error)"));
2939 strcat (buf, _("(inverted - bad wiring)"));
2943 lm_results.set_markup (string_compose (results_markup, buf));
2946 have_lm_results = true;
2947 end_latency_detection ();
2948 lm_use_button.set_sensitive (true);
2956 EngineControl::check_midi_latency_measurement ()
2958 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2960 if (!mididm->have_signal () || mididm->latency () == 0) {
2961 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2966 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2968 if (sample_rate == 0) {
2969 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2970 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2974 ARDOUR::framecnt_t frames_total = mididm->latency();
2975 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2976 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2977 _("Detected roundtrip latency: "),
2978 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2979 _("Systemic latency: "),
2980 extra, extra * 1000.0f / sample_rate);
2984 if (!mididm->ok ()) {
2986 strcat (buf, _("(averaging)"));
2990 if (mididm->deviation () > 50.0) {
2992 strcat (buf, _("(too large jitter)"));
2994 } else if (mididm->deviation () > 10.0) {
2996 strcat (buf, _("(large jitter)"));
3000 have_lm_results = true;
3001 end_latency_detection ();
3002 lm_use_button.set_sensitive (true);
3003 lm_results.set_markup (string_compose (results_markup, buf));
3005 } else if (mididm->processed () > 400) {
3006 have_lm_results = false;
3007 end_latency_detection ();
3008 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3012 lm_results.set_markup (string_compose (results_markup, buf));
3018 EngineControl::start_latency_detection ()
3020 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
3021 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
3023 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3024 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3025 if (_measure_midi) {
3026 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3028 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3030 lm_measure_label.set_text (_("Cancel"));
3031 have_lm_results = false;
3032 lm_use_button.set_sensitive (false);
3033 lm_input_channel_combo.set_sensitive (false);
3034 lm_output_channel_combo.set_sensitive (false);
3040 EngineControl::end_latency_detection ()
3042 latency_timeout.disconnect ();
3043 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3044 lm_measure_label.set_text (_("Measure"));
3045 if (!have_lm_results) {
3046 lm_use_button.set_sensitive (false);
3048 lm_input_channel_combo.set_sensitive (true);
3049 lm_output_channel_combo.set_sensitive (true);
3054 EngineControl::latency_button_clicked ()
3057 start_latency_detection ();
3059 end_latency_detection ();
3064 EngineControl::latency_back_button_clicked ()
3066 ARDOUR::AudioEngine::instance()->stop(true);
3067 notebook.set_current_page(0);
3071 EngineControl::use_latency_button_clicked ()
3073 if (_measure_midi) {
3074 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3078 ARDOUR::framecnt_t frames_total = mididm->latency();
3079 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3080 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3081 _measure_midi->input_latency = one_way;
3082 _measure_midi->output_latency = one_way;
3083 notebook.set_current_page (midi_tab);
3085 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3091 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3092 one_way = std::max (0., one_way);
3094 input_latency_adjustment.set_value (one_way);
3095 output_latency_adjustment.set_value (one_way);
3097 /* back to settings page */
3098 notebook.set_current_page (0);
3103 EngineControl::on_delete_event (GdkEventAny* ev)
3105 if (notebook.get_current_page() == 2) {
3106 /* currently on latency tab - be sure to clean up */
3107 end_latency_detection ();
3109 return ArdourDialog::on_delete_event (ev);
3113 EngineControl::engine_running ()
3115 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3118 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3119 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3121 if (backend->can_set_period_size ()) {
3122 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3125 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3126 connect_disconnect_button.show();
3128 started_at_least_once = true;
3129 if (_have_control) {
3130 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3132 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3134 update_sensitivity();
3138 EngineControl::engine_stopped ()
3140 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3143 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3144 connect_disconnect_button.show();
3146 if (_have_control) {
3147 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3149 engine_status.set_markup(X_(""));
3152 update_sensitivity();
3156 EngineControl::device_list_changed ()
3158 if (ignore_device_changes) {
3161 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3163 midi_option_changed();
3167 EngineControl::connect_disconnect_click()
3169 if (ARDOUR::AudioEngine::instance()->running()) {
3177 EngineControl::calibrate_audio_latency ()
3179 _measure_midi.reset ();
3180 have_lm_results = false;
3181 lm_use_button.set_sensitive (false);
3182 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3183 notebook.set_current_page (latency_tab);
3187 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3190 have_lm_results = false;
3191 lm_use_button.set_sensitive (false);
3192 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3193 notebook.set_current_page (latency_tab);
3197 EngineControl::configure_midi_devices ()
3199 notebook.set_current_page (midi_tab);