2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
55 #include "ui_config.h"
61 using namespace Gtkmm2ext;
64 using namespace ARDOUR_UI_UTILS;
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
73 EngineControl::EngineControl ()
74 : ArdourDialog (_("Audio/MIDI Setup"))
77 , input_latency_adjustment (0, 0, 99999, 1)
78 , input_latency (input_latency_adjustment)
79 , output_latency_adjustment (0, 0, 99999, 1)
80 , output_latency (output_latency_adjustment)
81 , input_channels_adjustment (0, 0, 256, 1)
82 , input_channels (input_channels_adjustment)
83 , output_channels_adjustment (0, 0, 256, 1)
84 , output_channels (output_channels_adjustment)
85 , ports_adjustment (128, 8, 1024, 1, 16)
86 , ports_spinner (ports_adjustment)
87 , control_app_button (_("Device Control Panel"))
88 , midi_devices_button (_("Midi Device Setup"))
89 , start_stop_button (_("Stop"))
90 , update_devices_button (_("Refresh Devices"))
91 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
92 , lm_measure_label (_("Measure"))
93 , lm_use_button (_("Use results"))
94 , lm_back_button (_("Back to settings ... (ignore results)"))
95 , lm_button_audio (_("Calibrate Audio"))
97 , have_lm_results (false)
99 , midi_back_button (_("Back to settings"))
101 , ignore_device_changes (0)
102 , _desired_sample_rate (0)
103 , started_at_least_once (false)
104 , queue_device_changed (false)
105 , _have_control (true)
108 using namespace Notebook_Helpers;
109 vector<string> backend_names;
111 AttachOptions xopt = AttachOptions (FILL|EXPAND);
114 set_name (X_("AudioMIDISetup"));
116 if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
117 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
119 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
122 /* the backend combo is the one thing that is ALWAYS visible */
124 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
126 if (backends.empty()) {
127 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));
129 throw failed_constructor ();
132 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
133 backend_names.push_back ((*b)->name);
136 set_popdown_strings (backend_combo, backend_names);
138 /* setup basic packing characteristics for the table used on the main
139 * tab of the notebook
142 basic_packer.set_spacings (6);
143 basic_packer.set_border_width (12);
144 basic_packer.set_homogeneous (false);
148 basic_hbox.pack_start (basic_packer, false, false);
150 /* latency measurement tab */
152 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
155 lm_table.set_row_spacings (12);
156 lm_table.set_col_spacings (6);
157 lm_table.set_homogeneous (false);
159 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
162 lm_preamble.set_width_chars (60);
163 lm_preamble.set_line_wrap (true);
164 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
166 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
169 Gtk::Label* preamble;
170 preamble = manage (new Label);
171 preamble->set_width_chars (60);
172 preamble->set_line_wrap (true);
173 preamble->set_markup (_("Select two channels below and connect them using a cable."));
175 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
178 label = manage (new Label (_("Output channel")));
179 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
181 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
182 misc_align->add (lm_output_channel_combo);
183 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
186 label = manage (new Label (_("Input channel")));
187 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
189 misc_align = manage (new Alignment (0.0, 0.5));
190 misc_align->add (lm_input_channel_combo);
191 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
194 lm_measure_label.set_padding (10, 10);
195 lm_measure_button.add (lm_measure_label);
196 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
197 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
198 lm_back_button_signal = lm_back_button.signal_clicked().connect(
199 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
201 lm_use_button.set_sensitive (false);
203 /* Increase the default spacing around the labels of these three
209 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
210 l->set_padding (10, 10);
213 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
214 l->set_padding (10, 10);
217 preamble = manage (new Label);
218 preamble->set_width_chars (60);
219 preamble->set_line_wrap (true);
220 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
221 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 preamble = manage (new Label);
225 preamble->set_width_chars (60);
226 preamble->set_line_wrap (true);
227 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
228 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 ++row; // skip a row in the table
231 ++row; // skip a row in the table
233 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 ++row; // skip a row in the table
236 ++row; // skip a row in the table
238 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
239 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
240 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
242 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
244 lm_vbox.set_border_width (12);
245 lm_vbox.pack_start (lm_table, false, false);
247 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
251 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
252 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
253 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
254 notebook.set_border_width (12);
256 notebook.set_show_tabs (false);
257 notebook.show_all ();
259 notebook.set_name ("SettingsNotebook");
261 /* packup the notebook */
263 get_vbox()->set_border_width (12);
264 get_vbox()->pack_start (notebook);
266 /* need a special function to print "all available channels" when the
267 * channel counts hit zero.
270 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
271 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
273 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
274 midi_devices_button.set_name ("generic button");
275 midi_devices_button.set_can_focus(true);
277 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
278 control_app_button.set_name ("generic button");
279 control_app_button.set_can_focus(true);
280 manage_control_app_sensitivity ();
282 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
283 start_stop_button.set_sensitive (false);
284 start_stop_button.set_name ("generic button");
285 start_stop_button.set_can_focus(true);
286 start_stop_button.set_can_default(true);
288 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
289 update_devices_button.set_sensitive (false);
290 update_devices_button.set_name ("generic button");
291 update_devices_button.set_can_focus(true);
293 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
294 use_buffered_io_button.set_sensitive (false);
295 use_buffered_io_button.set_name ("generic button");
296 use_buffered_io_button.set_can_focus(true);
298 /* Pick up any existing audio setup configuration, if appropriate */
300 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
302 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
303 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
304 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
305 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
308 if (!set_state (*audio_setup)) {
309 set_default_state ();
312 set_default_state ();
315 update_sensitivity ();
316 connect_changed_signals ();
318 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
320 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
322 connect_disconnect_button.set_no_show_all();
323 use_buffered_io_button.set_no_show_all();
324 update_devices_button.set_no_show_all();
325 start_stop_button.set_no_show_all();
326 midi_devices_button.set_no_show_all();
330 EngineControl::connect_changed_signals ()
332 backend_combo_connection = backend_combo.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::backend_changed));
334 driver_combo_connection = driver_combo.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::driver_changed));
336 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
338 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
340 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
342 device_combo_connection = device_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::device_changed));
344 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
347 input_device_combo_connection = input_device_combo.signal_changed ().connect (
348 sigc::mem_fun (*this, &EngineControl::input_device_changed));
349 output_device_combo_connection = output_device_combo.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::output_device_changed));
352 input_latency_connection = input_latency.signal_changed ().connect (
353 sigc::mem_fun (*this, &EngineControl::parameter_changed));
354 output_latency_connection = output_latency.signal_changed ().connect (
355 sigc::mem_fun (*this, &EngineControl::parameter_changed));
356 input_channels_connection = input_channels.signal_changed ().connect (
357 sigc::mem_fun (*this, &EngineControl::parameter_changed));
358 output_channels_connection = output_channels.signal_changed ().connect (
359 sigc::mem_fun (*this, &EngineControl::parameter_changed));
363 EngineControl::block_changed_signals ()
365 if (block_signals++ == 0) {
366 DEBUG_ECONTROL ("Blocking changed signals");
367 backend_combo_connection.block ();
368 driver_combo_connection.block ();
369 sample_rate_combo_connection.block ();
370 buffer_size_combo_connection.block ();
371 nperiods_combo_connection.block ();
372 device_combo_connection.block ();
373 input_device_combo_connection.block ();
374 output_device_combo_connection.block ();
375 midi_option_combo_connection.block ();
376 input_latency_connection.block ();
377 output_latency_connection.block ();
378 input_channels_connection.block ();
379 output_channels_connection.block ();
384 EngineControl::unblock_changed_signals ()
386 if (--block_signals == 0) {
387 DEBUG_ECONTROL ("Unblocking changed signals");
388 backend_combo_connection.unblock ();
389 driver_combo_connection.unblock ();
390 sample_rate_combo_connection.unblock ();
391 buffer_size_combo_connection.unblock ();
392 nperiods_combo_connection.unblock ();
393 device_combo_connection.unblock ();
394 input_device_combo_connection.unblock ();
395 output_device_combo_connection.unblock ();
396 midi_option_combo_connection.unblock ();
397 input_latency_connection.unblock ();
398 output_latency_connection.unblock ();
399 input_channels_connection.unblock ();
400 output_channels_connection.unblock ();
404 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
405 const std::string& reason)
406 : ec (engine_control)
409 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
410 ec.block_changed_signals ();
413 EngineControl::SignalBlocker::~SignalBlocker ()
415 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
416 ec.unblock_changed_signals ();
420 EngineControl::on_show ()
422 ArdourDialog::on_show ();
423 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
424 // re-check _have_control (jackd running) see #6041
428 start_stop_button.grab_focus();
432 EngineControl::try_autostart ()
434 if (!start_stop_button.get_sensitive()) {
437 if (ARDOUR::AudioEngine::instance()->running()) {
440 return start_engine ();
444 EngineControl::start_engine ()
446 if (push_state_to_backend(true) != 0) {
447 MessageDialog msg(*this,
448 ARDOUR::AudioEngine::instance()->get_last_backend_error());
456 EngineControl::stop_engine (bool for_latency)
458 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
459 MessageDialog msg(*this,
460 ARDOUR::AudioEngine::instance()->get_last_backend_error());
468 EngineControl::build_notebook ()
471 AttachOptions xopt = AttachOptions (FILL|EXPAND);
473 /* clear the table */
475 Gtkmm2ext::container_clear (basic_vbox);
476 Gtkmm2ext::container_clear (basic_packer);
478 if (control_app_button.get_parent()) {
479 control_app_button.get_parent()->remove (control_app_button);
482 label = manage (left_aligned_label (_("Audio System:")));
483 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
484 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
486 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
487 engine_status.show();
489 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
490 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
491 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
493 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
494 lm_button_audio.set_name ("generic button");
495 lm_button_audio.set_can_focus(true);
498 build_full_control_notebook ();
500 build_no_control_notebook ();
503 basic_vbox.pack_start (basic_hbox, false, false);
506 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
507 basic_vbox.show_all ();
512 EngineControl::build_full_control_notebook ()
514 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
517 using namespace Notebook_Helpers;
519 vector<string> strings;
520 AttachOptions xopt = AttachOptions (FILL|EXPAND);
521 int row = 1; // row zero == backend combo
523 /* start packing it up */
525 if (backend->requires_driver_selection()) {
526 label = manage (left_aligned_label (_("Driver:")));
527 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
528 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
532 if (backend->use_separate_input_and_output_devices()) {
533 label = manage (left_aligned_label (_("Input Device:")));
534 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
535 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
537 label = manage (left_aligned_label (_("Output Device:")));
538 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
539 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
541 // reset so it isn't used in state comparisons
542 device_combo.set_active_text ("");
544 label = manage (left_aligned_label (_("Device:")));
545 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
546 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
548 // reset these so they don't get used in state comparisons
549 input_device_combo.set_active_text ("");
550 output_device_combo.set_active_text ("");
553 label = manage (left_aligned_label (_("Sample rate:")));
554 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
555 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
559 label = manage (left_aligned_label (_("Buffer size:")));
560 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
561 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
562 buffer_size_duration_label.set_alignment (0.0); /* left-align */
563 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
565 int ctrl_btn_span = 1;
566 if (backend->can_set_period_size ()) {
568 label = manage (left_aligned_label (_("Periods:")));
569 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
570 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 /* button spans 2 or 3 rows */
576 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
579 input_channels.set_name ("InputChannels");
580 input_channels.set_flags (Gtk::CAN_FOCUS);
581 input_channels.set_digits (0);
582 input_channels.set_wrap (false);
583 output_channels.set_editable (true);
585 if (!ARDOUR::Profile->get_mixbus()) {
586 label = manage (left_aligned_label (_("Input Channels:")));
587 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
588 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
592 output_channels.set_name ("OutputChannels");
593 output_channels.set_flags (Gtk::CAN_FOCUS);
594 output_channels.set_digits (0);
595 output_channels.set_wrap (false);
596 output_channels.set_editable (true);
598 if (!ARDOUR::Profile->get_mixbus()) {
599 label = manage (left_aligned_label (_("Output Channels:")));
600 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
601 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
605 input_latency.set_name ("InputLatency");
606 input_latency.set_flags (Gtk::CAN_FOCUS);
607 input_latency.set_digits (0);
608 input_latency.set_wrap (false);
609 input_latency.set_editable (true);
611 label = manage (left_aligned_label (_("Hardware input latency:")));
612 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
613 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
614 label = manage (left_aligned_label (_("samples")));
615 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
618 output_latency.set_name ("OutputLatency");
619 output_latency.set_flags (Gtk::CAN_FOCUS);
620 output_latency.set_digits (0);
621 output_latency.set_wrap (false);
622 output_latency.set_editable (true);
624 label = manage (left_aligned_label (_("Hardware output latency:")));
625 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
626 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
627 label = manage (left_aligned_label (_("samples")));
628 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
630 /* button spans 2 rows */
632 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
635 label = manage (left_aligned_label (_("MIDI System:")));
636 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
637 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
638 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
643 EngineControl::build_no_control_notebook ()
645 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
648 using namespace Notebook_Helpers;
650 vector<string> strings;
651 AttachOptions xopt = AttachOptions (FILL|EXPAND);
652 int row = 1; // row zero == backend combo
653 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
655 label = manage (new Label);
656 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
657 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
660 if (backend->can_change_sample_rate_when_running()) {
661 label = manage (left_aligned_label (_("Sample rate:")));
662 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
663 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
667 if (backend->can_change_buffer_size_when_running()) {
668 label = manage (left_aligned_label (_("Buffer size:")));
669 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
670 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
671 buffer_size_duration_label.set_alignment (0.0); /* left-align */
672 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
676 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
680 EngineControl::~EngineControl ()
682 ignore_changes = true;
686 EngineControl::disable_latency_tab ()
688 vector<string> empty;
689 set_popdown_strings (lm_output_channel_combo, empty);
690 set_popdown_strings (lm_input_channel_combo, empty);
691 lm_measure_button.set_sensitive (false);
692 lm_use_button.set_sensitive (false);
696 EngineControl::enable_latency_tab ()
698 vector<string> outputs;
699 vector<string> inputs;
701 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
702 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
703 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
705 if (!ARDOUR::AudioEngine::instance()->running()) {
706 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
707 notebook.set_current_page (0);
711 else if (inputs.empty() || outputs.empty()) {
712 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
713 notebook.set_current_page (0);
718 lm_back_button_signal.disconnect();
720 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
723 lm_back_button_signal = lm_back_button.signal_clicked().connect(
724 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
728 set_popdown_strings (lm_output_channel_combo, outputs);
729 lm_output_channel_combo.set_active_text (outputs.front());
730 lm_output_channel_combo.set_sensitive (true);
732 set_popdown_strings (lm_input_channel_combo, inputs);
733 lm_input_channel_combo.set_active_text (inputs.front());
734 lm_input_channel_combo.set_sensitive (true);
736 lm_measure_button.set_sensitive (true);
740 EngineControl::setup_midi_tab_for_backend ()
742 string backend = backend_combo.get_active_text ();
744 Gtkmm2ext::container_clear (midi_vbox);
746 midi_vbox.set_border_width (12);
747 midi_device_table.set_border_width (12);
749 if (backend == "JACK") {
750 setup_midi_tab_for_jack ();
753 midi_vbox.pack_start (midi_device_table, true, true);
754 midi_vbox.pack_start (midi_back_button, false, false);
755 midi_vbox.show_all ();
759 EngineControl::update_sensitivity ()
761 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
763 start_stop_button.set_sensitive (false);
768 size_t devices_available = 0;
770 if (backend->use_separate_input_and_output_devices ()) {
771 devices_available += get_popdown_string_count (input_device_combo);
772 devices_available += get_popdown_string_count (output_device_combo);
774 devices_available += get_popdown_string_count (device_combo);
777 if (devices_available == 0) {
779 input_latency.set_sensitive (false);
780 output_latency.set_sensitive (false);
781 input_channels.set_sensitive (false);
782 output_channels.set_sensitive (false);
784 input_latency.set_sensitive (true);
785 output_latency.set_sensitive (true);
786 input_channels.set_sensitive (true);
787 output_channels.set_sensitive (true);
790 if (get_popdown_string_count (buffer_size_combo) > 0) {
791 if (!ARDOUR::AudioEngine::instance()->running()) {
792 buffer_size_combo.set_sensitive (valid);
793 } else if (backend->can_change_sample_rate_when_running()) {
794 buffer_size_combo.set_sensitive (valid || !_have_control);
798 * Currently there is no way to manually stop the
799 * engine in order to re-configure it.
800 * This needs to remain sensitive for now.
802 * (it's also handy to implicily
803 * re-start the engine)
805 buffer_size_combo.set_sensitive (true);
807 buffer_size_combo.set_sensitive (false);
811 buffer_size_combo.set_sensitive (false);
815 if (get_popdown_string_count (sample_rate_combo) > 0) {
816 bool allow_to_set_rate = false;
817 if (!ARDOUR::AudioEngine::instance()->running()) {
818 if (!ARDOUR_UI::instance()->session_loaded) {
819 // engine is not running, no session loaded -> anything goes.
820 allow_to_set_rate = true;
821 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
822 // only allow to change if the current setting is not the native session rate.
823 allow_to_set_rate = true;
826 sample_rate_combo.set_sensitive (allow_to_set_rate);
828 sample_rate_combo.set_sensitive (false);
832 if (get_popdown_string_count (nperiods_combo) > 0) {
833 if (!ARDOUR::AudioEngine::instance()->running()) {
834 nperiods_combo.set_sensitive (true);
836 nperiods_combo.set_sensitive (false);
839 nperiods_combo.set_sensitive (false);
843 start_stop_button.set_sensitive(true);
844 start_stop_button.show();
845 if (ARDOUR::AudioEngine::instance()->running()) {
846 start_stop_button.set_text("Stop");
847 update_devices_button.set_sensitive(false);
848 use_buffered_io_button.set_sensitive(false);
850 if (backend->can_request_update_devices()) {
851 update_devices_button.show();
853 update_devices_button.hide();
855 if (backend->can_use_buffered_io()) {
856 use_buffered_io_button.show();
858 use_buffered_io_button.hide();
860 start_stop_button.set_text("Start");
861 update_devices_button.set_sensitive(true);
862 use_buffered_io_button.set_sensitive(true);
865 update_devices_button.set_sensitive(false);
866 update_devices_button.hide();
867 use_buffered_io_button.set_sensitive(false);
868 use_buffered_io_button.hide();
869 start_stop_button.set_sensitive(false);
870 start_stop_button.hide();
873 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
874 input_device_combo.set_sensitive (false);
875 output_device_combo.set_sensitive (false);
876 device_combo.set_sensitive (false);
877 driver_combo.set_sensitive (false);
879 input_device_combo.set_sensitive (true);
880 output_device_combo.set_sensitive (true);
881 device_combo.set_sensitive (true);
882 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
883 driver_combo.set_sensitive (true);
885 driver_combo.set_sensitive (false);
891 EngineControl::setup_midi_tab_for_jack ()
896 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
898 device->input_latency = a->get_value();
900 device->output_latency = a->get_value();
905 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
906 b->set_active (!b->get_active());
907 device->enabled = b->get_active();
908 refresh_midi_display(device->name);
912 EngineControl::refresh_midi_display (std::string focus)
914 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
918 AttachOptions xopt = AttachOptions (FILL|EXPAND);
921 Gtkmm2ext::container_clear (midi_device_table);
923 midi_device_table.set_spacings (6);
925 l = manage (new Label);
926 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
927 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
928 l->set_alignment (0.5, 0.5);
932 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
933 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
934 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
935 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
937 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
938 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
939 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
940 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
943 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
948 bool enabled = (*p)->enabled;
950 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
951 m->set_name ("midi device");
952 m->set_can_focus (Gtk::CAN_FOCUS);
953 m->add_events (Gdk::BUTTON_RELEASE_MASK);
954 m->set_active (enabled);
955 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
956 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
957 if ((*p)->name == focus) {
961 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
962 s = manage (new Gtk::SpinButton (*a));
963 a->set_value ((*p)->input_latency);
964 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
965 s->set_sensitive (_can_set_midi_latencies && enabled);
966 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
968 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
969 s = manage (new Gtk::SpinButton (*a));
970 a->set_value ((*p)->output_latency);
971 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
972 s->set_sensitive (_can_set_midi_latencies && enabled);
973 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
975 b = manage (new Button (_("Calibrate")));
976 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
977 b->set_sensitive (_can_set_midi_latencies && enabled);
978 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
985 EngineControl::backend_changed ()
987 SignalBlocker blocker (*this, "backend_changed");
988 string backend_name = backend_combo.get_active_text();
989 boost::shared_ptr<ARDOUR::AudioBackend> backend;
991 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
992 /* eh? setting the backend failed... how ? */
993 /* A: stale config contains a backend that does not exist in current build */
997 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
999 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1002 setup_midi_tab_for_backend ();
1003 _midi_devices.clear();
1005 if (backend->requires_driver_selection()) {
1006 if (set_driver_popdown_strings ()) {
1010 /* this will change the device text which will cause a call to
1011 * device changed which will set up parameters
1016 update_midi_options ();
1018 connect_disconnect_button.hide();
1020 midi_option_changed();
1022 started_at_least_once = false;
1024 /* changing the backend implies stopping the engine
1025 * ARDOUR::AudioEngine() may or may not emit this signal
1026 * depending on previous engine state
1028 engine_stopped (); // set "active/inactive"
1030 if (!_have_control) {
1031 // set settings from backend that we do have control over
1032 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1035 if (_have_control && !ignore_changes) {
1036 // set driver & devices
1037 State state = get_matching_state (backend_combo.get_active_text());
1039 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1040 set_current_state (state);
1044 if (!ignore_changes) {
1045 maybe_display_saved_state ();
1050 EngineControl::update_midi_options ()
1052 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1053 vector<string> midi_options = backend->enumerate_midi_options();
1055 if (midi_options.size() == 1) {
1056 /* only contains the "none" option */
1057 midi_option_combo.set_sensitive (false);
1059 if (_have_control) {
1060 set_popdown_strings (midi_option_combo, midi_options);
1061 midi_option_combo.set_active_text (midi_options.front());
1062 midi_option_combo.set_sensitive (true);
1064 midi_option_combo.set_sensitive (false);
1070 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1072 if (ARDOUR::Profile->get_mixbus()) {
1076 uint32_t cnt = (uint32_t) sb->get_value();
1078 sb->set_text (_("all available channels"));
1081 snprintf (buf, sizeof (buf), "%d", cnt);
1087 // @return true if there are drivers available
1089 EngineControl::set_driver_popdown_strings ()
1091 DEBUG_ECONTROL ("set_driver_popdown_strings");
1092 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1093 vector<string> drivers = backend->enumerate_drivers();
1095 if (drivers.empty ()) {
1096 // This is an error...?
1100 string current_driver = backend->driver_name ();
1102 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1104 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1107 current_driver = drivers.front ();
1110 set_popdown_strings (driver_combo, drivers);
1112 string_compose ("driver_combo.set_active_text: %1", current_driver));
1113 driver_combo.set_active_text (current_driver);
1118 EngineControl::get_default_device(const string& current_device_name,
1119 const vector<string>& available_devices)
1121 // If the current device is available, use it as default
1122 if (std::find (available_devices.begin (),
1123 available_devices.end (),
1124 current_device_name) != available_devices.end ()) {
1126 return current_device_name;
1129 using namespace ARDOUR;
1131 string default_device_name =
1132 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1134 vector<string>::const_iterator i;
1136 // If there is a "Default" device available, use it
1137 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1138 if (*i == default_device_name) {
1143 string none_device_name =
1144 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1146 // Use the first device that isn't "None"
1147 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1148 if (*i != none_device_name) {
1153 // Use "None" if there are no other available
1154 return available_devices.front();
1157 // @return true if there are devices available
1159 EngineControl::set_device_popdown_strings ()
1161 DEBUG_ECONTROL ("set_device_popdown_strings");
1162 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1163 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1165 /* NOTE: Ardour currently does not display the "available" field of the
1168 * Doing so would require a different GUI widget than the combo
1169 * box/popdown that we currently use, since it has no way to list
1170 * items that are not selectable. Something more like a popup menu,
1171 * which could have unselectable items, would be appropriate.
1174 vector<string> available_devices;
1176 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1177 available_devices.push_back (i->name);
1180 if (available_devices.empty ()) {
1184 set_popdown_strings (device_combo, available_devices);
1186 std::string default_device =
1187 get_default_device(backend->device_name(), available_devices);
1190 string_compose ("set device_combo active text: %1", default_device));
1192 device_combo.set_active_text(default_device);
1196 // @return true if there are input devices available
1198 EngineControl::set_input_device_popdown_strings ()
1200 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1201 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1202 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1204 vector<string> available_devices;
1206 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1207 available_devices.push_back (i->name);
1210 if (available_devices.empty()) {
1214 set_popdown_strings (input_device_combo, available_devices);
1216 std::string default_device =
1217 get_default_device(backend->input_device_name(), available_devices);
1220 string_compose ("set input_device_combo active text: %1", default_device));
1221 input_device_combo.set_active_text(default_device);
1225 // @return true if there are output devices available
1227 EngineControl::set_output_device_popdown_strings ()
1229 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1230 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1231 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1233 vector<string> available_devices;
1235 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1236 available_devices.push_back (i->name);
1239 if (available_devices.empty()) {
1243 set_popdown_strings (output_device_combo, available_devices);
1245 std::string default_device =
1246 get_default_device(backend->output_device_name(), available_devices);
1249 string_compose ("set output_device_combo active text: %1", default_device));
1250 output_device_combo.set_active_text(default_device);
1255 EngineControl::list_devices ()
1257 DEBUG_ECONTROL ("list_devices");
1258 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1261 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1263 bool devices_available = false;
1265 if (backend->use_separate_input_and_output_devices ()) {
1266 bool input_devices_available = set_input_device_popdown_strings ();
1267 bool output_devices_available = set_output_device_popdown_strings ();
1268 devices_available = input_devices_available || output_devices_available;
1270 devices_available = set_device_popdown_strings ();
1273 if (devices_available) {
1276 device_combo.clear();
1277 input_device_combo.clear();
1278 output_device_combo.clear();
1280 update_sensitivity ();
1284 EngineControl::driver_changed ()
1286 SignalBlocker blocker (*this, "driver_changed");
1287 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1290 backend->set_driver (driver_combo.get_active_text());
1293 // TODO load LRU device(s) for backend + driver combo
1295 if (!ignore_changes) {
1296 maybe_display_saved_state ();
1301 EngineControl::get_sample_rates_for_all_devices ()
1303 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1304 ARDOUR::AudioEngine::instance ()->current_backend ();
1305 vector<float> all_rates;
1307 if (backend->use_separate_input_and_output_devices ()) {
1308 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1310 all_rates = backend->available_sample_rates (get_device_name ());
1316 EngineControl::get_default_sample_rates ()
1318 vector<float> rates;
1319 rates.push_back (8000.0f);
1320 rates.push_back (16000.0f);
1321 rates.push_back (32000.0f);
1322 rates.push_back (44100.0f);
1323 rates.push_back (48000.0f);
1324 rates.push_back (88200.0f);
1325 rates.push_back (96000.0f);
1326 rates.push_back (192000.0f);
1327 rates.push_back (384000.0f);
1332 EngineControl::set_samplerate_popdown_strings ()
1334 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1335 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1340 if (_have_control) {
1341 sr = get_sample_rates_for_all_devices ();
1343 sr = get_default_sample_rates ();
1346 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1347 s.push_back (rate_as_string (*x));
1348 if (*x == _desired_sample_rate) {
1353 set_popdown_strings (sample_rate_combo, s);
1356 if (ARDOUR::AudioEngine::instance()->running()) {
1357 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1359 else if (desired.empty ()) {
1360 float new_active_sr = backend->default_sample_rate ();
1362 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1363 new_active_sr = sr.front ();
1366 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1368 sample_rate_combo.set_active_text (desired);
1372 update_sensitivity ();
1376 EngineControl::get_buffer_sizes_for_all_devices ()
1378 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1379 ARDOUR::AudioEngine::instance ()->current_backend ();
1380 vector<uint32_t> all_sizes;
1382 if (backend->use_separate_input_and_output_devices ()) {
1383 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1385 all_sizes = backend->available_buffer_sizes (get_device_name ());
1391 EngineControl::get_default_buffer_sizes ()
1393 vector<uint32_t> sizes;
1394 sizes.push_back (8);
1395 sizes.push_back (16);
1396 sizes.push_back (32);
1397 sizes.push_back (64);
1398 sizes.push_back (128);
1399 sizes.push_back (256);
1400 sizes.push_back (512);
1401 sizes.push_back (1024);
1402 sizes.push_back (2048);
1403 sizes.push_back (4096);
1404 sizes.push_back (8192);
1409 EngineControl::set_buffersize_popdown_strings ()
1411 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1412 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1413 vector<uint32_t> bs;
1416 if (_have_control) {
1417 bs = get_buffer_sizes_for_all_devices ();
1418 } else if (backend->can_change_buffer_size_when_running()) {
1419 bs = get_default_buffer_sizes ();
1422 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1423 s.push_back (bufsize_as_string (*x));
1426 uint32_t previous_size = 0;
1427 if (!buffer_size_combo.get_active_text().empty()) {
1428 previous_size = get_buffer_size ();
1431 set_popdown_strings (buffer_size_combo, s);
1435 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1436 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1439 buffer_size_combo.set_active_text(s.front());
1441 uint32_t period = backend->buffer_size();
1442 if (0 == period && backend->use_separate_input_and_output_devices()) {
1443 period = backend->default_buffer_size(get_input_device_name());
1445 if (0 == period && backend->use_separate_input_and_output_devices()) {
1446 period = backend->default_buffer_size(get_output_device_name());
1448 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1449 period = backend->default_buffer_size(get_device_name());
1452 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1454 show_buffer_duration ();
1456 update_sensitivity ();
1460 EngineControl::set_nperiods_popdown_strings ()
1462 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1463 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1464 vector<uint32_t> np;
1467 if (backend->can_set_period_size()) {
1468 np = backend->available_period_sizes (get_driver());
1471 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1472 s.push_back (nperiods_as_string (*x));
1475 set_popdown_strings (nperiods_combo, s);
1478 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1481 update_sensitivity ();
1485 EngineControl::device_changed ()
1487 SignalBlocker blocker (*this, "device_changed");
1488 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1491 string device_name_in;
1492 string device_name_out; // only used if backend support separate I/O devices
1494 if (backend->use_separate_input_and_output_devices()) {
1495 device_name_in = get_input_device_name ();
1496 device_name_out = get_output_device_name ();
1498 device_name_in = get_device_name ();
1501 /* we set the backend-device to query various device related intormation.
1502 * This has the side effect that backend->device_name() will match
1503 * the device_name and 'change_device' will never be true.
1504 * so work around this by setting...
1506 if (backend->use_separate_input_and_output_devices()) {
1507 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1508 queue_device_changed = true;
1511 if (device_name_in != backend->device_name()) {
1512 queue_device_changed = true;
1516 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1517 if (backend->use_separate_input_and_output_devices()) {
1518 backend->set_input_device_name (device_name_in);
1519 backend->set_output_device_name (device_name_out);
1521 backend->set_device_name(device_name_in);
1525 /* don't allow programmatic change to combos to cause a
1526 recursive call to this method.
1528 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1530 set_samplerate_popdown_strings ();
1531 set_buffersize_popdown_strings ();
1532 set_nperiods_popdown_strings ();
1534 /* TODO set min + max channel counts here */
1536 manage_control_app_sensitivity ();
1539 /* pick up any saved state for this device */
1541 if (!ignore_changes) {
1542 maybe_display_saved_state ();
1547 EngineControl::input_device_changed ()
1549 DEBUG_ECONTROL ("input_device_changed");
1551 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1552 if (backend && backend->match_input_output_devices_or_none ()) {
1553 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1555 if (get_output_device_name () != dev_none
1556 && get_input_device_name () != dev_none
1557 && get_input_device_name () != get_output_device_name ()) {
1558 block_changed_signals ();
1559 if (contains_value (output_device_combo, get_input_device_name ())) {
1560 output_device_combo.set_active_text (get_input_device_name ());
1562 assert (contains_value (output_device_combo, dev_none));
1563 output_device_combo.set_active_text (dev_none);
1565 unblock_changed_signals ();
1572 EngineControl::output_device_changed ()
1574 DEBUG_ECONTROL ("output_device_changed");
1575 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1576 if (backend && backend->match_input_output_devices_or_none ()) {
1577 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1579 if (get_input_device_name () != dev_none
1580 && get_input_device_name () != dev_none
1581 && get_input_device_name () != get_output_device_name ()) {
1582 block_changed_signals ();
1583 if (contains_value (input_device_combo, get_output_device_name ())) {
1584 input_device_combo.set_active_text (get_output_device_name ());
1586 assert (contains_value (input_device_combo, dev_none));
1587 input_device_combo.set_active_text (dev_none);
1589 unblock_changed_signals ();
1596 EngineControl::bufsize_as_string (uint32_t sz)
1598 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1602 EngineControl::nperiods_as_string (uint32_t np)
1605 snprintf (buf, sizeof (buf), "%u", np);
1611 EngineControl::sample_rate_changed ()
1613 DEBUG_ECONTROL ("sample_rate_changed");
1614 /* reset the strings for buffer size to show the correct msec value
1615 (reflecting the new sample rate).
1618 show_buffer_duration ();
1623 EngineControl::buffer_size_changed ()
1625 DEBUG_ECONTROL ("buffer_size_changed");
1626 show_buffer_duration ();
1630 EngineControl::nperiods_changed ()
1632 DEBUG_ECONTROL ("nperiods_changed");
1633 show_buffer_duration ();
1637 EngineControl::show_buffer_duration ()
1639 DEBUG_ECONTROL ("show_buffer_duration");
1640 /* buffer sizes - convert from just samples to samples + msecs for
1641 * the displayed string
1644 string bs_text = buffer_size_combo.get_active_text ();
1645 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1646 uint32_t rate = get_rate();
1648 /* Except for ALSA and Dummy backends, we don't know the number of periods
1649 * per cycle and settings.
1651 * jack1 vs jack2 have different default latencies since jack2 start
1652 * in async-mode unless --sync is given which adds an extra cycle
1653 * of latency. The value is not known if jackd is started externally..
1655 * So just display the period size, that's also what
1656 * ARDOUR_UI::update_sample_rate() does for the status bar.
1657 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1658 * but still, that's the buffer period, not [round-trip] latency)
1661 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1662 buffer_size_duration_label.set_text (buf);
1666 EngineControl::midi_option_changed ()
1668 DEBUG_ECONTROL ("midi_option_changed");
1669 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1672 backend->set_midi_option (get_midi_option());
1674 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1676 //_midi_devices.clear(); // TODO merge with state-saved settings..
1677 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1678 std::vector<MidiDeviceSettings> new_devices;
1680 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1681 MidiDeviceSettings mds = find_midi_device (i->name);
1682 if (i->available && !mds) {
1683 uint32_t input_latency = 0;
1684 uint32_t output_latency = 0;
1685 if (_can_set_midi_latencies) {
1686 input_latency = backend->systemic_midi_input_latency (i->name);
1687 output_latency = backend->systemic_midi_output_latency (i->name);
1689 bool enabled = backend->midi_device_enabled (i->name);
1690 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1691 new_devices.push_back (ptr);
1692 } else if (i->available) {
1693 new_devices.push_back (mds);
1696 _midi_devices = new_devices;
1698 if (_midi_devices.empty()) {
1699 midi_devices_button.hide ();
1701 midi_devices_button.show ();
1706 EngineControl::parameter_changed ()
1710 EngineControl::State
1711 EngineControl::get_matching_state (const string& backend)
1713 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1714 if ((*i)->backend == backend) {
1721 EngineControl::State
1722 EngineControl::get_matching_state (
1723 const string& backend,
1724 const string& driver,
1725 const string& device)
1727 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1728 if ((*i)->backend == backend &&
1729 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1737 EngineControl::State
1738 EngineControl::get_matching_state (
1739 const string& backend,
1740 const string& driver,
1741 const string& input_device,
1742 const string& output_device)
1744 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1745 if ((*i)->backend == backend &&
1746 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1754 EngineControl::State
1755 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1757 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1760 if (backend->use_separate_input_and_output_devices ()) {
1761 return get_matching_state (backend_combo.get_active_text(),
1762 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1763 input_device_combo.get_active_text(),
1764 output_device_combo.get_active_text());
1766 return get_matching_state (backend_combo.get_active_text(),
1767 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1768 device_combo.get_active_text());
1772 return get_matching_state (backend_combo.get_active_text(),
1774 device_combo.get_active_text());
1777 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1778 const EngineControl::State& state2)
1780 if (state1->backend == state2->backend &&
1781 state1->driver == state2->driver &&
1782 state1->device == state2->device &&
1783 state1->input_device == state2->input_device &&
1784 state1->output_device == state2->output_device) {
1791 EngineControl::state_sort_cmp (const State &a, const State &b) {
1795 else if (b->active) {
1799 return a->lru < b->lru;
1803 EngineControl::State
1804 EngineControl::save_state ()
1808 if (!_have_control) {
1809 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1811 state->lru = time (NULL) ;
1814 state.reset(new StateStruct);
1815 state->backend = get_backend ();
1817 state.reset(new StateStruct);
1818 store_state (state);
1821 for (StateList::iterator i = states.begin(); i != states.end();) {
1822 if (equivalent_states (*i, state)) {
1823 i = states.erase(i);
1829 states.push_back (state);
1831 states.sort (state_sort_cmp);
1837 EngineControl::store_state (State state)
1839 state->backend = get_backend ();
1840 state->driver = get_driver ();
1841 state->device = get_device_name ();
1842 state->input_device = get_input_device_name ();
1843 state->output_device = get_output_device_name ();
1844 state->sample_rate = get_rate ();
1845 state->buffer_size = get_buffer_size ();
1846 state->n_periods = get_nperiods ();
1847 state->input_latency = get_input_latency ();
1848 state->output_latency = get_output_latency ();
1849 state->input_channels = get_input_channels ();
1850 state->output_channels = get_output_channels ();
1851 state->midi_option = get_midi_option ();
1852 state->midi_devices = _midi_devices;
1853 state->use_buffered_io = get_use_buffered_io ();
1854 state->lru = time (NULL) ;
1858 EngineControl::maybe_display_saved_state ()
1860 if (!_have_control) {
1864 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1867 DEBUG_ECONTROL ("Restoring saved state");
1868 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1870 if (!_desired_sample_rate) {
1871 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1873 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1875 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1876 /* call this explicitly because we're ignoring changes to
1877 the controls at this point.
1879 show_buffer_duration ();
1880 input_latency.set_value (state->input_latency);
1881 output_latency.set_value (state->output_latency);
1883 use_buffered_io_button.set_active (state->use_buffered_io);
1885 if (!state->midi_option.empty()) {
1886 midi_option_combo.set_active_text (state->midi_option);
1887 _midi_devices = state->midi_devices;
1890 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1895 EngineControl::get_state ()
1899 XMLNode* root = new XMLNode ("AudioMIDISetup");
1902 if (!states.empty()) {
1903 XMLNode* state_nodes = new XMLNode ("EngineStates");
1905 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1907 XMLNode* node = new XMLNode ("State");
1909 node->add_property ("backend", (*i)->backend);
1910 node->add_property ("driver", (*i)->driver);
1911 node->add_property ("device", (*i)->device);
1912 node->add_property ("input-device", (*i)->input_device);
1913 node->add_property ("output-device", (*i)->output_device);
1914 node->add_property ("sample-rate", (*i)->sample_rate);
1915 node->add_property ("buffer-size", (*i)->buffer_size);
1916 node->add_property ("n-periods", (*i)->n_periods);
1917 node->add_property ("input-latency", (*i)->input_latency);
1918 node->add_property ("output-latency", (*i)->output_latency);
1919 node->add_property ("input-channels", (*i)->input_channels);
1920 node->add_property ("output-channels", (*i)->output_channels);
1921 node->add_property ("active", (*i)->active ? "yes" : "no");
1922 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1923 node->add_property ("midi-option", (*i)->midi_option);
1924 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1926 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1927 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1928 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1929 midi_device_stuff->add_property (X_("name"), (*p)->name);
1930 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1931 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1932 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1933 midi_devices->add_child_nocopy (*midi_device_stuff);
1935 node->add_child_nocopy (*midi_devices);
1937 state_nodes->add_child_nocopy (*node);
1940 root->add_child_nocopy (*state_nodes);
1947 EngineControl::set_default_state ()
1949 vector<string> backend_names;
1950 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1952 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1953 backend_names.push_back ((*b)->name);
1955 backend_combo.set_active_text (backend_names.front());
1957 // We could set default backends per platform etc here
1963 EngineControl::set_state (const XMLNode& root)
1965 XMLNodeList clist, cclist;
1966 XMLNodeConstIterator citer, cciter;
1967 XMLNode const * child;
1968 XMLNode const * grandchild;
1969 XMLProperty const * prop = NULL;
1971 if (root.name() != "AudioMIDISetup") {
1975 clist = root.children();
1979 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1983 if (child->name() != "EngineStates") {
1987 cclist = child->children();
1989 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1990 State state (new StateStruct);
1992 grandchild = *cciter;
1994 if (grandchild->name() != "State") {
1998 if ((prop = grandchild->property ("backend")) == 0) {
2001 state->backend = prop->value ();
2003 if ((prop = grandchild->property ("driver")) == 0) {
2006 state->driver = prop->value ();
2008 if ((prop = grandchild->property ("device")) == 0) {
2011 state->device = prop->value ();
2013 if ((prop = grandchild->property ("input-device")) == 0) {
2016 state->input_device = prop->value ();
2018 if ((prop = grandchild->property ("output-device")) == 0) {
2021 state->output_device = prop->value ();
2023 if ((prop = grandchild->property ("sample-rate")) == 0) {
2026 state->sample_rate = atof (prop->value ());
2028 if ((prop = grandchild->property ("buffer-size")) == 0) {
2031 state->buffer_size = atoi (prop->value ());
2033 if ((prop = grandchild->property ("n-periods")) == 0) {
2034 // optional (new value in 4.5)
2035 state->n_periods = 0;
2037 state->n_periods = atoi (prop->value ());
2040 if ((prop = grandchild->property ("input-latency")) == 0) {
2043 state->input_latency = atoi (prop->value ());
2045 if ((prop = grandchild->property ("output-latency")) == 0) {
2048 state->output_latency = atoi (prop->value ());
2050 if ((prop = grandchild->property ("input-channels")) == 0) {
2053 state->input_channels = atoi (prop->value ());
2055 if ((prop = grandchild->property ("output-channels")) == 0) {
2058 state->output_channels = atoi (prop->value ());
2060 if ((prop = grandchild->property ("active")) == 0) {
2063 state->active = string_is_affirmative (prop->value ());
2065 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2068 state->use_buffered_io = string_is_affirmative (prop->value ());
2070 if ((prop = grandchild->property ("midi-option")) == 0) {
2073 state->midi_option = prop->value ();
2075 state->midi_devices.clear();
2077 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2078 const XMLNodeList mnc = midinode->children();
2079 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2080 if ((*n)->property (X_("name")) == 0
2081 || (*n)->property (X_("enabled")) == 0
2082 || (*n)->property (X_("input-latency")) == 0
2083 || (*n)->property (X_("output-latency")) == 0
2088 MidiDeviceSettings ptr (new MidiDeviceSetting(
2089 (*n)->property (X_("name"))->value (),
2090 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2091 atoi ((*n)->property (X_("input-latency"))->value ()),
2092 atoi ((*n)->property (X_("output-latency"))->value ())
2094 state->midi_devices.push_back (ptr);
2098 if ((prop = grandchild->property ("lru"))) {
2099 state->lru = atoi (prop->value ());
2103 /* remove accumulated duplicates (due to bug in ealier version)
2104 * this can be removed again before release
2106 for (StateList::iterator i = states.begin(); i != states.end();) {
2107 if ((*i)->backend == state->backend &&
2108 (*i)->driver == state->driver &&
2109 (*i)->device == state->device) {
2110 i = states.erase(i);
2117 states.push_back (state);
2121 /* now see if there was an active state and switch the setup to it */
2123 // purge states of backend that are not available in this built
2124 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2125 vector<std::string> backend_names;
2127 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2128 backend_names.push_back((*i)->name);
2130 for (StateList::iterator i = states.begin(); i != states.end();) {
2131 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2132 i = states.erase(i);
2138 states.sort (state_sort_cmp);
2140 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2143 return set_current_state (*i);
2150 EngineControl::set_current_state (const State& state)
2152 DEBUG_ECONTROL ("set_current_state");
2154 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2156 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2157 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2158 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2159 // this shouldn't happen as the invalid backend names should have been
2160 // removed from the list of states.
2164 // now reflect the change in the backend in the GUI so backend_changed will
2165 // do the right thing
2166 backend_combo.set_active_text (state->backend);
2168 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2170 // we don't have control don't restore state
2175 if (!state->driver.empty ()) {
2176 if (!backend->requires_driver_selection ()) {
2177 DEBUG_ECONTROL ("Backend should require driver selection");
2178 // A backend has changed from having driver selection to not having
2179 // it or someone has been manually editing a config file and messed
2184 if (backend->set_driver (state->driver) != 0) {
2185 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2186 // Driver names for a backend have changed and the name in the
2187 // config file is now invalid or support for driver is no longer
2188 // included in the backend
2191 // no need to set the driver_combo as backend_changed will use
2192 // backend->driver_name to set the active driver
2195 if (!state->device.empty ()) {
2196 if (backend->set_device_name (state->device) != 0) {
2198 string_compose ("Unable to set device name %1", state->device));
2199 // device is no longer available on the system
2202 // no need to set active device as it will be picked up in
2203 // via backend_changed ()/set_device_popdown_strings
2206 // backend supports separate input/output devices
2207 if (backend->set_input_device_name (state->input_device) != 0) {
2208 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2209 state->input_device));
2210 // input device is no longer available on the system
2214 if (backend->set_output_device_name (state->output_device) != 0) {
2215 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2216 state->input_device));
2217 // output device is no longer available on the system
2220 // no need to set active devices as it will be picked up in via
2221 // backend_changed ()/set_*_device_popdown_strings
2226 // Now restore the state of the rest of the controls
2228 // We don't use a SignalBlocker as set_current_state is currently only
2229 // called from set_state before any signals are connected. If at some point
2230 // a more general named state mechanism is implemented and
2231 // set_current_state is called while signals are connected then a
2232 // SignalBlocker will need to be instantiated before setting these.
2234 device_combo.set_active_text (state->device);
2235 input_device_combo.set_active_text (state->input_device);
2236 output_device_combo.set_active_text (state->output_device);
2237 if (!_desired_sample_rate) {
2238 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2240 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2241 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2242 input_latency.set_value (state->input_latency);
2243 output_latency.set_value (state->output_latency);
2244 midi_option_combo.set_active_text (state->midi_option);
2245 use_buffered_io_button.set_active (state->use_buffered_io);
2250 EngineControl::push_state_to_backend (bool start)
2252 DEBUG_ECONTROL ("push_state_to_backend");
2253 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2254 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2260 /* figure out what is going to change */
2262 bool restart_required = false;
2263 bool was_running = ARDOUR::AudioEngine::instance()->running();
2264 bool change_driver = false;
2265 bool change_device = false;
2266 bool change_rate = false;
2267 bool change_bufsize = false;
2268 bool change_nperiods = false;
2269 bool change_latency = false;
2270 bool change_channels = false;
2271 bool change_midi = false;
2272 bool change_buffered_io = false;
2274 uint32_t ochan = get_output_channels ();
2275 uint32_t ichan = get_input_channels ();
2277 if (_have_control) {
2279 if (started_at_least_once) {
2281 /* we can control the backend */
2283 if (backend->requires_driver_selection()) {
2284 if (get_driver() != backend->driver_name()) {
2285 change_driver = true;
2289 if (backend->use_separate_input_and_output_devices()) {
2290 if (get_input_device_name() != backend->input_device_name()) {
2291 change_device = true;
2293 if (get_output_device_name() != backend->output_device_name()) {
2294 change_device = true;
2297 if (get_device_name() != backend->device_name()) {
2298 change_device = true;
2302 if (queue_device_changed) {
2303 change_device = true;
2306 if (get_rate() != backend->sample_rate()) {
2310 if (get_buffer_size() != backend->buffer_size()) {
2311 change_bufsize = true;
2314 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2315 && get_nperiods() != backend->period_size()) {
2316 change_nperiods = true;
2319 if (get_midi_option() != backend->midi_option()) {
2323 if (backend->can_use_buffered_io()) {
2324 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2325 change_buffered_io = true;
2329 /* zero-requested channels means "all available" */
2332 ichan = backend->input_channels();
2336 ochan = backend->output_channels();
2339 if (ichan != backend->input_channels()) {
2340 change_channels = true;
2343 if (ochan != backend->output_channels()) {
2344 change_channels = true;
2347 if (get_input_latency() != backend->systemic_input_latency() ||
2348 get_output_latency() != backend->systemic_output_latency()) {
2349 change_latency = true;
2352 /* backend never started, so we have to force a group
2355 change_device = true;
2356 if (backend->requires_driver_selection()) {
2357 change_driver = true;
2360 change_bufsize = true;
2361 change_channels = true;
2362 change_latency = true;
2364 change_buffered_io = backend->can_use_buffered_io();
2365 change_channels = true;
2366 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2371 /* we have no control over the backend, meaning that we can
2372 * only possibly change sample rate and buffer size.
2376 if (get_rate() != backend->sample_rate()) {
2377 change_bufsize = true;
2380 if (get_buffer_size() != backend->buffer_size()) {
2381 change_bufsize = true;
2385 queue_device_changed = false;
2387 if (!_have_control) {
2389 /* We do not have control over the backend, so the best we can
2390 * do is try to change the sample rate and/or bufsize and get
2394 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2398 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2403 backend->set_sample_rate (get_rate());
2406 if (change_bufsize) {
2407 backend->set_buffer_size (get_buffer_size());
2411 if (ARDOUR::AudioEngine::instance()->start ()) {
2412 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2422 /* determine if we need to stop the backend before changing parameters */
2424 if (change_driver || change_device || change_channels || change_nperiods ||
2425 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2426 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2427 change_midi || change_buffered_io ||
2428 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2429 restart_required = true;
2431 restart_required = false;
2436 if (restart_required) {
2437 if (ARDOUR::AudioEngine::instance()->stop()) {
2443 if (change_driver && backend->set_driver (get_driver())) {
2444 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2447 if (backend->use_separate_input_and_output_devices()) {
2448 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2449 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2452 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2453 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2457 if (change_device && backend->set_device_name (get_device_name())) {
2458 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2462 if (change_rate && backend->set_sample_rate (get_rate())) {
2463 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2466 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2467 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2470 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2471 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2475 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2476 if (backend->set_input_channels (get_input_channels())) {
2477 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2480 if (backend->set_output_channels (get_output_channels())) {
2481 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2485 if (change_latency) {
2486 if (backend->set_systemic_input_latency (get_input_latency())) {
2487 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2490 if (backend->set_systemic_output_latency (get_output_latency())) {
2491 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2497 backend->set_midi_option (get_midi_option());
2500 if (change_buffered_io) {
2501 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2505 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2506 if (_measure_midi) {
2507 if (*p == _measure_midi) {
2508 backend->set_midi_device_enabled ((*p)->name, true);
2510 backend->set_midi_device_enabled ((*p)->name, false);
2512 if (backend->can_change_systemic_latency_when_running ()) {
2513 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2514 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2518 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2519 if (backend->can_set_systemic_midi_latencies()) {
2520 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2521 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2526 if (start || (was_running && restart_required)) {
2527 if (ARDOUR::AudioEngine::instance()->start()) {
2538 EngineControl::post_push ()
2540 /* get a pointer to the current state object, creating one if
2544 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2547 state = save_state ();
2553 states.sort (state_sort_cmp);
2557 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2558 (*i)->active = false;
2561 /* mark this one active (to be used next time the dialog is
2565 state->active = true;
2567 if (_have_control) { // XXX
2568 manage_control_app_sensitivity ();
2571 /* schedule a redisplay of MIDI ports */
2572 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2577 EngineControl::get_rate () const
2579 float r = atof (sample_rate_combo.get_active_text ());
2580 /* the string may have been translated with an abbreviation for
2581 * thousands, so use a crude heuristic to fix this.
2591 EngineControl::get_buffer_size () const
2593 string txt = buffer_size_combo.get_active_text ();
2596 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2597 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2598 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2606 EngineControl::get_nperiods () const
2608 string txt = nperiods_combo.get_active_text ();
2609 return atoi (txt.c_str());
2613 EngineControl::get_midi_option () const
2615 return midi_option_combo.get_active_text();
2619 EngineControl::get_use_buffered_io () const
2621 return use_buffered_io_button.get_active();
2625 EngineControl::get_input_channels() const
2627 if (ARDOUR::Profile->get_mixbus()) {
2628 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2629 if (!backend) return 0;
2630 return backend->input_channels();
2632 return (uint32_t) input_channels_adjustment.get_value();
2636 EngineControl::get_output_channels() const
2638 if (ARDOUR::Profile->get_mixbus()) {
2639 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2640 if (!backend) return 0;
2641 return backend->input_channels();
2643 return (uint32_t) output_channels_adjustment.get_value();
2647 EngineControl::get_input_latency() const
2649 return (uint32_t) input_latency_adjustment.get_value();
2653 EngineControl::get_output_latency() const
2655 return (uint32_t) output_latency_adjustment.get_value();
2659 EngineControl::get_backend () const
2661 return backend_combo.get_active_text ();
2665 EngineControl::get_driver () const
2667 if (driver_combo.get_parent()) {
2668 return driver_combo.get_active_text ();
2675 EngineControl::get_device_name () const
2677 return device_combo.get_active_text ();
2681 EngineControl::get_input_device_name () const
2683 return input_device_combo.get_active_text ();
2687 EngineControl::get_output_device_name () const
2689 return output_device_combo.get_active_text ();
2693 EngineControl::control_app_button_clicked ()
2695 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2701 backend->launch_control_app ();
2705 EngineControl::start_stop_button_clicked ()
2707 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2713 if (ARDOUR::AudioEngine::instance()->running()) {
2714 ARDOUR::AudioEngine::instance()->stop ();
2716 if (!ARDOUR_UI::instance()->session_loaded) {
2720 if (!ARDOUR_UI::instance()->session_loaded) {
2721 ArdourDialog::on_response (RESPONSE_OK);
2727 EngineControl::update_devices_button_clicked ()
2729 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2735 if (backend->update_devices()) {
2736 device_list_changed ();
2741 EngineControl::use_buffered_io_button_clicked ()
2743 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2749 bool set_buffered_io = !use_buffered_io_button.get_active();
2750 use_buffered_io_button.set_active (set_buffered_io);
2751 backend->set_use_buffered_io (set_buffered_io);
2755 EngineControl::manage_control_app_sensitivity ()
2757 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2763 string appname = backend->control_app_name();
2765 if (appname.empty()) {
2766 control_app_button.set_sensitive (false);
2768 control_app_button.set_sensitive (true);
2773 EngineControl::set_desired_sample_rate (uint32_t sr)
2775 _desired_sample_rate = sr;
2776 if (ARDOUR::AudioEngine::instance ()->running ()
2777 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2784 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2786 if (page_num == 0) {
2787 _measure_midi.reset();
2788 update_sensitivity ();
2791 if (page_num == midi_tab) {
2793 refresh_midi_display ();
2796 if (page_num == latency_tab) {
2799 if (ARDOUR::AudioEngine::instance()->running()) {
2804 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2806 /* save any existing latency values */
2808 uint32_t il = (uint32_t) input_latency.get_value ();
2809 uint32_t ol = (uint32_t) input_latency.get_value ();
2811 /* reset to zero so that our new test instance
2812 will be clean of any existing latency measures.
2814 NB. this should really be done by the backend
2815 when stated for latency measurement.
2818 input_latency.set_value (0);
2819 output_latency.set_value (0);
2821 push_state_to_backend (false);
2825 input_latency.set_value (il);
2826 output_latency.set_value (ol);
2829 // This should be done in push_state_to_backend()
2830 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2831 disable_latency_tab ();
2834 enable_latency_tab ();
2838 end_latency_detection ();
2839 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2844 /* latency measurement */
2847 EngineControl::check_audio_latency_measurement ()
2849 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2851 if (mtdm->resolve () < 0) {
2852 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2856 if (mtdm->get_peak () > 0.707f) {
2857 // get_peak() resets the peak-hold in the detector.
2858 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2859 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2863 if (mtdm->err () > 0.3) {
2869 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2871 if (sample_rate == 0) {
2872 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2873 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2877 int frames_total = mtdm->del();
2878 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2880 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2881 _("Detected roundtrip latency: "),
2882 frames_total, frames_total * 1000.0f/sample_rate,
2883 _("Systemic latency: "),
2884 extra, extra * 1000.0f/sample_rate);
2888 if (mtdm->err () > 0.2) {
2890 strcat (buf, _("(signal detection error)"));
2896 strcat (buf, _("(inverted - bad wiring)"));
2900 lm_results.set_markup (string_compose (results_markup, buf));
2903 have_lm_results = true;
2904 end_latency_detection ();
2905 lm_use_button.set_sensitive (true);
2913 EngineControl::check_midi_latency_measurement ()
2915 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2917 if (!mididm->have_signal () || mididm->latency () == 0) {
2918 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2923 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2925 if (sample_rate == 0) {
2926 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2927 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2931 ARDOUR::framecnt_t frames_total = mididm->latency();
2932 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2933 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2934 _("Detected roundtrip latency: "),
2935 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2936 _("Systemic latency: "),
2937 extra, extra * 1000.0f / sample_rate);
2941 if (!mididm->ok ()) {
2943 strcat (buf, _("(averaging)"));
2947 if (mididm->deviation () > 50.0) {
2949 strcat (buf, _("(too large jitter)"));
2951 } else if (mididm->deviation () > 10.0) {
2953 strcat (buf, _("(large jitter)"));
2957 have_lm_results = true;
2958 end_latency_detection ();
2959 lm_use_button.set_sensitive (true);
2960 lm_results.set_markup (string_compose (results_markup, buf));
2962 } else if (mididm->processed () > 400) {
2963 have_lm_results = false;
2964 end_latency_detection ();
2965 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2969 lm_results.set_markup (string_compose (results_markup, buf));
2975 EngineControl::start_latency_detection ()
2977 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2978 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2980 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2981 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2982 if (_measure_midi) {
2983 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2985 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2987 lm_measure_label.set_text (_("Cancel"));
2988 have_lm_results = false;
2989 lm_use_button.set_sensitive (false);
2990 lm_input_channel_combo.set_sensitive (false);
2991 lm_output_channel_combo.set_sensitive (false);
2997 EngineControl::end_latency_detection ()
2999 latency_timeout.disconnect ();
3000 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3001 lm_measure_label.set_text (_("Measure"));
3002 if (!have_lm_results) {
3003 lm_use_button.set_sensitive (false);
3005 lm_input_channel_combo.set_sensitive (true);
3006 lm_output_channel_combo.set_sensitive (true);
3011 EngineControl::latency_button_clicked ()
3014 start_latency_detection ();
3016 end_latency_detection ();
3021 EngineControl::latency_back_button_clicked ()
3023 ARDOUR::AudioEngine::instance()->stop(true);
3024 notebook.set_current_page(0);
3028 EngineControl::use_latency_button_clicked ()
3030 if (_measure_midi) {
3031 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3035 ARDOUR::framecnt_t frames_total = mididm->latency();
3036 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3037 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3038 _measure_midi->input_latency = one_way;
3039 _measure_midi->output_latency = one_way;
3040 notebook.set_current_page (midi_tab);
3042 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3048 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3049 one_way = std::max (0., one_way);
3051 input_latency_adjustment.set_value (one_way);
3052 output_latency_adjustment.set_value (one_way);
3054 /* back to settings page */
3055 notebook.set_current_page (0);
3060 EngineControl::on_delete_event (GdkEventAny* ev)
3062 if (notebook.get_current_page() == 2) {
3063 /* currently on latency tab - be sure to clean up */
3064 end_latency_detection ();
3066 return ArdourDialog::on_delete_event (ev);
3070 EngineControl::engine_running ()
3072 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3075 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3076 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3078 if (backend->can_set_period_size ()) {
3079 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3082 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3083 connect_disconnect_button.show();
3085 started_at_least_once = true;
3086 if (_have_control) {
3087 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3089 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3091 update_sensitivity();
3095 EngineControl::engine_stopped ()
3097 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3100 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3101 connect_disconnect_button.show();
3103 if (_have_control) {
3104 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3106 engine_status.set_markup(X_(""));
3109 update_sensitivity();
3113 EngineControl::device_list_changed ()
3115 if (ignore_device_changes) {
3118 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3120 midi_option_changed();
3124 EngineControl::connect_disconnect_click()
3126 if (ARDOUR::AudioEngine::instance()->running()) {
3129 if (!ARDOUR_UI::instance()->session_loaded) {
3133 if (!ARDOUR_UI::instance()->session_loaded) {
3134 ArdourDialog::on_response (RESPONSE_OK);
3140 EngineControl::calibrate_audio_latency ()
3142 _measure_midi.reset ();
3143 have_lm_results = false;
3144 lm_use_button.set_sensitive (false);
3145 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3146 notebook.set_current_page (latency_tab);
3150 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3153 have_lm_results = false;
3154 lm_use_button.set_sensitive (false);
3155 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3156 notebook.set_current_page (latency_tab);
3160 EngineControl::configure_midi_devices ()
3162 notebook.set_current_page (midi_tab);