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);
279 start_stop_button.set_can_default(true);
281 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
282 update_devices_button.set_sensitive (false);
283 update_devices_button.set_name ("generic button");
284 update_devices_button.set_can_focus(true);
286 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
287 use_buffered_io_button.set_sensitive (false);
288 use_buffered_io_button.set_name ("generic button");
289 use_buffered_io_button.set_can_focus(true);
291 /* Pick up any existing audio setup configuration, if appropriate */
293 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
295 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
296 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
297 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
298 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
301 if (!set_state (*audio_setup)) {
302 set_default_state ();
305 set_default_state ();
308 update_sensitivity ();
309 connect_changed_signals ();
311 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
313 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
315 connect_disconnect_button.set_no_show_all();
316 use_buffered_io_button.set_no_show_all();
317 update_devices_button.set_no_show_all();
318 start_stop_button.set_no_show_all();
319 midi_devices_button.set_no_show_all();
323 EngineControl::connect_changed_signals ()
325 backend_combo_connection = backend_combo.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::backend_changed));
327 driver_combo_connection = driver_combo.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::driver_changed));
329 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
331 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
333 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
335 device_combo_connection = device_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::device_changed));
337 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
340 input_device_combo_connection = input_device_combo.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::input_device_changed));
342 output_device_combo_connection = output_device_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::output_device_changed));
345 input_latency_connection = input_latency.signal_changed ().connect (
346 sigc::mem_fun (*this, &EngineControl::parameter_changed));
347 output_latency_connection = output_latency.signal_changed ().connect (
348 sigc::mem_fun (*this, &EngineControl::parameter_changed));
349 input_channels_connection = input_channels.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::parameter_changed));
351 output_channels_connection = output_channels.signal_changed ().connect (
352 sigc::mem_fun (*this, &EngineControl::parameter_changed));
356 EngineControl::block_changed_signals ()
358 if (block_signals++ == 0) {
359 DEBUG_ECONTROL ("Blocking changed signals");
360 backend_combo_connection.block ();
361 driver_combo_connection.block ();
362 sample_rate_combo_connection.block ();
363 buffer_size_combo_connection.block ();
364 nperiods_combo_connection.block ();
365 device_combo_connection.block ();
366 input_device_combo_connection.block ();
367 output_device_combo_connection.block ();
368 midi_option_combo_connection.block ();
369 input_latency_connection.block ();
370 output_latency_connection.block ();
371 input_channels_connection.block ();
372 output_channels_connection.block ();
377 EngineControl::unblock_changed_signals ()
379 if (--block_signals == 0) {
380 DEBUG_ECONTROL ("Unblocking changed signals");
381 backend_combo_connection.unblock ();
382 driver_combo_connection.unblock ();
383 sample_rate_combo_connection.unblock ();
384 buffer_size_combo_connection.unblock ();
385 nperiods_combo_connection.unblock ();
386 device_combo_connection.unblock ();
387 input_device_combo_connection.unblock ();
388 output_device_combo_connection.unblock ();
389 midi_option_combo_connection.unblock ();
390 input_latency_connection.unblock ();
391 output_latency_connection.unblock ();
392 input_channels_connection.unblock ();
393 output_channels_connection.unblock ();
397 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
398 const std::string& reason)
399 : ec (engine_control)
402 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
403 ec.block_changed_signals ();
406 EngineControl::SignalBlocker::~SignalBlocker ()
408 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
409 ec.unblock_changed_signals ();
413 EngineControl::on_show ()
415 ArdourDialog::on_show ();
416 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
417 // re-check _have_control (jackd running) see #6041
421 start_stop_button.grab_focus();
425 EngineControl::try_autostart ()
427 if (!start_stop_button.get_sensitive()) {
430 if (ARDOUR::AudioEngine::instance()->running()) {
433 return start_engine ();
437 EngineControl::start_engine ()
439 if (push_state_to_backend(true) != 0) {
440 MessageDialog msg(*this,
441 ARDOUR::AudioEngine::instance()->get_last_backend_error());
449 EngineControl::stop_engine (bool for_latency)
451 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
452 MessageDialog msg(*this,
453 ARDOUR::AudioEngine::instance()->get_last_backend_error());
461 EngineControl::build_notebook ()
464 AttachOptions xopt = AttachOptions (FILL|EXPAND);
466 /* clear the table */
468 Gtkmm2ext::container_clear (basic_vbox);
469 Gtkmm2ext::container_clear (basic_packer);
471 if (control_app_button.get_parent()) {
472 control_app_button.get_parent()->remove (control_app_button);
475 label = manage (left_aligned_label (_("Audio System:")));
476 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
477 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
479 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
480 engine_status.show();
482 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
483 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
484 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
486 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
487 lm_button_audio.set_name ("generic button");
488 lm_button_audio.set_can_focus(true);
491 build_full_control_notebook ();
493 build_no_control_notebook ();
496 basic_vbox.pack_start (basic_hbox, false, false);
499 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
500 basic_vbox.show_all ();
505 EngineControl::build_full_control_notebook ()
507 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
510 using namespace Notebook_Helpers;
512 vector<string> strings;
513 AttachOptions xopt = AttachOptions (FILL|EXPAND);
514 int row = 1; // row zero == backend combo
516 /* start packing it up */
518 if (backend->requires_driver_selection()) {
519 label = manage (left_aligned_label (_("Driver:")));
520 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
521 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
525 if (backend->use_separate_input_and_output_devices()) {
526 label = manage (left_aligned_label (_("Input Device:")));
527 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
528 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
530 label = manage (left_aligned_label (_("Output Device:")));
531 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
532 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
534 // reset so it isn't used in state comparisons
535 device_combo.set_active_text ("");
537 label = manage (left_aligned_label (_("Device:")));
538 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
539 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
541 // reset these so they don't get used in state comparisons
542 input_device_combo.set_active_text ("");
543 output_device_combo.set_active_text ("");
546 label = manage (left_aligned_label (_("Sample rate:")));
547 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
548 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
552 label = manage (left_aligned_label (_("Buffer size:")));
553 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
554 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
555 buffer_size_duration_label.set_alignment (0.0); /* left-align */
556 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
558 int ctrl_btn_span = 1;
559 if (backend->can_set_period_size ()) {
561 label = manage (left_aligned_label (_("Periods:")));
562 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
563 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
567 /* button spans 2 or 3 rows */
569 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
572 input_channels.set_name ("InputChannels");
573 input_channels.set_flags (Gtk::CAN_FOCUS);
574 input_channels.set_digits (0);
575 input_channels.set_wrap (false);
576 output_channels.set_editable (true);
578 if (!ARDOUR::Profile->get_mixbus()) {
579 label = manage (left_aligned_label (_("Input Channels:")));
580 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
581 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
585 output_channels.set_name ("OutputChannels");
586 output_channels.set_flags (Gtk::CAN_FOCUS);
587 output_channels.set_digits (0);
588 output_channels.set_wrap (false);
589 output_channels.set_editable (true);
591 if (!ARDOUR::Profile->get_mixbus()) {
592 label = manage (left_aligned_label (_("Output Channels:")));
593 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
594 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
598 input_latency.set_name ("InputLatency");
599 input_latency.set_flags (Gtk::CAN_FOCUS);
600 input_latency.set_digits (0);
601 input_latency.set_wrap (false);
602 input_latency.set_editable (true);
604 label = manage (left_aligned_label (_("Hardware input latency:")));
605 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
606 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
607 label = manage (left_aligned_label (_("samples")));
608 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
611 output_latency.set_name ("OutputLatency");
612 output_latency.set_flags (Gtk::CAN_FOCUS);
613 output_latency.set_digits (0);
614 output_latency.set_wrap (false);
615 output_latency.set_editable (true);
617 label = manage (left_aligned_label (_("Hardware output latency:")));
618 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
619 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
620 label = manage (left_aligned_label (_("samples")));
621 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
623 /* button spans 2 rows */
625 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
628 label = manage (left_aligned_label (_("MIDI System:")));
629 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
630 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
631 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
636 EngineControl::build_no_control_notebook ()
638 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
641 using namespace Notebook_Helpers;
643 vector<string> strings;
644 AttachOptions xopt = AttachOptions (FILL|EXPAND);
645 int row = 1; // row zero == backend combo
646 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
648 label = manage (new Label);
649 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
650 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
653 if (backend->can_change_sample_rate_when_running()) {
654 label = manage (left_aligned_label (_("Sample rate:")));
655 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
656 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
660 if (backend->can_change_buffer_size_when_running()) {
661 label = manage (left_aligned_label (_("Buffer size:")));
662 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
663 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
664 buffer_size_duration_label.set_alignment (0.0); /* left-align */
665 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
669 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
673 EngineControl::~EngineControl ()
675 ignore_changes = true;
679 EngineControl::disable_latency_tab ()
681 vector<string> empty;
682 set_popdown_strings (lm_output_channel_combo, empty);
683 set_popdown_strings (lm_input_channel_combo, empty);
684 lm_measure_button.set_sensitive (false);
685 lm_use_button.set_sensitive (false);
689 EngineControl::enable_latency_tab ()
691 vector<string> outputs;
692 vector<string> inputs;
694 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
695 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
696 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
698 if (!ARDOUR::AudioEngine::instance()->running()) {
699 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
700 notebook.set_current_page (0);
704 else if (inputs.empty() || outputs.empty()) {
705 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
706 notebook.set_current_page (0);
711 lm_back_button_signal.disconnect();
713 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
716 lm_back_button_signal = lm_back_button.signal_clicked().connect(
717 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
721 set_popdown_strings (lm_output_channel_combo, outputs);
722 lm_output_channel_combo.set_active_text (outputs.front());
723 lm_output_channel_combo.set_sensitive (true);
725 set_popdown_strings (lm_input_channel_combo, inputs);
726 lm_input_channel_combo.set_active_text (inputs.front());
727 lm_input_channel_combo.set_sensitive (true);
729 lm_measure_button.set_sensitive (true);
733 EngineControl::setup_midi_tab_for_backend ()
735 string backend = backend_combo.get_active_text ();
737 Gtkmm2ext::container_clear (midi_vbox);
739 midi_vbox.set_border_width (12);
740 midi_device_table.set_border_width (12);
742 if (backend == "JACK") {
743 setup_midi_tab_for_jack ();
746 midi_vbox.pack_start (midi_device_table, true, true);
747 midi_vbox.pack_start (midi_back_button, false, false);
748 midi_vbox.show_all ();
752 EngineControl::update_sensitivity ()
754 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
756 start_stop_button.set_sensitive (false);
761 size_t devices_available = 0;
763 if (backend->use_separate_input_and_output_devices ()) {
764 devices_available += get_popdown_string_count (input_device_combo);
765 devices_available += get_popdown_string_count (output_device_combo);
767 devices_available += get_popdown_string_count (device_combo);
770 if (devices_available == 0) {
772 input_latency.set_sensitive (false);
773 output_latency.set_sensitive (false);
774 input_channels.set_sensitive (false);
775 output_channels.set_sensitive (false);
777 input_latency.set_sensitive (true);
778 output_latency.set_sensitive (true);
779 input_channels.set_sensitive (true);
780 output_channels.set_sensitive (true);
783 if (get_popdown_string_count (buffer_size_combo) > 0) {
784 if (!ARDOUR::AudioEngine::instance()->running()) {
785 buffer_size_combo.set_sensitive (valid);
786 } else if (backend->can_change_sample_rate_when_running()) {
787 buffer_size_combo.set_sensitive (valid || !_have_control);
791 * Currently there is no way to manually stop the
792 * engine in order to re-configure it.
793 * This needs to remain sensitive for now.
795 * (it's also handy to implicily
796 * re-start the engine)
798 buffer_size_combo.set_sensitive (true);
800 buffer_size_combo.set_sensitive (false);
804 buffer_size_combo.set_sensitive (false);
808 if (get_popdown_string_count (sample_rate_combo) > 0) {
809 bool allow_to_set_rate = false;
810 if (!ARDOUR::AudioEngine::instance()->running()) {
811 if (!ARDOUR_UI::instance()->session_loaded) {
812 // engine is not running, no session loaded -> anything goes.
813 allow_to_set_rate = true;
814 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
815 // only allow to change if the current setting is not the native session rate.
816 allow_to_set_rate = true;
819 sample_rate_combo.set_sensitive (allow_to_set_rate);
821 sample_rate_combo.set_sensitive (false);
825 if (get_popdown_string_count (nperiods_combo) > 0) {
826 if (!ARDOUR::AudioEngine::instance()->running()) {
827 nperiods_combo.set_sensitive (true);
829 nperiods_combo.set_sensitive (false);
832 nperiods_combo.set_sensitive (false);
836 start_stop_button.set_sensitive(true);
837 start_stop_button.show();
838 if (ARDOUR::AudioEngine::instance()->running()) {
839 start_stop_button.set_text("Stop");
840 update_devices_button.set_sensitive(false);
841 use_buffered_io_button.set_sensitive(false);
843 if (backend->can_request_update_devices()) {
844 update_devices_button.show();
846 update_devices_button.hide();
848 if (backend->can_use_buffered_io()) {
849 use_buffered_io_button.show();
851 use_buffered_io_button.hide();
853 start_stop_button.set_text("Start");
854 update_devices_button.set_sensitive(true);
855 use_buffered_io_button.set_sensitive(true);
858 update_devices_button.set_sensitive(false);
859 update_devices_button.hide();
860 use_buffered_io_button.set_sensitive(false);
861 use_buffered_io_button.hide();
862 start_stop_button.set_sensitive(false);
863 start_stop_button.hide();
866 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
867 input_device_combo.set_sensitive (false);
868 output_device_combo.set_sensitive (false);
869 device_combo.set_sensitive (false);
870 driver_combo.set_sensitive (false);
872 input_device_combo.set_sensitive (true);
873 output_device_combo.set_sensitive (true);
874 device_combo.set_sensitive (true);
875 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
876 driver_combo.set_sensitive (true);
878 driver_combo.set_sensitive (false);
884 EngineControl::setup_midi_tab_for_jack ()
889 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
891 device->input_latency = a->get_value();
893 device->output_latency = a->get_value();
898 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
899 b->set_active (!b->get_active());
900 device->enabled = b->get_active();
901 refresh_midi_display(device->name);
905 EngineControl::refresh_midi_display (std::string focus)
907 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
911 AttachOptions xopt = AttachOptions (FILL|EXPAND);
914 Gtkmm2ext::container_clear (midi_device_table);
916 midi_device_table.set_spacings (6);
918 l = manage (new Label);
919 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
920 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
921 l->set_alignment (0.5, 0.5);
925 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
926 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
927 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
928 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
930 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
931 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
932 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
933 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
936 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
941 bool enabled = (*p)->enabled;
943 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
944 m->set_name ("midi device");
945 m->set_can_focus (Gtk::CAN_FOCUS);
946 m->add_events (Gdk::BUTTON_RELEASE_MASK);
947 m->set_active (enabled);
948 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
949 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
950 if ((*p)->name == focus) {
954 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
955 s = manage (new Gtk::SpinButton (*a));
956 a->set_value ((*p)->input_latency);
957 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
958 s->set_sensitive (_can_set_midi_latencies && enabled);
959 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
961 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
962 s = manage (new Gtk::SpinButton (*a));
963 a->set_value ((*p)->output_latency);
964 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
965 s->set_sensitive (_can_set_midi_latencies && enabled);
966 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
968 b = manage (new Button (_("Calibrate")));
969 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
970 b->set_sensitive (_can_set_midi_latencies && enabled);
971 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
978 EngineControl::backend_changed ()
980 SignalBlocker blocker (*this, "backend_changed");
981 string backend_name = backend_combo.get_active_text();
982 boost::shared_ptr<ARDOUR::AudioBackend> backend;
984 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
985 /* eh? setting the backend failed... how ? */
986 /* A: stale config contains a backend that does not exist in current build */
990 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
992 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
995 setup_midi_tab_for_backend ();
996 _midi_devices.clear();
998 if (backend->requires_driver_selection()) {
999 if (set_driver_popdown_strings ()) {
1003 /* this will change the device text which will cause a call to
1004 * device changed which will set up parameters
1009 update_midi_options ();
1011 connect_disconnect_button.hide();
1013 midi_option_changed();
1015 started_at_least_once = false;
1017 /* changing the backend implies stopping the engine
1018 * ARDOUR::AudioEngine() may or may not emit this signal
1019 * depending on previous engine state
1021 engine_stopped (); // set "active/inactive"
1023 if (!_have_control) {
1024 // set settings from backend that we do have control over
1025 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1028 if (_have_control && !ignore_changes) {
1029 // set driver & devices
1030 State state = get_matching_state (backend_combo.get_active_text());
1032 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1033 set_current_state (state);
1037 if (!ignore_changes) {
1038 maybe_display_saved_state ();
1043 EngineControl::update_midi_options ()
1045 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1046 vector<string> midi_options = backend->enumerate_midi_options();
1048 if (midi_options.size() == 1) {
1049 /* only contains the "none" option */
1050 midi_option_combo.set_sensitive (false);
1052 if (_have_control) {
1053 set_popdown_strings (midi_option_combo, midi_options);
1054 midi_option_combo.set_active_text (midi_options.front());
1055 midi_option_combo.set_sensitive (true);
1057 midi_option_combo.set_sensitive (false);
1063 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1065 if (ARDOUR::Profile->get_mixbus()) {
1069 uint32_t cnt = (uint32_t) sb->get_value();
1071 sb->set_text (_("all available channels"));
1074 snprintf (buf, sizeof (buf), "%d", cnt);
1080 // @return true if there are drivers available
1082 EngineControl::set_driver_popdown_strings ()
1084 DEBUG_ECONTROL ("set_driver_popdown_strings");
1085 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1086 vector<string> drivers = backend->enumerate_drivers();
1088 if (drivers.empty ()) {
1089 // This is an error...?
1093 string current_driver = backend->driver_name ();
1095 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1097 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1100 current_driver = drivers.front ();
1103 set_popdown_strings (driver_combo, drivers);
1105 string_compose ("driver_combo.set_active_text: %1", current_driver));
1106 driver_combo.set_active_text (current_driver);
1111 EngineControl::get_default_device(const string& current_device_name,
1112 const vector<string>& available_devices)
1114 // If the current device is available, use it as default
1115 if (std::find (available_devices.begin (),
1116 available_devices.end (),
1117 current_device_name) != available_devices.end ()) {
1119 return current_device_name;
1122 using namespace ARDOUR;
1124 string default_device_name =
1125 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1127 vector<string>::const_iterator i;
1129 // If there is a "Default" device available, use it
1130 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1131 if (*i == default_device_name) {
1136 string none_device_name =
1137 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1139 // Use the first device that isn't "None"
1140 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1141 if (*i != none_device_name) {
1146 // Use "None" if there are no other available
1147 return available_devices.front();
1150 // @return true if there are devices available
1152 EngineControl::set_device_popdown_strings ()
1154 DEBUG_ECONTROL ("set_device_popdown_strings");
1155 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1156 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1158 /* NOTE: Ardour currently does not display the "available" field of the
1161 * Doing so would require a different GUI widget than the combo
1162 * box/popdown that we currently use, since it has no way to list
1163 * items that are not selectable. Something more like a popup menu,
1164 * which could have unselectable items, would be appropriate.
1167 vector<string> available_devices;
1169 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1170 available_devices.push_back (i->name);
1173 if (available_devices.empty ()) {
1177 set_popdown_strings (device_combo, available_devices);
1179 std::string default_device =
1180 get_default_device(backend->device_name(), available_devices);
1183 string_compose ("set device_combo active text: %1", default_device));
1185 device_combo.set_active_text(default_device);
1189 // @return true if there are input devices available
1191 EngineControl::set_input_device_popdown_strings ()
1193 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1194 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1195 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1197 vector<string> available_devices;
1199 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1200 available_devices.push_back (i->name);
1203 if (available_devices.empty()) {
1207 set_popdown_strings (input_device_combo, available_devices);
1209 std::string default_device =
1210 get_default_device(backend->input_device_name(), available_devices);
1213 string_compose ("set input_device_combo active text: %1", default_device));
1214 input_device_combo.set_active_text(default_device);
1218 // @return true if there are output devices available
1220 EngineControl::set_output_device_popdown_strings ()
1222 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1223 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1224 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1226 vector<string> available_devices;
1228 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1229 available_devices.push_back (i->name);
1232 if (available_devices.empty()) {
1236 set_popdown_strings (output_device_combo, available_devices);
1238 std::string default_device =
1239 get_default_device(backend->output_device_name(), available_devices);
1242 string_compose ("set output_device_combo active text: %1", default_device));
1243 output_device_combo.set_active_text(default_device);
1248 EngineControl::list_devices ()
1250 DEBUG_ECONTROL ("list_devices");
1251 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1254 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1256 bool devices_available = false;
1258 if (backend->use_separate_input_and_output_devices ()) {
1259 bool input_devices_available = set_input_device_popdown_strings ();
1260 bool output_devices_available = set_output_device_popdown_strings ();
1261 devices_available = input_devices_available || output_devices_available;
1263 devices_available = set_device_popdown_strings ();
1266 if (devices_available) {
1269 device_combo.clear();
1270 input_device_combo.clear();
1271 output_device_combo.clear();
1273 update_sensitivity ();
1277 EngineControl::driver_changed ()
1279 SignalBlocker blocker (*this, "driver_changed");
1280 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1283 backend->set_driver (driver_combo.get_active_text());
1286 // TODO load LRU device(s) for backend + driver combo
1288 if (!ignore_changes) {
1289 maybe_display_saved_state ();
1294 EngineControl::get_sample_rates_for_all_devices ()
1296 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1297 ARDOUR::AudioEngine::instance ()->current_backend ();
1298 vector<float> all_rates;
1300 if (backend->use_separate_input_and_output_devices ()) {
1301 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1303 all_rates = backend->available_sample_rates (get_device_name ());
1309 EngineControl::get_default_sample_rates ()
1311 vector<float> rates;
1312 rates.push_back (8000.0f);
1313 rates.push_back (16000.0f);
1314 rates.push_back (32000.0f);
1315 rates.push_back (44100.0f);
1316 rates.push_back (48000.0f);
1317 rates.push_back (88200.0f);
1318 rates.push_back (96000.0f);
1319 rates.push_back (192000.0f);
1320 rates.push_back (384000.0f);
1325 EngineControl::set_samplerate_popdown_strings ()
1327 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1328 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1333 if (_have_control) {
1334 sr = get_sample_rates_for_all_devices ();
1336 sr = get_default_sample_rates ();
1339 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1340 s.push_back (rate_as_string (*x));
1341 if (*x == _desired_sample_rate) {
1346 set_popdown_strings (sample_rate_combo, s);
1349 if (ARDOUR::AudioEngine::instance()->running()) {
1350 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1352 else if (desired.empty ()) {
1353 float new_active_sr = backend->default_sample_rate ();
1355 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1356 new_active_sr = sr.front ();
1359 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1361 sample_rate_combo.set_active_text (desired);
1365 update_sensitivity ();
1369 EngineControl::get_buffer_sizes_for_all_devices ()
1371 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1372 ARDOUR::AudioEngine::instance ()->current_backend ();
1373 vector<uint32_t> all_sizes;
1375 if (backend->use_separate_input_and_output_devices ()) {
1376 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1378 all_sizes = backend->available_buffer_sizes (get_device_name ());
1384 EngineControl::get_default_buffer_sizes ()
1386 vector<uint32_t> sizes;
1387 sizes.push_back (8);
1388 sizes.push_back (16);
1389 sizes.push_back (32);
1390 sizes.push_back (64);
1391 sizes.push_back (128);
1392 sizes.push_back (256);
1393 sizes.push_back (512);
1394 sizes.push_back (1024);
1395 sizes.push_back (2048);
1396 sizes.push_back (4096);
1397 sizes.push_back (8192);
1402 EngineControl::set_buffersize_popdown_strings ()
1404 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1405 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1406 vector<uint32_t> bs;
1409 if (_have_control) {
1410 bs = get_buffer_sizes_for_all_devices ();
1411 } else if (backend->can_change_buffer_size_when_running()) {
1412 bs = get_default_buffer_sizes ();
1415 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1416 s.push_back (bufsize_as_string (*x));
1419 uint32_t previous_size = 0;
1420 if (!buffer_size_combo.get_active_text().empty()) {
1421 previous_size = get_buffer_size ();
1424 set_popdown_strings (buffer_size_combo, s);
1428 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1429 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1432 buffer_size_combo.set_active_text(s.front());
1434 uint32_t period = backend->buffer_size();
1435 if (0 == period && backend->use_separate_input_and_output_devices()) {
1436 period = backend->default_buffer_size(get_input_device_name());
1438 if (0 == period && backend->use_separate_input_and_output_devices()) {
1439 period = backend->default_buffer_size(get_output_device_name());
1441 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1442 period = backend->default_buffer_size(get_device_name());
1445 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1447 show_buffer_duration ();
1449 update_sensitivity ();
1453 EngineControl::set_nperiods_popdown_strings ()
1455 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1456 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1457 vector<uint32_t> np;
1460 if (backend->can_set_period_size()) {
1461 np = backend->available_period_sizes (get_driver());
1464 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1465 s.push_back (nperiods_as_string (*x));
1468 set_popdown_strings (nperiods_combo, s);
1471 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1474 update_sensitivity ();
1478 EngineControl::device_changed ()
1480 SignalBlocker blocker (*this, "device_changed");
1481 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1484 string device_name_in;
1485 string device_name_out; // only used if backend support separate I/O devices
1487 if (backend->use_separate_input_and_output_devices()) {
1488 device_name_in = get_input_device_name ();
1489 device_name_out = get_output_device_name ();
1491 device_name_in = get_device_name ();
1494 /* we set the backend-device to query various device related intormation.
1495 * This has the side effect that backend->device_name() will match
1496 * the device_name and 'change_device' will never be true.
1497 * so work around this by setting...
1499 if (backend->use_separate_input_and_output_devices()) {
1500 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1501 queue_device_changed = true;
1504 if (device_name_in != backend->device_name()) {
1505 queue_device_changed = true;
1509 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1510 if (backend->use_separate_input_and_output_devices()) {
1511 backend->set_input_device_name (device_name_in);
1512 backend->set_output_device_name (device_name_out);
1514 backend->set_device_name(device_name_in);
1518 /* don't allow programmatic change to combos to cause a
1519 recursive call to this method.
1521 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1523 set_samplerate_popdown_strings ();
1524 set_buffersize_popdown_strings ();
1525 set_nperiods_popdown_strings ();
1527 /* TODO set min + max channel counts here */
1529 manage_control_app_sensitivity ();
1532 /* pick up any saved state for this device */
1534 if (!ignore_changes) {
1535 maybe_display_saved_state ();
1540 EngineControl::input_device_changed ()
1542 DEBUG_ECONTROL ("input_device_changed");
1544 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1545 if (backend && backend->match_input_output_devices_or_none ()) {
1546 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1548 if (get_output_device_name () != dev_none
1549 && get_input_device_name () != dev_none
1550 && get_input_device_name () != get_output_device_name ()) {
1551 block_changed_signals ();
1552 if (contains_value (output_device_combo, get_input_device_name ())) {
1553 output_device_combo.set_active_text (get_input_device_name ());
1555 assert (contains_value (output_device_combo, dev_none));
1556 output_device_combo.set_active_text (dev_none);
1558 unblock_changed_signals ();
1565 EngineControl::output_device_changed ()
1567 DEBUG_ECONTROL ("output_device_changed");
1568 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1569 if (backend && backend->match_input_output_devices_or_none ()) {
1570 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1572 if (get_input_device_name () != dev_none
1573 && get_input_device_name () != dev_none
1574 && get_input_device_name () != get_output_device_name ()) {
1575 block_changed_signals ();
1576 if (contains_value (input_device_combo, get_output_device_name ())) {
1577 input_device_combo.set_active_text (get_output_device_name ());
1579 assert (contains_value (input_device_combo, dev_none));
1580 input_device_combo.set_active_text (dev_none);
1582 unblock_changed_signals ();
1589 EngineControl::bufsize_as_string (uint32_t sz)
1591 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1595 EngineControl::nperiods_as_string (uint32_t np)
1598 snprintf (buf, sizeof (buf), "%u", np);
1604 EngineControl::sample_rate_changed ()
1606 DEBUG_ECONTROL ("sample_rate_changed");
1607 /* reset the strings for buffer size to show the correct msec value
1608 (reflecting the new sample rate).
1611 show_buffer_duration ();
1616 EngineControl::buffer_size_changed ()
1618 DEBUG_ECONTROL ("buffer_size_changed");
1619 show_buffer_duration ();
1623 EngineControl::nperiods_changed ()
1625 DEBUG_ECONTROL ("nperiods_changed");
1626 show_buffer_duration ();
1630 EngineControl::show_buffer_duration ()
1632 DEBUG_ECONTROL ("show_buffer_duration");
1633 /* buffer sizes - convert from just samples to samples + msecs for
1634 * the displayed string
1637 string bs_text = buffer_size_combo.get_active_text ();
1638 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1639 uint32_t rate = get_rate();
1641 /* Except for ALSA and Dummy backends, we don't know the number of periods
1642 * per cycle and settings.
1644 * jack1 vs jack2 have different default latencies since jack2 start
1645 * in async-mode unless --sync is given which adds an extra cycle
1646 * of latency. The value is not known if jackd is started externally..
1648 * So just display the period size, that's also what
1649 * ARDOUR_UI::update_sample_rate() does for the status bar.
1650 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1651 * but still, that's the buffer period, not [round-trip] latency)
1654 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1655 buffer_size_duration_label.set_text (buf);
1659 EngineControl::midi_option_changed ()
1661 DEBUG_ECONTROL ("midi_option_changed");
1662 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1665 backend->set_midi_option (get_midi_option());
1667 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1669 //_midi_devices.clear(); // TODO merge with state-saved settings..
1670 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1671 std::vector<MidiDeviceSettings> new_devices;
1673 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1674 MidiDeviceSettings mds = find_midi_device (i->name);
1675 if (i->available && !mds) {
1676 uint32_t input_latency = 0;
1677 uint32_t output_latency = 0;
1678 if (_can_set_midi_latencies) {
1679 input_latency = backend->systemic_midi_input_latency (i->name);
1680 output_latency = backend->systemic_midi_output_latency (i->name);
1682 bool enabled = backend->midi_device_enabled (i->name);
1683 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1684 new_devices.push_back (ptr);
1685 } else if (i->available) {
1686 new_devices.push_back (mds);
1689 _midi_devices = new_devices;
1691 if (_midi_devices.empty()) {
1692 midi_devices_button.hide ();
1694 midi_devices_button.show ();
1699 EngineControl::parameter_changed ()
1703 EngineControl::State
1704 EngineControl::get_matching_state (const string& backend)
1706 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1707 if ((*i)->backend == backend) {
1714 EngineControl::State
1715 EngineControl::get_matching_state (
1716 const string& backend,
1717 const string& driver,
1718 const string& device)
1720 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1721 if ((*i)->backend == backend &&
1722 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1730 EngineControl::State
1731 EngineControl::get_matching_state (
1732 const string& backend,
1733 const string& driver,
1734 const string& input_device,
1735 const string& output_device)
1737 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1738 if ((*i)->backend == backend &&
1739 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1747 EngineControl::State
1748 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1750 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1753 if (backend->use_separate_input_and_output_devices ()) {
1754 return get_matching_state (backend_combo.get_active_text(),
1755 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1756 input_device_combo.get_active_text(),
1757 output_device_combo.get_active_text());
1759 return get_matching_state (backend_combo.get_active_text(),
1760 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1761 device_combo.get_active_text());
1765 return get_matching_state (backend_combo.get_active_text(),
1767 device_combo.get_active_text());
1770 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1771 const EngineControl::State& state2)
1773 if (state1->backend == state2->backend &&
1774 state1->driver == state2->driver &&
1775 state1->device == state2->device &&
1776 state1->input_device == state2->input_device &&
1777 state1->output_device == state2->output_device) {
1784 EngineControl::state_sort_cmp (const State &a, const State &b) {
1788 else if (b->active) {
1792 return a->lru < b->lru;
1796 EngineControl::State
1797 EngineControl::save_state ()
1801 if (!_have_control) {
1802 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1804 state->lru = time (NULL) ;
1807 state.reset(new StateStruct);
1808 state->backend = get_backend ();
1810 state.reset(new StateStruct);
1811 store_state (state);
1814 for (StateList::iterator i = states.begin(); i != states.end();) {
1815 if (equivalent_states (*i, state)) {
1816 i = states.erase(i);
1822 states.push_back (state);
1824 states.sort (state_sort_cmp);
1830 EngineControl::store_state (State state)
1832 state->backend = get_backend ();
1833 state->driver = get_driver ();
1834 state->device = get_device_name ();
1835 state->input_device = get_input_device_name ();
1836 state->output_device = get_output_device_name ();
1837 state->sample_rate = get_rate ();
1838 state->buffer_size = get_buffer_size ();
1839 state->n_periods = get_nperiods ();
1840 state->input_latency = get_input_latency ();
1841 state->output_latency = get_output_latency ();
1842 state->input_channels = get_input_channels ();
1843 state->output_channels = get_output_channels ();
1844 state->midi_option = get_midi_option ();
1845 state->midi_devices = _midi_devices;
1846 state->use_buffered_io = get_use_buffered_io ();
1847 state->lru = time (NULL) ;
1851 EngineControl::maybe_display_saved_state ()
1853 if (!_have_control) {
1857 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1860 DEBUG_ECONTROL ("Restoring saved state");
1861 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1863 if (!_desired_sample_rate) {
1864 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1866 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1868 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1869 /* call this explicitly because we're ignoring changes to
1870 the controls at this point.
1872 show_buffer_duration ();
1873 input_latency.set_value (state->input_latency);
1874 output_latency.set_value (state->output_latency);
1876 use_buffered_io_button.set_active (state->use_buffered_io);
1878 if (!state->midi_option.empty()) {
1879 midi_option_combo.set_active_text (state->midi_option);
1880 _midi_devices = state->midi_devices;
1883 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1888 EngineControl::get_state ()
1892 XMLNode* root = new XMLNode ("AudioMIDISetup");
1895 if (!states.empty()) {
1896 XMLNode* state_nodes = new XMLNode ("EngineStates");
1898 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1900 XMLNode* node = new XMLNode ("State");
1902 node->add_property ("backend", (*i)->backend);
1903 node->add_property ("driver", (*i)->driver);
1904 node->add_property ("device", (*i)->device);
1905 node->add_property ("input-device", (*i)->input_device);
1906 node->add_property ("output-device", (*i)->output_device);
1907 node->add_property ("sample-rate", (*i)->sample_rate);
1908 node->add_property ("buffer-size", (*i)->buffer_size);
1909 node->add_property ("n-periods", (*i)->n_periods);
1910 node->add_property ("input-latency", (*i)->input_latency);
1911 node->add_property ("output-latency", (*i)->output_latency);
1912 node->add_property ("input-channels", (*i)->input_channels);
1913 node->add_property ("output-channels", (*i)->output_channels);
1914 node->add_property ("active", (*i)->active ? "yes" : "no");
1915 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1916 node->add_property ("midi-option", (*i)->midi_option);
1917 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1919 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1920 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1921 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1922 midi_device_stuff->add_property (X_("name"), (*p)->name);
1923 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1924 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1925 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1926 midi_devices->add_child_nocopy (*midi_device_stuff);
1928 node->add_child_nocopy (*midi_devices);
1930 state_nodes->add_child_nocopy (*node);
1933 root->add_child_nocopy (*state_nodes);
1940 EngineControl::set_default_state ()
1942 vector<string> backend_names;
1943 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1945 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1946 backend_names.push_back ((*b)->name);
1948 backend_combo.set_active_text (backend_names.front());
1950 // We could set default backends per platform etc here
1956 EngineControl::set_state (const XMLNode& root)
1958 XMLNodeList clist, cclist;
1959 XMLNodeConstIterator citer, cciter;
1960 XMLNode const * child;
1961 XMLNode const * grandchild;
1962 XMLProperty const * prop = NULL;
1964 if (root.name() != "AudioMIDISetup") {
1968 clist = root.children();
1972 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1976 if (child->name() != "EngineStates") {
1980 cclist = child->children();
1982 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1983 State state (new StateStruct);
1985 grandchild = *cciter;
1987 if (grandchild->name() != "State") {
1991 if ((prop = grandchild->property ("backend")) == 0) {
1994 state->backend = prop->value ();
1996 if ((prop = grandchild->property ("driver")) == 0) {
1999 state->driver = prop->value ();
2001 if ((prop = grandchild->property ("device")) == 0) {
2004 state->device = prop->value ();
2006 if ((prop = grandchild->property ("input-device")) == 0) {
2009 state->input_device = prop->value ();
2011 if ((prop = grandchild->property ("output-device")) == 0) {
2014 state->output_device = prop->value ();
2016 if ((prop = grandchild->property ("sample-rate")) == 0) {
2019 state->sample_rate = atof (prop->value ());
2021 if ((prop = grandchild->property ("buffer-size")) == 0) {
2024 state->buffer_size = atoi (prop->value ());
2026 if ((prop = grandchild->property ("n-periods")) == 0) {
2027 // optional (new value in 4.5)
2028 state->n_periods = 0;
2030 state->n_periods = atoi (prop->value ());
2033 if ((prop = grandchild->property ("input-latency")) == 0) {
2036 state->input_latency = atoi (prop->value ());
2038 if ((prop = grandchild->property ("output-latency")) == 0) {
2041 state->output_latency = atoi (prop->value ());
2043 if ((prop = grandchild->property ("input-channels")) == 0) {
2046 state->input_channels = atoi (prop->value ());
2048 if ((prop = grandchild->property ("output-channels")) == 0) {
2051 state->output_channels = atoi (prop->value ());
2053 if ((prop = grandchild->property ("active")) == 0) {
2056 state->active = string_is_affirmative (prop->value ());
2058 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2061 state->use_buffered_io = string_is_affirmative (prop->value ());
2063 if ((prop = grandchild->property ("midi-option")) == 0) {
2066 state->midi_option = prop->value ();
2068 state->midi_devices.clear();
2070 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2071 const XMLNodeList mnc = midinode->children();
2072 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2073 if ((*n)->property (X_("name")) == 0
2074 || (*n)->property (X_("enabled")) == 0
2075 || (*n)->property (X_("input-latency")) == 0
2076 || (*n)->property (X_("output-latency")) == 0
2081 MidiDeviceSettings ptr (new MidiDeviceSetting(
2082 (*n)->property (X_("name"))->value (),
2083 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2084 atoi ((*n)->property (X_("input-latency"))->value ()),
2085 atoi ((*n)->property (X_("output-latency"))->value ())
2087 state->midi_devices.push_back (ptr);
2091 if ((prop = grandchild->property ("lru"))) {
2092 state->lru = atoi (prop->value ());
2096 /* remove accumulated duplicates (due to bug in ealier version)
2097 * this can be removed again before release
2099 for (StateList::iterator i = states.begin(); i != states.end();) {
2100 if ((*i)->backend == state->backend &&
2101 (*i)->driver == state->driver &&
2102 (*i)->device == state->device) {
2103 i = states.erase(i);
2110 states.push_back (state);
2114 /* now see if there was an active state and switch the setup to it */
2116 // purge states of backend that are not available in this built
2117 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2118 vector<std::string> backend_names;
2120 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2121 backend_names.push_back((*i)->name);
2123 for (StateList::iterator i = states.begin(); i != states.end();) {
2124 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2125 i = states.erase(i);
2131 states.sort (state_sort_cmp);
2133 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2136 return set_current_state (*i);
2143 EngineControl::set_current_state (const State& state)
2145 DEBUG_ECONTROL ("set_current_state");
2147 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2149 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2150 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2151 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2152 // this shouldn't happen as the invalid backend names should have been
2153 // removed from the list of states.
2157 // now reflect the change in the backend in the GUI so backend_changed will
2158 // do the right thing
2159 backend_combo.set_active_text (state->backend);
2161 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2163 // we don't have control don't restore state
2168 if (!state->driver.empty ()) {
2169 if (!backend->requires_driver_selection ()) {
2170 DEBUG_ECONTROL ("Backend should require driver selection");
2171 // A backend has changed from having driver selection to not having
2172 // it or someone has been manually editing a config file and messed
2177 if (backend->set_driver (state->driver) != 0) {
2178 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2179 // Driver names for a backend have changed and the name in the
2180 // config file is now invalid or support for driver is no longer
2181 // included in the backend
2184 // no need to set the driver_combo as backend_changed will use
2185 // backend->driver_name to set the active driver
2188 if (!state->device.empty ()) {
2189 if (backend->set_device_name (state->device) != 0) {
2191 string_compose ("Unable to set device name %1", state->device));
2192 // device is no longer available on the system
2195 // no need to set active device as it will be picked up in
2196 // via backend_changed ()/set_device_popdown_strings
2199 // backend supports separate input/output devices
2200 if (backend->set_input_device_name (state->input_device) != 0) {
2201 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2202 state->input_device));
2203 // input device is no longer available on the system
2207 if (backend->set_output_device_name (state->output_device) != 0) {
2208 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2209 state->input_device));
2210 // output device is no longer available on the system
2213 // no need to set active devices as it will be picked up in via
2214 // backend_changed ()/set_*_device_popdown_strings
2219 // Now restore the state of the rest of the controls
2221 // We don't use a SignalBlocker as set_current_state is currently only
2222 // called from set_state before any signals are connected. If at some point
2223 // a more general named state mechanism is implemented and
2224 // set_current_state is called while signals are connected then a
2225 // SignalBlocker will need to be instantiated before setting these.
2227 device_combo.set_active_text (state->device);
2228 input_device_combo.set_active_text (state->input_device);
2229 output_device_combo.set_active_text (state->output_device);
2230 if (!_desired_sample_rate) {
2231 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2233 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2234 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2235 input_latency.set_value (state->input_latency);
2236 output_latency.set_value (state->output_latency);
2237 midi_option_combo.set_active_text (state->midi_option);
2238 use_buffered_io_button.set_active (state->use_buffered_io);
2243 EngineControl::push_state_to_backend (bool start)
2245 DEBUG_ECONTROL ("push_state_to_backend");
2246 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2247 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2253 /* figure out what is going to change */
2255 bool restart_required = false;
2256 bool was_running = ARDOUR::AudioEngine::instance()->running();
2257 bool change_driver = false;
2258 bool change_device = false;
2259 bool change_rate = false;
2260 bool change_bufsize = false;
2261 bool change_nperiods = false;
2262 bool change_latency = false;
2263 bool change_channels = false;
2264 bool change_midi = false;
2265 bool change_buffered_io = false;
2267 uint32_t ochan = get_output_channels ();
2268 uint32_t ichan = get_input_channels ();
2270 if (_have_control) {
2272 if (started_at_least_once) {
2274 /* we can control the backend */
2276 if (backend->requires_driver_selection()) {
2277 if (get_driver() != backend->driver_name()) {
2278 change_driver = true;
2282 if (backend->use_separate_input_and_output_devices()) {
2283 if (get_input_device_name() != backend->input_device_name()) {
2284 change_device = true;
2286 if (get_output_device_name() != backend->output_device_name()) {
2287 change_device = true;
2290 if (get_device_name() != backend->device_name()) {
2291 change_device = true;
2295 if (queue_device_changed) {
2296 change_device = true;
2299 if (get_rate() != backend->sample_rate()) {
2303 if (get_buffer_size() != backend->buffer_size()) {
2304 change_bufsize = true;
2307 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2308 && get_nperiods() != backend->period_size()) {
2309 change_nperiods = true;
2312 if (get_midi_option() != backend->midi_option()) {
2316 if (backend->can_use_buffered_io()) {
2317 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2318 change_buffered_io = true;
2322 /* zero-requested channels means "all available" */
2325 ichan = backend->input_channels();
2329 ochan = backend->output_channels();
2332 if (ichan != backend->input_channels()) {
2333 change_channels = true;
2336 if (ochan != backend->output_channels()) {
2337 change_channels = true;
2340 if (get_input_latency() != backend->systemic_input_latency() ||
2341 get_output_latency() != backend->systemic_output_latency()) {
2342 change_latency = true;
2345 /* backend never started, so we have to force a group
2348 change_device = true;
2349 if (backend->requires_driver_selection()) {
2350 change_driver = true;
2353 change_bufsize = true;
2354 change_channels = true;
2355 change_latency = true;
2357 change_buffered_io = backend->can_use_buffered_io();
2358 change_channels = true;
2359 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2364 /* we have no control over the backend, meaning that we can
2365 * only possibly change sample rate and buffer size.
2369 if (get_rate() != backend->sample_rate()) {
2370 change_bufsize = true;
2373 if (get_buffer_size() != backend->buffer_size()) {
2374 change_bufsize = true;
2378 queue_device_changed = false;
2380 if (!_have_control) {
2382 /* We do not have control over the backend, so the best we can
2383 * do is try to change the sample rate and/or bufsize and get
2387 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2391 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2396 backend->set_sample_rate (get_rate());
2399 if (change_bufsize) {
2400 backend->set_buffer_size (get_buffer_size());
2404 if (ARDOUR::AudioEngine::instance()->start ()) {
2405 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2415 /* determine if we need to stop the backend before changing parameters */
2417 if (change_driver || change_device || change_channels || change_nperiods ||
2418 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2419 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2420 change_midi || change_buffered_io ||
2421 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2422 restart_required = true;
2424 restart_required = false;
2429 if (restart_required) {
2430 if (ARDOUR::AudioEngine::instance()->stop()) {
2436 if (change_driver && backend->set_driver (get_driver())) {
2437 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2440 if (backend->use_separate_input_and_output_devices()) {
2441 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2442 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2445 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2446 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2450 if (change_device && backend->set_device_name (get_device_name())) {
2451 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2455 if (change_rate && backend->set_sample_rate (get_rate())) {
2456 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2459 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2460 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2463 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2464 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2468 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2469 if (backend->set_input_channels (get_input_channels())) {
2470 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2473 if (backend->set_output_channels (get_output_channels())) {
2474 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2478 if (change_latency) {
2479 if (backend->set_systemic_input_latency (get_input_latency())) {
2480 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2483 if (backend->set_systemic_output_latency (get_output_latency())) {
2484 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2490 backend->set_midi_option (get_midi_option());
2493 if (change_buffered_io) {
2494 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2498 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2499 if (_measure_midi) {
2500 if (*p == _measure_midi) {
2501 backend->set_midi_device_enabled ((*p)->name, true);
2503 backend->set_midi_device_enabled ((*p)->name, false);
2505 if (backend->can_change_systemic_latency_when_running ()) {
2506 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2507 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2511 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2512 if (backend->can_set_systemic_midi_latencies()) {
2513 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2514 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2519 if (start || (was_running && restart_required)) {
2520 if (ARDOUR::AudioEngine::instance()->start()) {
2531 EngineControl::post_push ()
2533 /* get a pointer to the current state object, creating one if
2537 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2540 state = save_state ();
2546 states.sort (state_sort_cmp);
2550 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2551 (*i)->active = false;
2554 /* mark this one active (to be used next time the dialog is
2558 state->active = true;
2560 if (_have_control) { // XXX
2561 manage_control_app_sensitivity ();
2564 /* schedule a redisplay of MIDI ports */
2565 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2570 EngineControl::get_rate () const
2572 float r = atof (sample_rate_combo.get_active_text ());
2573 /* the string may have been translated with an abbreviation for
2574 * thousands, so use a crude heuristic to fix this.
2584 EngineControl::get_buffer_size () const
2586 string txt = buffer_size_combo.get_active_text ();
2589 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2590 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2591 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2599 EngineControl::get_nperiods () const
2601 string txt = nperiods_combo.get_active_text ();
2602 return atoi (txt.c_str());
2606 EngineControl::get_midi_option () const
2608 return midi_option_combo.get_active_text();
2612 EngineControl::get_use_buffered_io () const
2614 return use_buffered_io_button.get_active();
2618 EngineControl::get_input_channels() const
2620 if (ARDOUR::Profile->get_mixbus()) {
2621 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2622 if (!backend) return 0;
2623 return backend->input_channels();
2625 return (uint32_t) input_channels_adjustment.get_value();
2629 EngineControl::get_output_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) output_channels_adjustment.get_value();
2640 EngineControl::get_input_latency() const
2642 return (uint32_t) input_latency_adjustment.get_value();
2646 EngineControl::get_output_latency() const
2648 return (uint32_t) output_latency_adjustment.get_value();
2652 EngineControl::get_backend () const
2654 return backend_combo.get_active_text ();
2658 EngineControl::get_driver () const
2660 if (driver_combo.get_parent()) {
2661 return driver_combo.get_active_text ();
2668 EngineControl::get_device_name () const
2670 return device_combo.get_active_text ();
2674 EngineControl::get_input_device_name () const
2676 return input_device_combo.get_active_text ();
2680 EngineControl::get_output_device_name () const
2682 return output_device_combo.get_active_text ();
2686 EngineControl::control_app_button_clicked ()
2688 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2694 backend->launch_control_app ();
2698 EngineControl::start_stop_button_clicked ()
2700 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2706 if (ARDOUR::AudioEngine::instance()->running()) {
2707 ARDOUR::AudioEngine::instance()->stop ();
2709 if (!ARDOUR_UI::instance()->session_loaded) {
2713 if (!ARDOUR_UI::instance()->session_loaded) {
2714 ArdourDialog::on_response (RESPONSE_OK);
2720 EngineControl::update_devices_button_clicked ()
2722 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2728 if (backend->update_devices()) {
2729 device_list_changed ();
2734 EngineControl::use_buffered_io_button_clicked ()
2736 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2742 bool set_buffered_io = !use_buffered_io_button.get_active();
2743 use_buffered_io_button.set_active (set_buffered_io);
2744 backend->set_use_buffered_io (set_buffered_io);
2748 EngineControl::manage_control_app_sensitivity ()
2750 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2756 string appname = backend->control_app_name();
2758 if (appname.empty()) {
2759 control_app_button.set_sensitive (false);
2761 control_app_button.set_sensitive (true);
2766 EngineControl::set_desired_sample_rate (uint32_t sr)
2768 _desired_sample_rate = sr;
2769 if (ARDOUR::AudioEngine::instance ()->running ()
2770 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2777 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2779 if (page_num == 0) {
2780 _measure_midi.reset();
2781 update_sensitivity ();
2784 if (page_num == midi_tab) {
2786 refresh_midi_display ();
2789 if (page_num == latency_tab) {
2792 if (ARDOUR::AudioEngine::instance()->running()) {
2797 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2799 /* save any existing latency values */
2801 uint32_t il = (uint32_t) input_latency.get_value ();
2802 uint32_t ol = (uint32_t) input_latency.get_value ();
2804 /* reset to zero so that our new test instance
2805 will be clean of any existing latency measures.
2807 NB. this should really be done by the backend
2808 when stated for latency measurement.
2811 input_latency.set_value (0);
2812 output_latency.set_value (0);
2814 push_state_to_backend (false);
2818 input_latency.set_value (il);
2819 output_latency.set_value (ol);
2822 // This should be done in push_state_to_backend()
2823 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2824 disable_latency_tab ();
2827 enable_latency_tab ();
2831 end_latency_detection ();
2832 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2837 /* latency measurement */
2840 EngineControl::check_audio_latency_measurement ()
2842 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2844 if (mtdm->resolve () < 0) {
2845 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2849 if (mtdm->get_peak () > 0.707f) {
2850 // get_peak() resets the peak-hold in the detector.
2851 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2852 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2856 if (mtdm->err () > 0.3) {
2862 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2864 if (sample_rate == 0) {
2865 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2866 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2870 int frames_total = mtdm->del();
2871 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2873 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2874 _("Detected roundtrip latency: "),
2875 frames_total, frames_total * 1000.0f/sample_rate,
2876 _("Systemic latency: "),
2877 extra, extra * 1000.0f/sample_rate);
2881 if (mtdm->err () > 0.2) {
2883 strcat (buf, _("(signal detection error)"));
2889 strcat (buf, _("(inverted - bad wiring)"));
2893 lm_results.set_markup (string_compose (results_markup, buf));
2896 have_lm_results = true;
2897 end_latency_detection ();
2898 lm_use_button.set_sensitive (true);
2906 EngineControl::check_midi_latency_measurement ()
2908 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2910 if (!mididm->have_signal () || mididm->latency () == 0) {
2911 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2916 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2918 if (sample_rate == 0) {
2919 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2920 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2924 ARDOUR::framecnt_t frames_total = mididm->latency();
2925 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2926 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2927 _("Detected roundtrip latency: "),
2928 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2929 _("Systemic latency: "),
2930 extra, extra * 1000.0f / sample_rate);
2934 if (!mididm->ok ()) {
2936 strcat (buf, _("(averaging)"));
2940 if (mididm->deviation () > 50.0) {
2942 strcat (buf, _("(too large jitter)"));
2944 } else if (mididm->deviation () > 10.0) {
2946 strcat (buf, _("(large jitter)"));
2950 have_lm_results = true;
2951 end_latency_detection ();
2952 lm_use_button.set_sensitive (true);
2953 lm_results.set_markup (string_compose (results_markup, buf));
2955 } else if (mididm->processed () > 400) {
2956 have_lm_results = false;
2957 end_latency_detection ();
2958 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2962 lm_results.set_markup (string_compose (results_markup, buf));
2968 EngineControl::start_latency_detection ()
2970 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2971 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2973 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2974 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2975 if (_measure_midi) {
2976 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2978 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2980 lm_measure_label.set_text (_("Cancel"));
2981 have_lm_results = false;
2982 lm_use_button.set_sensitive (false);
2983 lm_input_channel_combo.set_sensitive (false);
2984 lm_output_channel_combo.set_sensitive (false);
2990 EngineControl::end_latency_detection ()
2992 latency_timeout.disconnect ();
2993 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2994 lm_measure_label.set_text (_("Measure"));
2995 if (!have_lm_results) {
2996 lm_use_button.set_sensitive (false);
2998 lm_input_channel_combo.set_sensitive (true);
2999 lm_output_channel_combo.set_sensitive (true);
3004 EngineControl::latency_button_clicked ()
3007 start_latency_detection ();
3009 end_latency_detection ();
3014 EngineControl::latency_back_button_clicked ()
3016 ARDOUR::AudioEngine::instance()->stop(true);
3017 notebook.set_current_page(0);
3021 EngineControl::use_latency_button_clicked ()
3023 if (_measure_midi) {
3024 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3028 ARDOUR::framecnt_t frames_total = mididm->latency();
3029 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3030 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3031 _measure_midi->input_latency = one_way;
3032 _measure_midi->output_latency = one_way;
3033 notebook.set_current_page (midi_tab);
3035 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3041 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3042 one_way = std::max (0., one_way);
3044 input_latency_adjustment.set_value (one_way);
3045 output_latency_adjustment.set_value (one_way);
3047 /* back to settings page */
3048 notebook.set_current_page (0);
3053 EngineControl::on_delete_event (GdkEventAny* ev)
3055 if (notebook.get_current_page() == 2) {
3056 /* currently on latency tab - be sure to clean up */
3057 end_latency_detection ();
3059 return ArdourDialog::on_delete_event (ev);
3063 EngineControl::engine_running ()
3065 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3068 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3069 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3071 if (backend->can_set_period_size ()) {
3072 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3075 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3076 connect_disconnect_button.show();
3078 started_at_least_once = true;
3079 if (_have_control) {
3080 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3082 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3084 update_sensitivity();
3088 EngineControl::engine_stopped ()
3090 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3093 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3094 connect_disconnect_button.show();
3096 if (_have_control) {
3097 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3099 engine_status.set_markup(X_(""));
3102 update_sensitivity();
3106 EngineControl::device_list_changed ()
3108 if (ignore_device_changes) {
3111 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3113 midi_option_changed();
3117 EngineControl::connect_disconnect_click()
3119 if (ARDOUR::AudioEngine::instance()->running()) {
3122 if (!ARDOUR_UI::instance()->session_loaded) {
3126 if (!ARDOUR_UI::instance()->session_loaded) {
3127 ArdourDialog::on_response (RESPONSE_OK);
3133 EngineControl::calibrate_audio_latency ()
3135 _measure_midi.reset ();
3136 have_lm_results = false;
3137 lm_use_button.set_sensitive (false);
3138 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3139 notebook.set_current_page (latency_tab);
3143 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3146 have_lm_results = false;
3147 lm_use_button.set_sensitive (false);
3148 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3149 notebook.set_current_page (latency_tab);
3153 EngineControl::configure_midi_devices ()
3155 notebook.set_current_page (midi_tab);