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) {
469 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 if (!ARDOUR::AudioEngine::instance()->running()) {
856 sample_rate_combo.set_sensitive (true);
858 sample_rate_combo.set_sensitive (false);
861 sample_rate_combo.set_sensitive (false);
865 if (get_popdown_string_count (nperiods_combo) > 0) {
866 if (!ARDOUR::AudioEngine::instance()->running()) {
867 nperiods_combo.set_sensitive (true);
869 nperiods_combo.set_sensitive (false);
872 nperiods_combo.set_sensitive (false);
876 start_stop_button.set_sensitive(true);
877 start_stop_button.show();
878 if (ARDOUR::AudioEngine::instance()->running()) {
879 start_stop_button.set_text("Stop");
880 update_devices_button.set_sensitive(false);
881 use_buffered_io_button.set_sensitive(false);
883 if (backend->can_request_update_devices()) {
884 update_devices_button.show();
886 update_devices_button.hide();
888 if (backend->can_use_buffered_io()) {
889 use_buffered_io_button.show();
891 use_buffered_io_button.hide();
893 start_stop_button.set_text("Start");
894 update_devices_button.set_sensitive(true);
895 use_buffered_io_button.set_sensitive(true);
898 update_devices_button.set_sensitive(false);
899 update_devices_button.hide();
900 use_buffered_io_button.set_sensitive(false);
901 use_buffered_io_button.hide();
902 start_stop_button.set_sensitive(false);
903 start_stop_button.hide();
906 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
907 input_device_combo.set_sensitive (false);
908 output_device_combo.set_sensitive (false);
909 device_combo.set_sensitive (false);
910 driver_combo.set_sensitive (false);
912 input_device_combo.set_sensitive (true);
913 output_device_combo.set_sensitive (true);
914 device_combo.set_sensitive (true);
915 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
916 driver_combo.set_sensitive (true);
918 driver_combo.set_sensitive (false);
922 if (valid || !_have_control) {
923 ok_button->set_sensitive (true);
925 ok_button->set_sensitive (false);
930 EngineControl::setup_midi_tab_for_jack ()
935 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
937 device->input_latency = a->get_value();
939 device->output_latency = a->get_value();
944 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
945 b->set_active (!b->get_active());
946 device->enabled = b->get_active();
947 refresh_midi_display(device->name);
951 EngineControl::refresh_midi_display (std::string focus)
953 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
957 AttachOptions xopt = AttachOptions (FILL|EXPAND);
960 Gtkmm2ext::container_clear (midi_device_table);
962 midi_device_table.set_spacings (6);
964 l = manage (new Label);
965 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
966 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
967 l->set_alignment (0.5, 0.5);
971 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
972 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
973 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
974 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
976 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
977 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
978 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
979 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
982 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
987 bool enabled = (*p)->enabled;
989 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
990 m->set_name ("midi device");
991 m->set_can_focus (Gtk::CAN_FOCUS);
992 m->add_events (Gdk::BUTTON_RELEASE_MASK);
993 m->set_active (enabled);
994 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
995 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
996 if ((*p)->name == focus) {
1000 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1001 s = manage (new Gtk::SpinButton (*a));
1002 a->set_value ((*p)->input_latency);
1003 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1004 s->set_sensitive (_can_set_midi_latencies && enabled);
1005 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1007 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1008 s = manage (new Gtk::SpinButton (*a));
1009 a->set_value ((*p)->output_latency);
1010 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1011 s->set_sensitive (_can_set_midi_latencies && enabled);
1012 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1014 b = manage (new Button (_("Calibrate")));
1015 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1016 b->set_sensitive (_can_set_midi_latencies && enabled);
1017 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1024 EngineControl::backend_changed ()
1026 SignalBlocker blocker (*this, "backend_changed");
1027 string backend_name = backend_combo.get_active_text();
1028 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1030 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1031 /* eh? setting the backend failed... how ? */
1032 /* A: stale config contains a backend that does not exist in current build */
1036 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1038 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1041 setup_midi_tab_for_backend ();
1042 _midi_devices.clear();
1044 if (backend->requires_driver_selection()) {
1045 if (set_driver_popdown_strings ()) {
1049 /* this will change the device text which will cause a call to
1050 * device changed which will set up parameters
1055 update_midi_options ();
1057 connect_disconnect_button.hide();
1059 midi_option_changed();
1061 started_at_least_once = false;
1063 /* changing the backend implies stopping the engine
1064 * ARDOUR::AudioEngine() may or may not emit this signal
1065 * depending on previous engine state
1067 engine_stopped (); // set "active/inactive"
1069 if (!_have_control) {
1070 // set settings from backend that we do have control over
1071 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1074 if (_have_control && !ignore_changes) {
1075 // set driver & devices
1076 State state = get_matching_state (backend_combo.get_active_text());
1078 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1079 set_current_state (state);
1083 if (!ignore_changes) {
1084 maybe_display_saved_state ();
1089 EngineControl::update_midi_options ()
1091 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1092 vector<string> midi_options = backend->enumerate_midi_options();
1094 if (midi_options.size() == 1) {
1095 /* only contains the "none" option */
1096 midi_option_combo.set_sensitive (false);
1098 if (_have_control) {
1099 set_popdown_strings (midi_option_combo, midi_options);
1100 midi_option_combo.set_active_text (midi_options.front());
1101 midi_option_combo.set_sensitive (true);
1103 midi_option_combo.set_sensitive (false);
1109 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1111 if (ARDOUR::Profile->get_mixbus()) {
1115 uint32_t cnt = (uint32_t) sb->get_value();
1117 sb->set_text (_("all available channels"));
1120 snprintf (buf, sizeof (buf), "%d", cnt);
1126 // @return true if there are drivers available
1128 EngineControl::set_driver_popdown_strings ()
1130 DEBUG_ECONTROL ("set_driver_popdown_strings");
1131 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1132 vector<string> drivers = backend->enumerate_drivers();
1134 if (drivers.empty ()) {
1135 // This is an error...?
1139 string current_driver = backend->driver_name ();
1141 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1143 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1146 current_driver = drivers.front ();
1149 set_popdown_strings (driver_combo, drivers);
1151 string_compose ("driver_combo.set_active_text: %1", current_driver));
1152 driver_combo.set_active_text (current_driver);
1157 EngineControl::get_default_device(const string& current_device_name,
1158 const vector<string>& available_devices)
1160 // If the current device is available, use it as default
1161 if (std::find (available_devices.begin (),
1162 available_devices.end (),
1163 current_device_name) != available_devices.end ()) {
1165 return current_device_name;
1168 using namespace ARDOUR;
1170 string default_device_name =
1171 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1173 vector<string>::const_iterator i;
1175 // If there is a "Default" device available, use it
1176 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1177 if (*i == default_device_name) {
1182 string none_device_name =
1183 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1185 // Use the first device that isn't "None"
1186 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1187 if (*i != none_device_name) {
1192 // Use "None" if there are no other available
1193 return available_devices.front();
1196 // @return true if there are devices available
1198 EngineControl::set_device_popdown_strings ()
1200 DEBUG_ECONTROL ("set_device_popdown_strings");
1201 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1202 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1204 /* NOTE: Ardour currently does not display the "available" field of the
1207 * Doing so would require a different GUI widget than the combo
1208 * box/popdown that we currently use, since it has no way to list
1209 * items that are not selectable. Something more like a popup menu,
1210 * which could have unselectable items, would be appropriate.
1213 vector<string> available_devices;
1215 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1216 available_devices.push_back (i->name);
1219 if (available_devices.empty ()) {
1223 set_popdown_strings (device_combo, available_devices);
1225 std::string default_device =
1226 get_default_device(backend->device_name(), available_devices);
1229 string_compose ("set device_combo active text: %1", default_device));
1231 device_combo.set_active_text(default_device);
1235 // @return true if there are input devices available
1237 EngineControl::set_input_device_popdown_strings ()
1239 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1240 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1241 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1243 vector<string> available_devices;
1245 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1246 available_devices.push_back (i->name);
1249 if (available_devices.empty()) {
1253 set_popdown_strings (input_device_combo, available_devices);
1255 std::string default_device =
1256 get_default_device(backend->input_device_name(), available_devices);
1259 string_compose ("set input_device_combo active text: %1", default_device));
1260 input_device_combo.set_active_text(default_device);
1264 // @return true if there are output devices available
1266 EngineControl::set_output_device_popdown_strings ()
1268 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1269 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1270 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1272 vector<string> available_devices;
1274 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1275 available_devices.push_back (i->name);
1278 if (available_devices.empty()) {
1282 set_popdown_strings (output_device_combo, available_devices);
1284 std::string default_device =
1285 get_default_device(backend->output_device_name(), available_devices);
1288 string_compose ("set output_device_combo active text: %1", default_device));
1289 output_device_combo.set_active_text(default_device);
1294 EngineControl::list_devices ()
1296 DEBUG_ECONTROL ("list_devices");
1297 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1300 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1302 bool devices_available = false;
1304 if (backend->use_separate_input_and_output_devices ()) {
1305 bool input_devices_available = set_input_device_popdown_strings ();
1306 bool output_devices_available = set_output_device_popdown_strings ();
1307 devices_available = input_devices_available || output_devices_available;
1309 devices_available = set_device_popdown_strings ();
1312 if (devices_available) {
1315 device_combo.clear();
1316 input_device_combo.clear();
1317 output_device_combo.clear();
1319 update_sensitivity ();
1323 EngineControl::driver_changed ()
1325 SignalBlocker blocker (*this, "driver_changed");
1326 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1329 backend->set_driver (driver_combo.get_active_text());
1332 // TODO load LRU device(s) for backend + driver combo
1334 if (!ignore_changes) {
1335 maybe_display_saved_state ();
1340 EngineControl::get_sample_rates_for_all_devices ()
1342 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1343 ARDOUR::AudioEngine::instance ()->current_backend ();
1344 vector<float> all_rates;
1346 if (backend->use_separate_input_and_output_devices ()) {
1347 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1349 all_rates = backend->available_sample_rates (get_device_name ());
1355 EngineControl::get_default_sample_rates ()
1357 vector<float> rates;
1358 rates.push_back (8000.0f);
1359 rates.push_back (16000.0f);
1360 rates.push_back (32000.0f);
1361 rates.push_back (44100.0f);
1362 rates.push_back (48000.0f);
1363 rates.push_back (88200.0f);
1364 rates.push_back (96000.0f);
1365 rates.push_back (192000.0f);
1366 rates.push_back (384000.0f);
1371 EngineControl::set_samplerate_popdown_strings ()
1373 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1374 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1379 if (_have_control) {
1380 sr = get_sample_rates_for_all_devices ();
1382 sr = get_default_sample_rates ();
1385 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1386 s.push_back (rate_as_string (*x));
1387 if (*x == _desired_sample_rate) {
1392 set_popdown_strings (sample_rate_combo, s);
1395 if (desired.empty ()) {
1396 float new_active_sr = backend->default_sample_rate ();
1398 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1399 new_active_sr = sr.front ();
1402 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1404 sample_rate_combo.set_active_text (desired);
1408 update_sensitivity ();
1412 EngineControl::get_buffer_sizes_for_all_devices ()
1414 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1415 ARDOUR::AudioEngine::instance ()->current_backend ();
1416 vector<uint32_t> all_sizes;
1418 if (backend->use_separate_input_and_output_devices ()) {
1419 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1421 all_sizes = backend->available_buffer_sizes (get_device_name ());
1427 EngineControl::get_default_buffer_sizes ()
1429 vector<uint32_t> sizes;
1430 sizes.push_back (8);
1431 sizes.push_back (16);
1432 sizes.push_back (32);
1433 sizes.push_back (64);
1434 sizes.push_back (128);
1435 sizes.push_back (256);
1436 sizes.push_back (512);
1437 sizes.push_back (1024);
1438 sizes.push_back (2048);
1439 sizes.push_back (4096);
1440 sizes.push_back (8192);
1445 EngineControl::set_buffersize_popdown_strings ()
1447 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1448 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1449 vector<uint32_t> bs;
1452 if (_have_control) {
1453 bs = get_buffer_sizes_for_all_devices ();
1454 } else if (backend->can_change_buffer_size_when_running()) {
1455 bs = get_default_buffer_sizes ();
1458 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1459 s.push_back (bufsize_as_string (*x));
1462 uint32_t previous_size = 0;
1463 if (!buffer_size_combo.get_active_text().empty()) {
1464 previous_size = get_buffer_size ();
1467 set_popdown_strings (buffer_size_combo, s);
1471 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1472 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1475 buffer_size_combo.set_active_text(s.front());
1477 uint32_t period = backend->buffer_size();
1478 if (0 == period && backend->use_separate_input_and_output_devices()) {
1479 period = backend->default_buffer_size(get_input_device_name());
1481 if (0 == period && backend->use_separate_input_and_output_devices()) {
1482 period = backend->default_buffer_size(get_output_device_name());
1484 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1485 period = backend->default_buffer_size(get_device_name());
1488 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1490 show_buffer_duration ();
1492 update_sensitivity ();
1496 EngineControl::set_nperiods_popdown_strings ()
1498 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1499 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1500 vector<uint32_t> np;
1503 if (backend->can_set_period_size()) {
1504 np = backend->available_period_sizes (get_driver());
1507 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1508 s.push_back (nperiods_as_string (*x));
1511 set_popdown_strings (nperiods_combo, s);
1514 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1517 update_sensitivity ();
1521 EngineControl::device_changed ()
1523 SignalBlocker blocker (*this, "device_changed");
1524 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1527 string device_name_in;
1528 string device_name_out; // only used if backend support separate I/O devices
1530 if (backend->use_separate_input_and_output_devices()) {
1531 device_name_in = get_input_device_name ();
1532 device_name_out = get_output_device_name ();
1534 device_name_in = get_device_name ();
1537 /* we set the backend-device to query various device related intormation.
1538 * This has the side effect that backend->device_name() will match
1539 * the device_name and 'change_device' will never be true.
1540 * so work around this by setting...
1542 if (backend->use_separate_input_and_output_devices()) {
1543 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1544 queue_device_changed = true;
1547 if (device_name_in != backend->device_name()) {
1548 queue_device_changed = true;
1552 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1553 if (backend->use_separate_input_and_output_devices()) {
1554 backend->set_input_device_name (device_name_in);
1555 backend->set_output_device_name (device_name_out);
1557 backend->set_device_name(device_name_in);
1561 /* don't allow programmatic change to combos to cause a
1562 recursive call to this method.
1564 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1566 set_samplerate_popdown_strings ();
1567 set_buffersize_popdown_strings ();
1568 set_nperiods_popdown_strings ();
1570 /* TODO set min + max channel counts here */
1572 manage_control_app_sensitivity ();
1575 /* pick up any saved state for this device */
1577 if (!ignore_changes) {
1578 maybe_display_saved_state ();
1583 EngineControl::input_device_changed ()
1585 DEBUG_ECONTROL ("input_device_changed");
1590 EngineControl::output_device_changed ()
1592 DEBUG_ECONTROL ("output_device_changed");
1597 EngineControl::bufsize_as_string (uint32_t sz)
1599 /* Translators: "samples" is always plural here, so no
1600 need for plural+singular forms.
1603 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1608 EngineControl::nperiods_as_string (uint32_t np)
1611 snprintf (buf, sizeof (buf), "%u", np);
1617 EngineControl::sample_rate_changed ()
1619 DEBUG_ECONTROL ("sample_rate_changed");
1620 /* reset the strings for buffer size to show the correct msec value
1621 (reflecting the new sample rate).
1624 show_buffer_duration ();
1629 EngineControl::buffer_size_changed ()
1631 DEBUG_ECONTROL ("buffer_size_changed");
1632 show_buffer_duration ();
1636 EngineControl::nperiods_changed ()
1638 DEBUG_ECONTROL ("nperiods_changed");
1639 show_buffer_duration ();
1643 EngineControl::show_buffer_duration ()
1645 DEBUG_ECONTROL ("show_buffer_duration");
1646 /* buffer sizes - convert from just samples to samples + msecs for
1647 * the displayed string
1650 string bs_text = buffer_size_combo.get_active_text ();
1651 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1652 uint32_t rate = get_rate();
1654 /* Except for ALSA and Dummy backends, we don't know the number of periods
1655 * per cycle and settings.
1657 * jack1 vs jack2 have different default latencies since jack2 start
1658 * in async-mode unless --sync is given which adds an extra cycle
1659 * of latency. The value is not known if jackd is started externally..
1661 * So just display the period size, that's also what
1662 * ARDOUR_UI::update_sample_rate() does for the status bar.
1663 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1664 * but still, that's the buffer period, not [round-trip] latency)
1667 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1668 buffer_size_duration_label.set_text (buf);
1672 EngineControl::midi_option_changed ()
1674 DEBUG_ECONTROL ("midi_option_changed");
1675 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1678 backend->set_midi_option (get_midi_option());
1680 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1682 //_midi_devices.clear(); // TODO merge with state-saved settings..
1683 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1684 std::vector<MidiDeviceSettings> new_devices;
1686 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1687 MidiDeviceSettings mds = find_midi_device (i->name);
1688 if (i->available && !mds) {
1689 uint32_t input_latency = 0;
1690 uint32_t output_latency = 0;
1691 if (_can_set_midi_latencies) {
1692 input_latency = backend->systemic_midi_input_latency (i->name);
1693 output_latency = backend->systemic_midi_output_latency (i->name);
1695 bool enabled = backend->midi_device_enabled (i->name);
1696 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1697 new_devices.push_back (ptr);
1698 } else if (i->available) {
1699 new_devices.push_back (mds);
1702 _midi_devices = new_devices;
1704 if (_midi_devices.empty()) {
1705 midi_devices_button.hide ();
1707 midi_devices_button.show ();
1712 EngineControl::parameter_changed ()
1716 EngineControl::State
1717 EngineControl::get_matching_state (const string& backend)
1719 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1720 if ((*i)->backend == backend) {
1727 EngineControl::State
1728 EngineControl::get_matching_state (
1729 const string& backend,
1730 const string& driver,
1731 const string& device)
1733 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1734 if ((*i)->backend == backend &&
1735 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1743 EngineControl::State
1744 EngineControl::get_matching_state (
1745 const string& backend,
1746 const string& driver,
1747 const string& input_device,
1748 const string& output_device)
1750 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1751 if ((*i)->backend == backend &&
1752 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1760 EngineControl::State
1761 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1763 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1766 if (backend->use_separate_input_and_output_devices ()) {
1767 return get_matching_state (backend_combo.get_active_text(),
1768 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1769 input_device_combo.get_active_text(),
1770 output_device_combo.get_active_text());
1772 return get_matching_state (backend_combo.get_active_text(),
1773 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1774 device_combo.get_active_text());
1778 return get_matching_state (backend_combo.get_active_text(),
1780 device_combo.get_active_text());
1783 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1784 const EngineControl::State& state2)
1786 if (state1->backend == state2->backend &&
1787 state1->driver == state2->driver &&
1788 state1->device == state2->device &&
1789 state1->input_device == state2->input_device &&
1790 state1->output_device == state2->output_device) {
1797 EngineControl::state_sort_cmp (const State &a, const State &b) {
1801 else if (b->active) {
1805 return a->lru < b->lru;
1809 EngineControl::State
1810 EngineControl::save_state ()
1814 if (!_have_control) {
1815 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1817 state->lru = time (NULL) ;
1820 state.reset(new StateStruct);
1821 state->backend = get_backend ();
1823 state.reset(new StateStruct);
1824 store_state (state);
1827 for (StateList::iterator i = states.begin(); i != states.end();) {
1828 if (equivalent_states (*i, state)) {
1829 i = states.erase(i);
1835 states.push_back (state);
1837 states.sort (state_sort_cmp);
1843 EngineControl::store_state (State state)
1845 state->backend = get_backend ();
1846 state->driver = get_driver ();
1847 state->device = get_device_name ();
1848 state->input_device = get_input_device_name ();
1849 state->output_device = get_output_device_name ();
1850 state->sample_rate = get_rate ();
1851 state->buffer_size = get_buffer_size ();
1852 state->n_periods = get_nperiods ();
1853 state->input_latency = get_input_latency ();
1854 state->output_latency = get_output_latency ();
1855 state->input_channels = get_input_channels ();
1856 state->output_channels = get_output_channels ();
1857 state->midi_option = get_midi_option ();
1858 state->midi_devices = _midi_devices;
1859 state->use_buffered_io = get_use_buffered_io ();
1860 state->lru = time (NULL) ;
1864 EngineControl::maybe_display_saved_state ()
1866 if (!_have_control) {
1870 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1873 DEBUG_ECONTROL ("Restoring saved state");
1874 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1876 if (!_desired_sample_rate) {
1877 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1879 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1881 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1882 /* call this explicitly because we're ignoring changes to
1883 the controls at this point.
1885 show_buffer_duration ();
1886 input_latency.set_value (state->input_latency);
1887 output_latency.set_value (state->output_latency);
1889 use_buffered_io_button.set_active (state->use_buffered_io);
1891 if (!state->midi_option.empty()) {
1892 midi_option_combo.set_active_text (state->midi_option);
1893 _midi_devices = state->midi_devices;
1896 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1901 EngineControl::get_state ()
1903 LocaleGuard lg (X_("C"));
1905 XMLNode* root = new XMLNode ("AudioMIDISetup");
1908 if (!states.empty()) {
1909 XMLNode* state_nodes = new XMLNode ("EngineStates");
1911 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1913 XMLNode* node = new XMLNode ("State");
1915 node->add_property ("backend", (*i)->backend);
1916 node->add_property ("driver", (*i)->driver);
1917 node->add_property ("device", (*i)->device);
1918 node->add_property ("input-device", (*i)->input_device);
1919 node->add_property ("output-device", (*i)->output_device);
1920 node->add_property ("sample-rate", (*i)->sample_rate);
1921 node->add_property ("buffer-size", (*i)->buffer_size);
1922 node->add_property ("n-periods", (*i)->n_periods);
1923 node->add_property ("input-latency", (*i)->input_latency);
1924 node->add_property ("output-latency", (*i)->output_latency);
1925 node->add_property ("input-channels", (*i)->input_channels);
1926 node->add_property ("output-channels", (*i)->output_channels);
1927 node->add_property ("active", (*i)->active ? "yes" : "no");
1928 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1929 node->add_property ("midi-option", (*i)->midi_option);
1930 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1932 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1933 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1934 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1935 midi_device_stuff->add_property (X_("name"), (*p)->name);
1936 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1937 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1938 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1939 midi_devices->add_child_nocopy (*midi_device_stuff);
1941 node->add_child_nocopy (*midi_devices);
1943 state_nodes->add_child_nocopy (*node);
1946 root->add_child_nocopy (*state_nodes);
1953 EngineControl::set_default_state ()
1955 vector<string> backend_names;
1956 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1958 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1959 backend_names.push_back ((*b)->name);
1961 backend_combo.set_active_text (backend_names.front());
1963 // We could set default backends per platform etc here
1969 EngineControl::set_state (const XMLNode& root)
1971 XMLNodeList clist, cclist;
1972 XMLNodeConstIterator citer, cciter;
1974 XMLNode* grandchild;
1975 XMLProperty* prop = NULL;
1977 fprintf (stderr, "EngineControl::set_state\n");
1979 if (root.name() != "AudioMIDISetup") {
1983 clist = root.children();
1987 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1991 if (child->name() != "EngineStates") {
1995 cclist = child->children();
1997 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1998 State state (new StateStruct);
2000 grandchild = *cciter;
2002 if (grandchild->name() != "State") {
2006 if ((prop = grandchild->property ("backend")) == 0) {
2009 state->backend = prop->value ();
2011 if ((prop = grandchild->property ("driver")) == 0) {
2014 state->driver = prop->value ();
2016 if ((prop = grandchild->property ("device")) == 0) {
2019 state->device = prop->value ();
2021 if ((prop = grandchild->property ("input-device")) == 0) {
2024 state->input_device = prop->value ();
2026 if ((prop = grandchild->property ("output-device")) == 0) {
2029 state->output_device = prop->value ();
2031 if ((prop = grandchild->property ("sample-rate")) == 0) {
2034 state->sample_rate = atof (prop->value ());
2036 if ((prop = grandchild->property ("buffer-size")) == 0) {
2039 state->buffer_size = atoi (prop->value ());
2041 if ((prop = grandchild->property ("n-periods")) == 0) {
2042 // optional (new value in 4.5)
2043 state->n_periods = 0;
2045 state->n_periods = atoi (prop->value ());
2048 if ((prop = grandchild->property ("input-latency")) == 0) {
2051 state->input_latency = atoi (prop->value ());
2053 if ((prop = grandchild->property ("output-latency")) == 0) {
2056 state->output_latency = atoi (prop->value ());
2058 if ((prop = grandchild->property ("input-channels")) == 0) {
2061 state->input_channels = atoi (prop->value ());
2063 if ((prop = grandchild->property ("output-channels")) == 0) {
2066 state->output_channels = atoi (prop->value ());
2068 if ((prop = grandchild->property ("active")) == 0) {
2071 state->active = string_is_affirmative (prop->value ());
2073 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2076 state->use_buffered_io = string_is_affirmative (prop->value ());
2078 if ((prop = grandchild->property ("midi-option")) == 0) {
2081 state->midi_option = prop->value ();
2083 state->midi_devices.clear();
2085 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2086 const XMLNodeList mnc = midinode->children();
2087 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2088 if ((*n)->property (X_("name")) == 0
2089 || (*n)->property (X_("enabled")) == 0
2090 || (*n)->property (X_("input-latency")) == 0
2091 || (*n)->property (X_("output-latency")) == 0
2096 MidiDeviceSettings ptr (new MidiDeviceSetting(
2097 (*n)->property (X_("name"))->value (),
2098 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2099 atoi ((*n)->property (X_("input-latency"))->value ()),
2100 atoi ((*n)->property (X_("output-latency"))->value ())
2102 state->midi_devices.push_back (ptr);
2106 if ((prop = grandchild->property ("lru"))) {
2107 state->lru = atoi (prop->value ());
2111 /* remove accumulated duplicates (due to bug in ealier version)
2112 * this can be removed again before release
2114 for (StateList::iterator i = states.begin(); i != states.end();) {
2115 if ((*i)->backend == state->backend &&
2116 (*i)->driver == state->driver &&
2117 (*i)->device == state->device) {
2118 i = states.erase(i);
2125 states.push_back (state);
2129 /* now see if there was an active state and switch the setup to it */
2131 // purge states of backend that are not available in this built
2132 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2133 vector<std::string> backend_names;
2135 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2136 backend_names.push_back((*i)->name);
2138 for (StateList::iterator i = states.begin(); i != states.end();) {
2139 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2140 i = states.erase(i);
2146 states.sort (state_sort_cmp);
2148 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2151 return set_current_state (*i);
2158 EngineControl::set_current_state (const State& state)
2160 DEBUG_ECONTROL ("set_current_state");
2162 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2164 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2165 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2166 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2167 // this shouldn't happen as the invalid backend names should have been
2168 // removed from the list of states.
2172 // now reflect the change in the backend in the GUI so backend_changed will
2173 // do the right thing
2174 backend_combo.set_active_text (state->backend);
2176 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2178 // we don't have control don't restore state
2183 if (!state->driver.empty ()) {
2184 if (!backend->requires_driver_selection ()) {
2185 DEBUG_ECONTROL ("Backend should require driver selection");
2186 // A backend has changed from having driver selection to not having
2187 // it or someone has been manually editing a config file and messed
2192 if (backend->set_driver (state->driver) != 0) {
2193 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2194 // Driver names for a backend have changed and the name in the
2195 // config file is now invalid or support for driver is no longer
2196 // included in the backend
2199 // no need to set the driver_combo as backend_changed will use
2200 // backend->driver_name to set the active driver
2203 if (!state->device.empty ()) {
2204 if (backend->set_device_name (state->device) != 0) {
2206 string_compose ("Unable to set device name %1", state->device));
2207 // device is no longer available on the system
2210 // no need to set active device as it will be picked up in
2211 // via backend_changed ()/set_device_popdown_strings
2214 // backend supports separate input/output devices
2215 if (backend->set_input_device_name (state->input_device) != 0) {
2216 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2217 state->input_device));
2218 // input device is no longer available on the system
2222 if (backend->set_output_device_name (state->output_device) != 0) {
2223 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2224 state->input_device));
2225 // output device is no longer available on the system
2228 // no need to set active devices as it will be picked up in via
2229 // backend_changed ()/set_*_device_popdown_strings
2234 // Now restore the state of the rest of the controls
2236 // We don't use a SignalBlocker as set_current_state is currently only
2237 // called from set_state before any signals are connected. If at some point
2238 // a more general named state mechanism is implemented and
2239 // set_current_state is called while signals are connected then a
2240 // SignalBlocker will need to be instantiated before setting these.
2242 device_combo.set_active_text (state->device);
2243 input_device_combo.set_active_text (state->input_device);
2244 output_device_combo.set_active_text (state->output_device);
2245 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2246 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2247 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2248 input_latency.set_value (state->input_latency);
2249 output_latency.set_value (state->output_latency);
2250 midi_option_combo.set_active_text (state->midi_option);
2251 use_buffered_io_button.set_active (state->use_buffered_io);
2256 EngineControl::push_state_to_backend (bool start)
2258 DEBUG_ECONTROL ("push_state_to_backend");
2259 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2260 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2266 /* figure out what is going to change */
2268 bool restart_required = false;
2269 bool was_running = ARDOUR::AudioEngine::instance()->running();
2270 bool change_driver = false;
2271 bool change_device = false;
2272 bool change_rate = false;
2273 bool change_bufsize = false;
2274 bool change_nperiods = false;
2275 bool change_latency = false;
2276 bool change_channels = false;
2277 bool change_midi = false;
2278 bool change_buffered_io = false;
2280 uint32_t ochan = get_output_channels ();
2281 uint32_t ichan = get_input_channels ();
2283 if (_have_control) {
2285 if (started_at_least_once) {
2287 /* we can control the backend */
2289 if (backend->requires_driver_selection()) {
2290 if (get_driver() != backend->driver_name()) {
2291 change_driver = true;
2295 if (backend->use_separate_input_and_output_devices()) {
2296 if (get_input_device_name() != backend->input_device_name()) {
2297 change_device = true;
2299 if (get_output_device_name() != backend->output_device_name()) {
2300 change_device = true;
2303 if (get_device_name() != backend->device_name()) {
2304 change_device = true;
2308 if (queue_device_changed) {
2309 change_device = true;
2312 if (get_rate() != backend->sample_rate()) {
2316 if (get_buffer_size() != backend->buffer_size()) {
2317 change_bufsize = true;
2320 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2321 && get_nperiods() != backend->period_size()) {
2322 change_nperiods = true;
2325 if (get_midi_option() != backend->midi_option()) {
2329 if (backend->can_use_buffered_io()) {
2330 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2331 change_buffered_io = true;
2335 /* zero-requested channels means "all available" */
2338 ichan = backend->input_channels();
2342 ochan = backend->output_channels();
2345 if (ichan != backend->input_channels()) {
2346 change_channels = true;
2349 if (ochan != backend->output_channels()) {
2350 change_channels = true;
2353 if (get_input_latency() != backend->systemic_input_latency() ||
2354 get_output_latency() != backend->systemic_output_latency()) {
2355 change_latency = true;
2358 /* backend never started, so we have to force a group
2361 change_device = true;
2362 if (backend->requires_driver_selection()) {
2363 change_driver = true;
2366 change_bufsize = true;
2367 change_channels = true;
2368 change_latency = 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()) ||
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 ();
2725 EngineControl::update_devices_button_clicked ()
2727 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2733 if (backend->update_devices()) {
2734 device_list_changed ();
2739 EngineControl::use_buffered_io_button_clicked ()
2741 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2747 bool set_buffered_io = !use_buffered_io_button.get_active();
2748 use_buffered_io_button.set_active (set_buffered_io);
2749 backend->set_use_buffered_io (set_buffered_io);
2753 EngineControl::manage_control_app_sensitivity ()
2755 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2761 string appname = backend->control_app_name();
2763 if (appname.empty()) {
2764 control_app_button.set_sensitive (false);
2766 control_app_button.set_sensitive (true);
2771 EngineControl::set_desired_sample_rate (uint32_t sr)
2773 _desired_sample_rate = sr;
2774 if (ARDOUR::AudioEngine::instance ()->running ()
2775 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2782 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2784 if (page_num == 0) {
2785 cancel_button->set_sensitive (true);
2786 _measure_midi.reset();
2787 update_sensitivity ();
2789 cancel_button->set_sensitive (false);
2790 ok_button->set_sensitive (false);
2793 if (page_num == midi_tab) {
2795 refresh_midi_display ();
2798 if (page_num == latency_tab) {
2801 if (ARDOUR::AudioEngine::instance()->running()) {
2806 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2808 /* save any existing latency values */
2810 uint32_t il = (uint32_t) input_latency.get_value ();
2811 uint32_t ol = (uint32_t) input_latency.get_value ();
2813 /* reset to zero so that our new test instance
2814 will be clean of any existing latency measures.
2816 NB. this should really be done by the backend
2817 when stated for latency measurement.
2820 input_latency.set_value (0);
2821 output_latency.set_value (0);
2823 push_state_to_backend (false);
2827 input_latency.set_value (il);
2828 output_latency.set_value (ol);
2831 // This should be done in push_state_to_backend()
2832 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2833 disable_latency_tab ();
2836 enable_latency_tab ();
2840 end_latency_detection ();
2841 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2846 /* latency measurement */
2849 EngineControl::check_audio_latency_measurement ()
2851 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2853 if (mtdm->resolve () < 0) {
2854 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2858 if (mtdm->get_peak () > 0.707f) {
2859 // get_peak() resets the peak-hold in the detector.
2860 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2861 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2865 if (mtdm->err () > 0.3) {
2871 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2873 if (sample_rate == 0) {
2874 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2875 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2879 int frames_total = mtdm->del();
2880 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2882 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2883 _("Detected roundtrip latency: "),
2884 frames_total, frames_total * 1000.0f/sample_rate,
2885 _("Systemic latency: "),
2886 extra, extra * 1000.0f/sample_rate);
2890 if (mtdm->err () > 0.2) {
2892 strcat (buf, _("(signal detection error)"));
2898 strcat (buf, _("(inverted - bad wiring)"));
2902 lm_results.set_markup (string_compose (results_markup, buf));
2905 have_lm_results = true;
2906 end_latency_detection ();
2907 lm_use_button.set_sensitive (true);
2915 EngineControl::check_midi_latency_measurement ()
2917 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2919 if (!mididm->have_signal () || mididm->latency () == 0) {
2920 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2925 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2927 if (sample_rate == 0) {
2928 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2929 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2933 ARDOUR::framecnt_t frames_total = mididm->latency();
2934 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2935 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2936 _("Detected roundtrip latency: "),
2937 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2938 _("Systemic latency: "),
2939 extra, extra * 1000.0f / sample_rate);
2943 if (!mididm->ok ()) {
2945 strcat (buf, _("(averaging)"));
2949 if (mididm->deviation () > 50.0) {
2951 strcat (buf, _("(too large jitter)"));
2953 } else if (mididm->deviation () > 10.0) {
2955 strcat (buf, _("(large jitter)"));
2959 have_lm_results = true;
2960 end_latency_detection ();
2961 lm_use_button.set_sensitive (true);
2962 lm_results.set_markup (string_compose (results_markup, buf));
2964 } else if (mididm->processed () > 400) {
2965 have_lm_results = false;
2966 end_latency_detection ();
2967 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2971 lm_results.set_markup (string_compose (results_markup, buf));
2977 EngineControl::start_latency_detection ()
2979 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2980 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2982 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2983 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2984 if (_measure_midi) {
2985 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2987 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2989 lm_measure_label.set_text (_("Cancel"));
2990 have_lm_results = false;
2991 lm_use_button.set_sensitive (false);
2992 lm_input_channel_combo.set_sensitive (false);
2993 lm_output_channel_combo.set_sensitive (false);
2999 EngineControl::end_latency_detection ()
3001 latency_timeout.disconnect ();
3002 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3003 lm_measure_label.set_text (_("Measure"));
3004 if (!have_lm_results) {
3005 lm_use_button.set_sensitive (false);
3007 lm_input_channel_combo.set_sensitive (true);
3008 lm_output_channel_combo.set_sensitive (true);
3013 EngineControl::latency_button_clicked ()
3016 start_latency_detection ();
3018 end_latency_detection ();
3023 EngineControl::latency_back_button_clicked ()
3025 ARDOUR::AudioEngine::instance()->stop(true);
3026 notebook.set_current_page(0);
3030 EngineControl::use_latency_button_clicked ()
3032 if (_measure_midi) {
3033 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3037 ARDOUR::framecnt_t frames_total = mididm->latency();
3038 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3039 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3040 _measure_midi->input_latency = one_way;
3041 _measure_midi->output_latency = one_way;
3042 notebook.set_current_page (midi_tab);
3044 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3050 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3051 one_way = std::max (0., one_way);
3053 input_latency_adjustment.set_value (one_way);
3054 output_latency_adjustment.set_value (one_way);
3056 /* back to settings page */
3057 notebook.set_current_page (0);
3062 EngineControl::on_delete_event (GdkEventAny* ev)
3064 if (notebook.get_current_page() == 2) {
3065 /* currently on latency tab - be sure to clean up */
3066 end_latency_detection ();
3068 return ArdourDialog::on_delete_event (ev);
3072 EngineControl::engine_running ()
3074 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3077 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3078 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3080 if (backend->can_set_period_size ()) {
3081 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3084 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3085 connect_disconnect_button.show();
3087 started_at_least_once = true;
3088 if (_have_control) {
3089 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3091 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3093 update_sensitivity();
3097 EngineControl::engine_stopped ()
3099 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3102 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3103 connect_disconnect_button.show();
3105 if (_have_control) {
3106 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3108 engine_status.set_markup(X_(""));
3111 update_sensitivity();
3115 EngineControl::device_list_changed ()
3117 if (ignore_device_changes) {
3120 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3122 midi_option_changed();
3126 EngineControl::connect_disconnect_click()
3128 if (ARDOUR::AudioEngine::instance()->running()) {
3136 EngineControl::calibrate_audio_latency ()
3138 _measure_midi.reset ();
3139 have_lm_results = false;
3140 lm_use_button.set_sensitive (false);
3141 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3142 notebook.set_current_page (latency_tab);
3146 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3149 have_lm_results = false;
3150 lm_use_button.set_sensitive (false);
3151 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3152 notebook.set_current_page (latency_tab);
3156 EngineControl::configure_midi_devices ()
3158 notebook.set_current_page (midi_tab);