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"
56 #include "public_editor.h"
63 using namespace Gtkmm2ext;
66 using namespace ARDOUR_UI_UTILS;
68 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
70 static const unsigned int midi_tab = 2;
71 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
73 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
75 EngineControl::EngineControl ()
76 : ArdourDialog (_("Audio/MIDI Setup"))
79 , input_latency_adjustment (0, 0, 99999, 1)
80 , input_latency (input_latency_adjustment)
81 , output_latency_adjustment (0, 0, 99999, 1)
82 , output_latency (output_latency_adjustment)
83 , input_channels_adjustment (0, 0, 256, 1)
84 , input_channels (input_channels_adjustment)
85 , output_channels_adjustment (0, 0, 256, 1)
86 , output_channels (output_channels_adjustment)
87 , ports_adjustment (128, 8, 1024, 1, 16)
88 , ports_spinner (ports_adjustment)
89 , control_app_button (_("Device Control Panel"))
90 , midi_devices_button (_("Midi Device Setup"))
91 , start_stop_button (_("Stop"))
92 , update_devices_button (_("Refresh Devices"))
93 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
94 , lm_measure_label (_("Measure"))
95 , lm_use_button (_("Use results"))
96 , lm_back_button (_("Back to settings ... (ignore results)"))
97 , lm_button_audio (_("Calibrate Audio"))
99 , have_lm_results (false)
101 , midi_back_button (_("Back to settings"))
103 , ignore_device_changes (0)
104 , _desired_sample_rate (0)
105 , started_at_least_once (false)
106 , queue_device_changed (false)
107 , _have_control (true)
110 using namespace Notebook_Helpers;
111 vector<string> backend_names;
113 AttachOptions xopt = AttachOptions (FILL|EXPAND);
116 set_name (X_("AudioMIDISetup"));
118 /* the backend combo is the one thing that is ALWAYS visible */
120 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
122 if (backends.empty()) {
123 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));
125 throw failed_constructor ();
128 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
129 backend_names.push_back ((*b)->name);
132 set_popdown_strings (backend_combo, backend_names);
134 /* setup basic packing characteristics for the table used on the main
135 * tab of the notebook
138 basic_packer.set_spacings (6);
139 basic_packer.set_border_width (12);
140 basic_packer.set_homogeneous (false);
144 basic_hbox.pack_start (basic_packer, false, false);
146 /* latency measurement tab */
148 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
151 lm_table.set_row_spacings (12);
152 lm_table.set_col_spacings (6);
153 lm_table.set_homogeneous (false);
155 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
158 lm_preamble.set_width_chars (60);
159 lm_preamble.set_line_wrap (true);
160 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
162 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
165 Gtk::Label* preamble;
166 preamble = manage (new Label);
167 preamble->set_width_chars (60);
168 preamble->set_line_wrap (true);
169 preamble->set_markup (_("Select two channels below and connect them using a cable."));
171 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
174 label = manage (new Label (_("Output channel")));
175 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
177 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
178 misc_align->add (lm_output_channel_combo);
179 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
182 label = manage (new Label (_("Input channel")));
183 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
185 misc_align = manage (new Alignment (0.0, 0.5));
186 misc_align->add (lm_input_channel_combo);
187 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
190 lm_measure_label.set_padding (10, 10);
191 lm_measure_button.add (lm_measure_label);
192 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
193 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
194 lm_back_button_signal = lm_back_button.signal_clicked().connect(
195 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
197 lm_use_button.set_sensitive (false);
199 /* Increase the default spacing around the labels of these three
205 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
206 l->set_padding (10, 10);
209 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
210 l->set_padding (10, 10);
213 preamble = manage (new Label);
214 preamble->set_width_chars (60);
215 preamble->set_line_wrap (true);
216 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
217 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220 preamble = manage (new Label);
221 preamble->set_width_chars (60);
222 preamble->set_line_wrap (true);
223 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
224 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 ++row; // skip a row in the table
227 ++row; // skip a row in the table
229 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 ++row; // skip a row in the table
232 ++row; // skip a row in the table
234 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
236 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
238 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
240 lm_vbox.set_border_width (12);
241 lm_vbox.pack_start (lm_table, false, false);
243 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
247 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
248 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
249 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
250 notebook.set_border_width (12);
252 notebook.set_show_tabs (false);
253 notebook.show_all ();
255 notebook.set_name ("SettingsNotebook");
257 /* packup the notebook */
259 get_vbox()->set_border_width (12);
260 get_vbox()->pack_start (notebook);
262 /* need a special function to print "all available channels" when the
263 * channel counts hit zero.
266 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
267 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
269 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
270 midi_devices_button.set_name ("generic button");
271 midi_devices_button.set_can_focus(true);
273 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
274 control_app_button.set_name ("generic button");
275 control_app_button.set_can_focus(true);
276 manage_control_app_sensitivity ();
278 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
279 start_stop_button.set_sensitive (false);
280 start_stop_button.set_name ("generic button");
281 start_stop_button.set_can_focus(true);
282 start_stop_button.set_can_default(true);
283 start_stop_button.set_act_on_release (false);
285 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
286 update_devices_button.set_sensitive (false);
287 update_devices_button.set_name ("generic button");
288 update_devices_button.set_can_focus(true);
290 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
291 use_buffered_io_button.set_sensitive (false);
292 use_buffered_io_button.set_name ("generic button");
293 use_buffered_io_button.set_can_focus(true);
295 /* Pick up any existing audio setup configuration, if appropriate */
297 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
299 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
300 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
301 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
302 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
305 if (!set_state (*audio_setup)) {
306 set_default_state ();
309 set_default_state ();
312 update_sensitivity ();
313 connect_changed_signals ();
315 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
317 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
319 connect_disconnect_button.set_no_show_all();
320 use_buffered_io_button.set_no_show_all();
321 update_devices_button.set_no_show_all();
322 start_stop_button.set_no_show_all();
323 midi_devices_button.set_no_show_all();
327 EngineControl::connect_changed_signals ()
329 backend_combo_connection = backend_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::backend_changed));
331 driver_combo_connection = driver_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::driver_changed));
333 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
335 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
337 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
339 device_combo_connection = device_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::device_changed));
341 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
342 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
344 input_device_combo_connection = input_device_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::input_device_changed));
346 output_device_combo_connection = output_device_combo.signal_changed ().connect (
347 sigc::mem_fun (*this, &EngineControl::output_device_changed));
349 input_latency_connection = input_latency.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::parameter_changed));
351 output_latency_connection = output_latency.signal_changed ().connect (
352 sigc::mem_fun (*this, &EngineControl::parameter_changed));
353 input_channels_connection = input_channels.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::parameter_changed));
355 output_channels_connection = output_channels.signal_changed ().connect (
356 sigc::mem_fun (*this, &EngineControl::parameter_changed));
360 EngineControl::block_changed_signals ()
362 if (block_signals++ == 0) {
363 DEBUG_ECONTROL ("Blocking changed signals");
364 backend_combo_connection.block ();
365 driver_combo_connection.block ();
366 sample_rate_combo_connection.block ();
367 buffer_size_combo_connection.block ();
368 nperiods_combo_connection.block ();
369 device_combo_connection.block ();
370 input_device_combo_connection.block ();
371 output_device_combo_connection.block ();
372 midi_option_combo_connection.block ();
373 input_latency_connection.block ();
374 output_latency_connection.block ();
375 input_channels_connection.block ();
376 output_channels_connection.block ();
381 EngineControl::unblock_changed_signals ()
383 if (--block_signals == 0) {
384 DEBUG_ECONTROL ("Unblocking changed signals");
385 backend_combo_connection.unblock ();
386 driver_combo_connection.unblock ();
387 sample_rate_combo_connection.unblock ();
388 buffer_size_combo_connection.unblock ();
389 nperiods_combo_connection.unblock ();
390 device_combo_connection.unblock ();
391 input_device_combo_connection.unblock ();
392 output_device_combo_connection.unblock ();
393 midi_option_combo_connection.unblock ();
394 input_latency_connection.unblock ();
395 output_latency_connection.unblock ();
396 input_channels_connection.unblock ();
397 output_channels_connection.unblock ();
401 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
402 const std::string& reason)
403 : ec (engine_control)
406 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
407 ec.block_changed_signals ();
410 EngineControl::SignalBlocker::~SignalBlocker ()
412 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
413 ec.unblock_changed_signals ();
417 EngineControl::on_show ()
419 ArdourDialog::on_show ();
420 if (Splash::instance()) {
421 Splash::instance()->hide ();
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::on_map ()
434 if (!ARDOUR_UI::instance()->session_loaded && !PublicEditor::_instance) {
435 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
436 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
437 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
439 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
441 ArdourDialog::on_map ();
445 EngineControl::try_autostart ()
447 if (!start_stop_button.get_sensitive()) {
450 if (ARDOUR::AudioEngine::instance()->running()) {
453 return start_engine ();
457 EngineControl::start_engine ()
459 if (push_state_to_backend(true) != 0) {
460 MessageDialog msg(*this,
461 ARDOUR::AudioEngine::instance()->get_last_backend_error());
469 EngineControl::stop_engine (bool for_latency)
471 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
472 MessageDialog msg(*this,
473 ARDOUR::AudioEngine::instance()->get_last_backend_error());
481 EngineControl::build_notebook ()
484 AttachOptions xopt = AttachOptions (FILL|EXPAND);
486 /* clear the table */
488 Gtkmm2ext::container_clear (basic_vbox);
489 Gtkmm2ext::container_clear (basic_packer);
491 if (control_app_button.get_parent()) {
492 control_app_button.get_parent()->remove (control_app_button);
495 label = manage (left_aligned_label (_("Audio System:")));
496 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
497 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
499 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
500 engine_status.show();
502 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
503 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
504 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
506 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
507 lm_button_audio.set_name ("generic button");
508 lm_button_audio.set_can_focus(true);
511 build_full_control_notebook ();
513 build_no_control_notebook ();
516 basic_vbox.pack_start (basic_hbox, false, false);
519 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
520 basic_vbox.show_all ();
525 EngineControl::build_full_control_notebook ()
527 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
530 using namespace Notebook_Helpers;
532 vector<string> strings;
533 AttachOptions xopt = AttachOptions (FILL|EXPAND);
534 int row = 1; // row zero == backend combo
536 /* start packing it up */
538 if (backend->requires_driver_selection()) {
539 label = manage (left_aligned_label (_("Driver:")));
540 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
541 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
545 if (backend->use_separate_input_and_output_devices()) {
546 label = manage (left_aligned_label (_("Input Device:")));
547 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
548 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
550 label = manage (left_aligned_label (_("Output Device:")));
551 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
552 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
554 // reset so it isn't used in state comparisons
555 device_combo.set_active_text ("");
557 label = manage (left_aligned_label (_("Device:")));
558 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
559 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
561 // reset these so they don't get used in state comparisons
562 input_device_combo.set_active_text ("");
563 output_device_combo.set_active_text ("");
566 label = manage (left_aligned_label (_("Sample rate:")));
567 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
568 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
572 label = manage (left_aligned_label (_("Buffer size:")));
573 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
574 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
575 buffer_size_duration_label.set_alignment (0.0); /* left-align */
576 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
578 int ctrl_btn_span = 1;
579 if (backend->can_set_period_size ()) {
581 label = manage (left_aligned_label (_("Periods:")));
582 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
583 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
587 /* button spans 2 or 3 rows */
589 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
592 input_channels.set_name ("InputChannels");
593 input_channels.set_flags (Gtk::CAN_FOCUS);
594 input_channels.set_digits (0);
595 input_channels.set_wrap (false);
596 output_channels.set_editable (true);
598 if (!ARDOUR::Profile->get_mixbus()) {
599 label = manage (left_aligned_label (_("Input Channels:")));
600 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
601 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
605 output_channels.set_name ("OutputChannels");
606 output_channels.set_flags (Gtk::CAN_FOCUS);
607 output_channels.set_digits (0);
608 output_channels.set_wrap (false);
609 output_channels.set_editable (true);
611 if (!ARDOUR::Profile->get_mixbus()) {
612 label = manage (left_aligned_label (_("Output Channels:")));
613 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
614 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
618 input_latency.set_name ("InputLatency");
619 input_latency.set_flags (Gtk::CAN_FOCUS);
620 input_latency.set_digits (0);
621 input_latency.set_wrap (false);
622 input_latency.set_editable (true);
624 label = manage (left_aligned_label (_("Hardware input latency:")));
625 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
626 basic_packer.attach (input_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);
631 output_latency.set_name ("OutputLatency");
632 output_latency.set_flags (Gtk::CAN_FOCUS);
633 output_latency.set_digits (0);
634 output_latency.set_wrap (false);
635 output_latency.set_editable (true);
637 label = manage (left_aligned_label (_("Hardware output latency:")));
638 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
639 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
640 label = manage (left_aligned_label (_("samples")));
641 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
643 /* button spans 2 rows */
645 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
648 label = manage (left_aligned_label (_("MIDI System:")));
649 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
650 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
651 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
656 EngineControl::build_no_control_notebook ()
658 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
661 using namespace Notebook_Helpers;
663 vector<string> strings;
664 AttachOptions xopt = AttachOptions (FILL|EXPAND);
665 int row = 1; // row zero == backend combo
666 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
668 label = manage (new Label);
669 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
670 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
673 if (backend->can_change_sample_rate_when_running()) {
674 label = manage (left_aligned_label (_("Sample rate:")));
675 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
676 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
680 if (backend->can_change_buffer_size_when_running()) {
681 label = manage (left_aligned_label (_("Buffer size:")));
682 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
683 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
684 buffer_size_duration_label.set_alignment (0.0); /* left-align */
685 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
689 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
693 EngineControl::~EngineControl ()
695 ignore_changes = true;
699 EngineControl::disable_latency_tab ()
701 vector<string> empty;
702 set_popdown_strings (lm_output_channel_combo, empty);
703 set_popdown_strings (lm_input_channel_combo, empty);
704 lm_measure_button.set_sensitive (false);
705 lm_use_button.set_sensitive (false);
709 EngineControl::enable_latency_tab ()
711 vector<string> outputs;
712 vector<string> inputs;
714 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
715 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
716 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
718 if (!ARDOUR::AudioEngine::instance()->running()) {
719 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
720 notebook.set_current_page (0);
724 else if (inputs.empty() || outputs.empty()) {
725 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
726 notebook.set_current_page (0);
731 lm_back_button_signal.disconnect();
733 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
736 lm_back_button_signal = lm_back_button.signal_clicked().connect(
737 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
741 set_popdown_strings (lm_output_channel_combo, outputs);
742 lm_output_channel_combo.set_active_text (outputs.front());
743 lm_output_channel_combo.set_sensitive (true);
745 set_popdown_strings (lm_input_channel_combo, inputs);
746 lm_input_channel_combo.set_active_text (inputs.front());
747 lm_input_channel_combo.set_sensitive (true);
749 lm_measure_button.set_sensitive (true);
753 EngineControl::setup_midi_tab_for_backend ()
755 string backend = backend_combo.get_active_text ();
757 Gtkmm2ext::container_clear (midi_vbox);
759 midi_vbox.set_border_width (12);
760 midi_device_table.set_border_width (12);
762 if (backend == "JACK") {
763 setup_midi_tab_for_jack ();
766 midi_vbox.pack_start (midi_device_table, true, true);
767 midi_vbox.pack_start (midi_back_button, false, false);
768 midi_vbox.show_all ();
772 EngineControl::update_sensitivity ()
774 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
776 start_stop_button.set_sensitive (false);
781 size_t devices_available = 0;
782 bool engine_running = ARDOUR::AudioEngine::instance()->running();
784 if (backend->use_separate_input_and_output_devices ()) {
785 devices_available += get_popdown_string_count (input_device_combo);
786 devices_available += get_popdown_string_count (output_device_combo);
788 devices_available += get_popdown_string_count (device_combo);
791 if (devices_available == 0) {
793 input_latency.set_sensitive (false);
794 output_latency.set_sensitive (false);
795 input_channels.set_sensitive (false);
796 output_channels.set_sensitive (false);
798 input_latency.set_sensitive (true);
799 output_latency.set_sensitive (true);
800 input_channels.set_sensitive (!engine_running);
801 output_channels.set_sensitive (!engine_running);
804 if (get_popdown_string_count (buffer_size_combo) > 0) {
805 if (!engine_running) {
806 buffer_size_combo.set_sensitive (valid);
807 } else if (backend->can_change_sample_rate_when_running()) {
808 buffer_size_combo.set_sensitive (valid || !_have_control);
812 * Currently there is no way to manually stop the
813 * engine in order to re-configure it.
814 * This needs to remain sensitive for now.
816 * (it's also handy to implicily
817 * re-start the engine)
819 buffer_size_combo.set_sensitive (true);
821 buffer_size_combo.set_sensitive (false);
825 buffer_size_combo.set_sensitive (false);
829 if (get_popdown_string_count (sample_rate_combo) > 0) {
830 bool allow_to_set_rate = false;
831 if (!engine_running) {
832 if (!ARDOUR_UI::instance()->session_loaded) {
833 // engine is not running, no session loaded -> anything goes.
834 allow_to_set_rate = true;
835 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
836 // only allow to change if the current setting is not the native session rate.
837 allow_to_set_rate = true;
840 sample_rate_combo.set_sensitive (allow_to_set_rate);
842 sample_rate_combo.set_sensitive (false);
846 if (get_popdown_string_count (nperiods_combo) > 0) {
847 if (!engine_running) {
848 nperiods_combo.set_sensitive (true);
850 nperiods_combo.set_sensitive (false);
853 nperiods_combo.set_sensitive (false);
857 start_stop_button.set_sensitive(true);
858 start_stop_button.show();
859 if (engine_running) {
860 start_stop_button.set_text("Stop");
861 update_devices_button.set_sensitive(false);
862 use_buffered_io_button.set_sensitive(false);
864 if (backend->can_request_update_devices()) {
865 update_devices_button.show();
867 update_devices_button.hide();
869 if (backend->can_use_buffered_io()) {
870 use_buffered_io_button.show();
872 use_buffered_io_button.hide();
874 start_stop_button.set_text("Start");
875 update_devices_button.set_sensitive(true);
876 use_buffered_io_button.set_sensitive(true);
879 update_devices_button.set_sensitive(false);
880 update_devices_button.hide();
881 use_buffered_io_button.set_sensitive(false);
882 use_buffered_io_button.hide();
883 start_stop_button.set_sensitive(false);
884 start_stop_button.hide();
887 if (engine_running && _have_control) {
888 input_device_combo.set_sensitive (false);
889 output_device_combo.set_sensitive (false);
890 device_combo.set_sensitive (false);
891 driver_combo.set_sensitive (false);
893 input_device_combo.set_sensitive (true);
894 output_device_combo.set_sensitive (true);
895 device_combo.set_sensitive (true);
896 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
897 driver_combo.set_sensitive (true);
899 driver_combo.set_sensitive (false);
903 midi_option_combo.set_sensitive (!engine_running);
907 EngineControl::setup_midi_tab_for_jack ()
912 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
914 device->input_latency = a->get_value();
916 device->output_latency = a->get_value();
921 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
922 b->set_active (!b->get_active());
923 device->enabled = b->get_active();
924 refresh_midi_display(device->name);
928 EngineControl::refresh_midi_display (std::string focus)
930 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
934 AttachOptions xopt = AttachOptions (FILL|EXPAND);
937 Gtkmm2ext::container_clear (midi_device_table);
939 midi_device_table.set_spacings (6);
941 l = manage (new Label);
942 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
943 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
944 l->set_alignment (0.5, 0.5);
948 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
949 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
950 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
951 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
953 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
954 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
955 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
956 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
959 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
964 bool enabled = (*p)->enabled;
966 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
967 m->set_name ("midi device");
968 m->set_can_focus (Gtk::CAN_FOCUS);
969 m->add_events (Gdk::BUTTON_RELEASE_MASK);
970 m->set_active (enabled);
971 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
972 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
973 if ((*p)->name == focus) {
977 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
978 s = manage (new Gtk::SpinButton (*a));
979 a->set_value ((*p)->input_latency);
980 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
981 s->set_sensitive (_can_set_midi_latencies && enabled);
982 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
984 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
985 s = manage (new Gtk::SpinButton (*a));
986 a->set_value ((*p)->output_latency);
987 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
988 s->set_sensitive (_can_set_midi_latencies && enabled);
989 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
991 b = manage (new Button (_("Calibrate")));
992 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
993 b->set_sensitive (_can_set_midi_latencies && enabled);
994 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1001 EngineControl::backend_changed ()
1003 SignalBlocker blocker (*this, "backend_changed");
1004 string backend_name = backend_combo.get_active_text();
1005 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1007 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1008 /* eh? setting the backend failed... how ? */
1009 /* A: stale config contains a backend that does not exist in current build */
1013 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1015 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1018 setup_midi_tab_for_backend ();
1019 _midi_devices.clear();
1021 if (backend->requires_driver_selection()) {
1022 if (set_driver_popdown_strings ()) {
1026 /* this will change the device text which will cause a call to
1027 * device changed which will set up parameters
1032 update_midi_options ();
1034 connect_disconnect_button.hide();
1036 midi_option_changed();
1038 started_at_least_once = false;
1040 /* changing the backend implies stopping the engine
1041 * ARDOUR::AudioEngine() may or may not emit this signal
1042 * depending on previous engine state
1044 engine_stopped (); // set "active/inactive"
1046 if (!_have_control) {
1047 // set settings from backend that we do have control over
1048 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1051 if (_have_control && !ignore_changes) {
1052 // set driver & devices
1053 State state = get_matching_state (backend_combo.get_active_text());
1055 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1056 set_current_state (state);
1060 if (!ignore_changes) {
1061 maybe_display_saved_state ();
1066 EngineControl::update_midi_options ()
1068 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1069 vector<string> midi_options = backend->enumerate_midi_options();
1071 if (midi_options.size() == 1) {
1072 /* only contains the "none" option */
1073 midi_option_combo.set_sensitive (false);
1075 if (_have_control) {
1076 set_popdown_strings (midi_option_combo, midi_options);
1077 midi_option_combo.set_active_text (midi_options.front());
1078 midi_option_combo.set_sensitive (true);
1080 midi_option_combo.set_sensitive (false);
1086 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1088 if (ARDOUR::Profile->get_mixbus()) {
1092 uint32_t cnt = (uint32_t) sb->get_value();
1094 sb->set_text (_("all available channels"));
1097 snprintf (buf, sizeof (buf), "%d", cnt);
1103 // @return true if there are drivers available
1105 EngineControl::set_driver_popdown_strings ()
1107 DEBUG_ECONTROL ("set_driver_popdown_strings");
1108 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1109 vector<string> drivers = backend->enumerate_drivers();
1111 if (drivers.empty ()) {
1112 // This is an error...?
1116 string current_driver = backend->driver_name ();
1118 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1120 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1123 current_driver = drivers.front ();
1126 set_popdown_strings (driver_combo, drivers);
1128 string_compose ("driver_combo.set_active_text: %1", current_driver));
1129 driver_combo.set_active_text (current_driver);
1134 EngineControl::get_default_device(const string& current_device_name,
1135 const vector<string>& available_devices)
1137 // If the current device is available, use it as default
1138 if (std::find (available_devices.begin (),
1139 available_devices.end (),
1140 current_device_name) != available_devices.end ()) {
1142 return current_device_name;
1145 using namespace ARDOUR;
1147 string default_device_name =
1148 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1150 vector<string>::const_iterator i;
1152 // If there is a "Default" device available, use it
1153 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1154 if (*i == default_device_name) {
1159 string none_device_name =
1160 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1162 // Use the first device that isn't "None"
1163 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1164 if (*i != none_device_name) {
1169 // Use "None" if there are no other available
1170 return available_devices.front();
1173 // @return true if there are devices available
1175 EngineControl::set_device_popdown_strings ()
1177 DEBUG_ECONTROL ("set_device_popdown_strings");
1178 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1179 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1181 /* NOTE: Ardour currently does not display the "available" field of the
1184 * Doing so would require a different GUI widget than the combo
1185 * box/popdown that we currently use, since it has no way to list
1186 * items that are not selectable. Something more like a popup menu,
1187 * which could have unselectable items, would be appropriate.
1190 vector<string> available_devices;
1192 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1193 available_devices.push_back (i->name);
1196 if (available_devices.empty ()) {
1200 set_popdown_strings (device_combo, available_devices);
1202 std::string default_device =
1203 get_default_device(backend->device_name(), available_devices);
1206 string_compose ("set device_combo active text: %1", default_device));
1208 device_combo.set_active_text(default_device);
1212 // @return true if there are input devices available
1214 EngineControl::set_input_device_popdown_strings ()
1216 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1217 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1218 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1220 vector<string> available_devices;
1222 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1223 available_devices.push_back (i->name);
1226 if (available_devices.empty()) {
1230 set_popdown_strings (input_device_combo, available_devices);
1232 std::string default_device =
1233 get_default_device(backend->input_device_name(), available_devices);
1236 string_compose ("set input_device_combo active text: %1", default_device));
1237 input_device_combo.set_active_text(default_device);
1241 // @return true if there are output devices available
1243 EngineControl::set_output_device_popdown_strings ()
1245 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1246 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1247 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1249 vector<string> available_devices;
1251 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1252 available_devices.push_back (i->name);
1255 if (available_devices.empty()) {
1259 set_popdown_strings (output_device_combo, available_devices);
1261 std::string default_device =
1262 get_default_device(backend->output_device_name(), available_devices);
1265 string_compose ("set output_device_combo active text: %1", default_device));
1266 output_device_combo.set_active_text(default_device);
1271 EngineControl::list_devices ()
1273 DEBUG_ECONTROL ("list_devices");
1274 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1277 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1279 bool devices_available = false;
1281 if (backend->use_separate_input_and_output_devices ()) {
1282 bool input_devices_available = set_input_device_popdown_strings ();
1283 bool output_devices_available = set_output_device_popdown_strings ();
1284 devices_available = input_devices_available || output_devices_available;
1286 devices_available = set_device_popdown_strings ();
1289 if (devices_available) {
1292 device_combo.clear();
1293 input_device_combo.clear();
1294 output_device_combo.clear();
1296 update_sensitivity ();
1300 EngineControl::driver_changed ()
1302 SignalBlocker blocker (*this, "driver_changed");
1303 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1306 backend->set_driver (driver_combo.get_active_text());
1309 // TODO load LRU device(s) for backend + driver combo
1311 if (!ignore_changes) {
1312 maybe_display_saved_state ();
1317 EngineControl::get_sample_rates_for_all_devices ()
1319 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1320 ARDOUR::AudioEngine::instance ()->current_backend ();
1321 vector<float> all_rates;
1323 if (backend->use_separate_input_and_output_devices ()) {
1324 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1326 all_rates = backend->available_sample_rates (get_device_name ());
1332 EngineControl::get_default_sample_rates ()
1334 vector<float> rates;
1335 rates.push_back (8000.0f);
1336 rates.push_back (16000.0f);
1337 rates.push_back (32000.0f);
1338 rates.push_back (44100.0f);
1339 rates.push_back (48000.0f);
1340 rates.push_back (88200.0f);
1341 rates.push_back (96000.0f);
1342 rates.push_back (192000.0f);
1343 rates.push_back (384000.0f);
1348 EngineControl::set_samplerate_popdown_strings ()
1350 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1351 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1356 if (_have_control) {
1357 sr = get_sample_rates_for_all_devices ();
1359 sr = get_default_sample_rates ();
1362 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1363 s.push_back (rate_as_string (*x));
1364 if (*x == _desired_sample_rate) {
1369 set_popdown_strings (sample_rate_combo, s);
1372 if (ARDOUR::AudioEngine::instance()->running()) {
1373 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1375 else if (desired.empty ()) {
1376 float new_active_sr = backend->default_sample_rate ();
1378 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1379 new_active_sr = sr.front ();
1382 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1384 sample_rate_combo.set_active_text (desired);
1388 update_sensitivity ();
1392 EngineControl::get_buffer_sizes_for_all_devices ()
1394 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1395 ARDOUR::AudioEngine::instance ()->current_backend ();
1396 vector<uint32_t> all_sizes;
1398 if (backend->use_separate_input_and_output_devices ()) {
1399 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1401 all_sizes = backend->available_buffer_sizes (get_device_name ());
1407 EngineControl::get_default_buffer_sizes ()
1409 vector<uint32_t> sizes;
1410 sizes.push_back (8);
1411 sizes.push_back (16);
1412 sizes.push_back (32);
1413 sizes.push_back (64);
1414 sizes.push_back (128);
1415 sizes.push_back (256);
1416 sizes.push_back (512);
1417 sizes.push_back (1024);
1418 sizes.push_back (2048);
1419 sizes.push_back (4096);
1420 sizes.push_back (8192);
1425 EngineControl::set_buffersize_popdown_strings ()
1427 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1428 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1429 vector<uint32_t> bs;
1432 if (_have_control) {
1433 bs = get_buffer_sizes_for_all_devices ();
1434 } else if (backend->can_change_buffer_size_when_running()) {
1435 bs = get_default_buffer_sizes ();
1438 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1439 s.push_back (bufsize_as_string (*x));
1442 uint32_t previous_size = 0;
1443 if (!buffer_size_combo.get_active_text().empty()) {
1444 previous_size = get_buffer_size ();
1447 set_popdown_strings (buffer_size_combo, s);
1451 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1452 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1455 buffer_size_combo.set_active_text(s.front());
1457 uint32_t period = backend->buffer_size();
1458 if (0 == period && backend->use_separate_input_and_output_devices()) {
1459 period = backend->default_buffer_size(get_input_device_name());
1461 if (0 == period && backend->use_separate_input_and_output_devices()) {
1462 period = backend->default_buffer_size(get_output_device_name());
1464 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1465 period = backend->default_buffer_size(get_device_name());
1468 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1470 show_buffer_duration ();
1472 update_sensitivity ();
1476 EngineControl::set_nperiods_popdown_strings ()
1478 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1479 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1480 vector<uint32_t> np;
1483 if (backend->can_set_period_size()) {
1484 np = backend->available_period_sizes (get_driver());
1487 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1488 s.push_back (nperiods_as_string (*x));
1491 set_popdown_strings (nperiods_combo, s);
1494 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1497 update_sensitivity ();
1501 EngineControl::device_changed ()
1503 SignalBlocker blocker (*this, "device_changed");
1504 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1507 string device_name_in;
1508 string device_name_out; // only used if backend support separate I/O devices
1510 if (backend->use_separate_input_and_output_devices()) {
1511 device_name_in = get_input_device_name ();
1512 device_name_out = get_output_device_name ();
1514 device_name_in = get_device_name ();
1517 /* we set the backend-device to query various device related intormation.
1518 * This has the side effect that backend->device_name() will match
1519 * the device_name and 'change_device' will never be true.
1520 * so work around this by setting...
1522 if (backend->use_separate_input_and_output_devices()) {
1523 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1524 queue_device_changed = true;
1527 if (device_name_in != backend->device_name()) {
1528 queue_device_changed = true;
1532 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1533 if (backend->use_separate_input_and_output_devices()) {
1534 backend->set_input_device_name (device_name_in);
1535 backend->set_output_device_name (device_name_out);
1537 backend->set_device_name(device_name_in);
1541 /* don't allow programmatic change to combos to cause a
1542 recursive call to this method.
1544 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1546 set_samplerate_popdown_strings ();
1547 set_buffersize_popdown_strings ();
1548 set_nperiods_popdown_strings ();
1550 /* TODO set min + max channel counts here */
1552 manage_control_app_sensitivity ();
1555 /* pick up any saved state for this device */
1557 if (!ignore_changes) {
1558 maybe_display_saved_state ();
1563 EngineControl::input_device_changed ()
1565 DEBUG_ECONTROL ("input_device_changed");
1567 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1568 if (backend && backend->match_input_output_devices_or_none ()) {
1569 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1571 if (get_output_device_name () != dev_none
1572 && get_input_device_name () != dev_none
1573 && get_input_device_name () != get_output_device_name ()) {
1574 block_changed_signals ();
1575 if (contains_value (output_device_combo, get_input_device_name ())) {
1576 output_device_combo.set_active_text (get_input_device_name ());
1578 assert (contains_value (output_device_combo, dev_none));
1579 output_device_combo.set_active_text (dev_none);
1581 unblock_changed_signals ();
1588 EngineControl::output_device_changed ()
1590 DEBUG_ECONTROL ("output_device_changed");
1591 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1592 if (backend && backend->match_input_output_devices_or_none ()) {
1593 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1595 if (get_input_device_name () != dev_none
1596 && get_input_device_name () != dev_none
1597 && get_input_device_name () != get_output_device_name ()) {
1598 block_changed_signals ();
1599 if (contains_value (input_device_combo, get_output_device_name ())) {
1600 input_device_combo.set_active_text (get_output_device_name ());
1602 assert (contains_value (input_device_combo, dev_none));
1603 input_device_combo.set_active_text (dev_none);
1605 unblock_changed_signals ();
1612 EngineControl::bufsize_as_string (uint32_t sz)
1614 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1618 EngineControl::nperiods_as_string (uint32_t np)
1621 snprintf (buf, sizeof (buf), "%u", np);
1627 EngineControl::sample_rate_changed ()
1629 DEBUG_ECONTROL ("sample_rate_changed");
1630 /* reset the strings for buffer size to show the correct msec value
1631 (reflecting the new sample rate).
1634 show_buffer_duration ();
1639 EngineControl::buffer_size_changed ()
1641 DEBUG_ECONTROL ("buffer_size_changed");
1642 show_buffer_duration ();
1646 EngineControl::nperiods_changed ()
1648 DEBUG_ECONTROL ("nperiods_changed");
1649 show_buffer_duration ();
1653 EngineControl::show_buffer_duration ()
1655 DEBUG_ECONTROL ("show_buffer_duration");
1656 /* buffer sizes - convert from just samples to samples + msecs for
1657 * the displayed string
1660 string bs_text = buffer_size_combo.get_active_text ();
1661 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1662 uint32_t rate = get_rate();
1664 /* Except for ALSA and Dummy backends, we don't know the number of periods
1665 * per cycle and settings.
1667 * jack1 vs jack2 have different default latencies since jack2 start
1668 * in async-mode unless --sync is given which adds an extra cycle
1669 * of latency. The value is not known if jackd is started externally..
1671 * So just display the period size, that's also what
1672 * ARDOUR_UI::update_sample_rate() does for the status bar.
1673 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1674 * but still, that's the buffer period, not [round-trip] latency)
1677 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1678 buffer_size_duration_label.set_text (buf);
1682 EngineControl::midi_option_changed ()
1684 DEBUG_ECONTROL ("midi_option_changed");
1685 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1688 backend->set_midi_option (get_midi_option());
1690 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1692 //_midi_devices.clear(); // TODO merge with state-saved settings..
1693 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1694 std::vector<MidiDeviceSettings> new_devices;
1696 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1697 MidiDeviceSettings mds = find_midi_device (i->name);
1698 if (i->available && !mds) {
1699 uint32_t input_latency = 0;
1700 uint32_t output_latency = 0;
1701 if (_can_set_midi_latencies) {
1702 input_latency = backend->systemic_midi_input_latency (i->name);
1703 output_latency = backend->systemic_midi_output_latency (i->name);
1705 bool enabled = backend->midi_device_enabled (i->name);
1706 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1707 new_devices.push_back (ptr);
1708 } else if (i->available) {
1709 new_devices.push_back (mds);
1712 _midi_devices = new_devices;
1714 if (_midi_devices.empty()) {
1715 midi_devices_button.hide ();
1717 midi_devices_button.show ();
1722 EngineControl::parameter_changed ()
1726 EngineControl::State
1727 EngineControl::get_matching_state (const string& backend)
1729 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1730 if ((*i)->backend == backend) {
1737 EngineControl::State
1738 EngineControl::get_matching_state (
1739 const string& backend,
1740 const string& driver,
1741 const string& device)
1743 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1744 if ((*i)->backend == backend &&
1745 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1753 EngineControl::State
1754 EngineControl::get_matching_state (
1755 const string& backend,
1756 const string& driver,
1757 const string& input_device,
1758 const string& output_device)
1760 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1761 if ((*i)->backend == backend &&
1762 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1770 EngineControl::State
1771 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1773 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1776 if (backend->use_separate_input_and_output_devices ()) {
1777 return get_matching_state (backend_combo.get_active_text(),
1778 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1779 input_device_combo.get_active_text(),
1780 output_device_combo.get_active_text());
1782 return get_matching_state (backend_combo.get_active_text(),
1783 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1784 device_combo.get_active_text());
1788 return get_matching_state (backend_combo.get_active_text(),
1790 device_combo.get_active_text());
1793 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1794 const EngineControl::State& state2)
1796 if (state1->backend == state2->backend &&
1797 state1->driver == state2->driver &&
1798 state1->device == state2->device &&
1799 state1->input_device == state2->input_device &&
1800 state1->output_device == state2->output_device) {
1807 EngineControl::state_sort_cmp (const State &a, const State &b) {
1811 else if (b->active) {
1815 return a->lru < b->lru;
1819 EngineControl::State
1820 EngineControl::save_state ()
1824 if (!_have_control) {
1825 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1827 state->lru = time (NULL) ;
1830 state.reset(new StateStruct);
1831 state->backend = get_backend ();
1833 state.reset(new StateStruct);
1834 store_state (state);
1837 for (StateList::iterator i = states.begin(); i != states.end();) {
1838 if (equivalent_states (*i, state)) {
1839 i = states.erase(i);
1845 states.push_back (state);
1847 states.sort (state_sort_cmp);
1853 EngineControl::store_state (State state)
1855 state->backend = get_backend ();
1856 state->driver = get_driver ();
1857 state->device = get_device_name ();
1858 state->input_device = get_input_device_name ();
1859 state->output_device = get_output_device_name ();
1860 state->sample_rate = get_rate ();
1861 state->buffer_size = get_buffer_size ();
1862 state->n_periods = get_nperiods ();
1863 state->input_latency = get_input_latency ();
1864 state->output_latency = get_output_latency ();
1865 state->input_channels = get_input_channels ();
1866 state->output_channels = get_output_channels ();
1867 state->midi_option = get_midi_option ();
1868 state->midi_devices = _midi_devices;
1869 state->use_buffered_io = get_use_buffered_io ();
1870 state->lru = time (NULL) ;
1874 EngineControl::maybe_display_saved_state ()
1876 if (!_have_control) {
1880 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1883 DEBUG_ECONTROL ("Restoring saved state");
1884 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1886 if (!_desired_sample_rate) {
1887 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1889 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1891 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1892 /* call this explicitly because we're ignoring changes to
1893 the controls at this point.
1895 show_buffer_duration ();
1896 input_latency.set_value (state->input_latency);
1897 output_latency.set_value (state->output_latency);
1899 use_buffered_io_button.set_active (state->use_buffered_io);
1901 if (!state->midi_option.empty()) {
1902 midi_option_combo.set_active_text (state->midi_option);
1903 _midi_devices = state->midi_devices;
1906 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1911 EngineControl::get_state ()
1915 XMLNode* root = new XMLNode ("AudioMIDISetup");
1918 if (!states.empty()) {
1919 XMLNode* state_nodes = new XMLNode ("EngineStates");
1921 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1923 XMLNode* node = new XMLNode ("State");
1925 node->add_property ("backend", (*i)->backend);
1926 node->add_property ("driver", (*i)->driver);
1927 node->add_property ("device", (*i)->device);
1928 node->add_property ("input-device", (*i)->input_device);
1929 node->add_property ("output-device", (*i)->output_device);
1930 node->add_property ("sample-rate", (*i)->sample_rate);
1931 node->add_property ("buffer-size", (*i)->buffer_size);
1932 node->add_property ("n-periods", (*i)->n_periods);
1933 node->add_property ("input-latency", (*i)->input_latency);
1934 node->add_property ("output-latency", (*i)->output_latency);
1935 node->add_property ("input-channels", (*i)->input_channels);
1936 node->add_property ("output-channels", (*i)->output_channels);
1937 node->add_property ("active", (*i)->active ? "yes" : "no");
1938 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1939 node->add_property ("midi-option", (*i)->midi_option);
1940 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1942 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1943 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1944 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1945 midi_device_stuff->add_property (X_("name"), (*p)->name);
1946 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1947 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1948 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1949 midi_devices->add_child_nocopy (*midi_device_stuff);
1951 node->add_child_nocopy (*midi_devices);
1953 state_nodes->add_child_nocopy (*node);
1956 root->add_child_nocopy (*state_nodes);
1963 EngineControl::set_default_state ()
1965 vector<string> backend_names;
1966 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1968 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1969 backend_names.push_back ((*b)->name);
1971 backend_combo.set_active_text (backend_names.front());
1973 // We could set default backends per platform etc here
1979 EngineControl::set_state (const XMLNode& root)
1981 XMLNodeList clist, cclist;
1982 XMLNodeConstIterator citer, cciter;
1983 XMLNode const * child;
1984 XMLNode const * grandchild;
1985 XMLProperty const * prop = NULL;
1987 if (root.name() != "AudioMIDISetup") {
1991 clist = root.children();
1995 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1999 if (child->name() != "EngineStates") {
2003 cclist = child->children();
2005 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2006 State state (new StateStruct);
2008 grandchild = *cciter;
2010 if (grandchild->name() != "State") {
2014 if ((prop = grandchild->property ("backend")) == 0) {
2017 state->backend = prop->value ();
2019 if ((prop = grandchild->property ("driver")) == 0) {
2022 state->driver = prop->value ();
2024 if ((prop = grandchild->property ("device")) == 0) {
2027 state->device = prop->value ();
2029 if ((prop = grandchild->property ("input-device")) == 0) {
2032 state->input_device = prop->value ();
2034 if ((prop = grandchild->property ("output-device")) == 0) {
2037 state->output_device = prop->value ();
2039 if ((prop = grandchild->property ("sample-rate")) == 0) {
2042 state->sample_rate = atof (prop->value ());
2044 if ((prop = grandchild->property ("buffer-size")) == 0) {
2047 state->buffer_size = atoi (prop->value ());
2049 if ((prop = grandchild->property ("n-periods")) == 0) {
2050 // optional (new value in 4.5)
2051 state->n_periods = 0;
2053 state->n_periods = atoi (prop->value ());
2056 if ((prop = grandchild->property ("input-latency")) == 0) {
2059 state->input_latency = atoi (prop->value ());
2061 if ((prop = grandchild->property ("output-latency")) == 0) {
2064 state->output_latency = atoi (prop->value ());
2066 if ((prop = grandchild->property ("input-channels")) == 0) {
2069 state->input_channels = atoi (prop->value ());
2071 if ((prop = grandchild->property ("output-channels")) == 0) {
2074 state->output_channels = atoi (prop->value ());
2076 if ((prop = grandchild->property ("active")) == 0) {
2079 state->active = string_is_affirmative (prop->value ());
2081 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2084 state->use_buffered_io = string_is_affirmative (prop->value ());
2086 if ((prop = grandchild->property ("midi-option")) == 0) {
2089 state->midi_option = prop->value ();
2091 state->midi_devices.clear();
2093 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2094 const XMLNodeList mnc = midinode->children();
2095 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2096 if ((*n)->property (X_("name")) == 0
2097 || (*n)->property (X_("enabled")) == 0
2098 || (*n)->property (X_("input-latency")) == 0
2099 || (*n)->property (X_("output-latency")) == 0
2104 MidiDeviceSettings ptr (new MidiDeviceSetting(
2105 (*n)->property (X_("name"))->value (),
2106 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2107 atoi ((*n)->property (X_("input-latency"))->value ()),
2108 atoi ((*n)->property (X_("output-latency"))->value ())
2110 state->midi_devices.push_back (ptr);
2114 if ((prop = grandchild->property ("lru"))) {
2115 state->lru = atoi (prop->value ());
2119 /* remove accumulated duplicates (due to bug in ealier version)
2120 * this can be removed again before release
2122 for (StateList::iterator i = states.begin(); i != states.end();) {
2123 if ((*i)->backend == state->backend &&
2124 (*i)->driver == state->driver &&
2125 (*i)->device == state->device) {
2126 i = states.erase(i);
2133 states.push_back (state);
2137 /* now see if there was an active state and switch the setup to it */
2139 // purge states of backend that are not available in this built
2140 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2141 vector<std::string> backend_names;
2143 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2144 backend_names.push_back((*i)->name);
2146 for (StateList::iterator i = states.begin(); i != states.end();) {
2147 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2148 i = states.erase(i);
2154 states.sort (state_sort_cmp);
2156 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2159 return set_current_state (*i);
2166 EngineControl::set_current_state (const State& state)
2168 DEBUG_ECONTROL ("set_current_state");
2170 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2172 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2173 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2174 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2175 // this shouldn't happen as the invalid backend names should have been
2176 // removed from the list of states.
2180 // now reflect the change in the backend in the GUI so backend_changed will
2181 // do the right thing
2182 backend_combo.set_active_text (state->backend);
2184 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2186 // we don't have control don't restore state
2191 if (!state->driver.empty ()) {
2192 if (!backend->requires_driver_selection ()) {
2193 DEBUG_ECONTROL ("Backend should require driver selection");
2194 // A backend has changed from having driver selection to not having
2195 // it or someone has been manually editing a config file and messed
2200 if (backend->set_driver (state->driver) != 0) {
2201 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2202 // Driver names for a backend have changed and the name in the
2203 // config file is now invalid or support for driver is no longer
2204 // included in the backend
2207 // no need to set the driver_combo as backend_changed will use
2208 // backend->driver_name to set the active driver
2211 if (!state->device.empty ()) {
2212 if (backend->set_device_name (state->device) != 0) {
2214 string_compose ("Unable to set device name %1", state->device));
2215 // device is no longer available on the system
2218 // no need to set active device as it will be picked up in
2219 // via backend_changed ()/set_device_popdown_strings
2222 // backend supports separate input/output devices
2223 if (backend->set_input_device_name (state->input_device) != 0) {
2224 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2225 state->input_device));
2226 // input device is no longer available on the system
2230 if (backend->set_output_device_name (state->output_device) != 0) {
2231 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2232 state->input_device));
2233 // output device is no longer available on the system
2236 // no need to set active devices as it will be picked up in via
2237 // backend_changed ()/set_*_device_popdown_strings
2242 // Now restore the state of the rest of the controls
2244 // We don't use a SignalBlocker as set_current_state is currently only
2245 // called from set_state before any signals are connected. If at some point
2246 // a more general named state mechanism is implemented and
2247 // set_current_state is called while signals are connected then a
2248 // SignalBlocker will need to be instantiated before setting these.
2250 device_combo.set_active_text (state->device);
2251 input_device_combo.set_active_text (state->input_device);
2252 output_device_combo.set_active_text (state->output_device);
2253 if (!_desired_sample_rate) {
2254 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2256 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2257 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2258 input_latency.set_value (state->input_latency);
2259 output_latency.set_value (state->output_latency);
2260 midi_option_combo.set_active_text (state->midi_option);
2261 use_buffered_io_button.set_active (state->use_buffered_io);
2266 EngineControl::push_state_to_backend (bool start)
2268 DEBUG_ECONTROL ("push_state_to_backend");
2269 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2270 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2276 /* figure out what is going to change */
2278 bool restart_required = false;
2279 bool was_running = ARDOUR::AudioEngine::instance()->running();
2280 bool change_driver = false;
2281 bool change_device = false;
2282 bool change_rate = false;
2283 bool change_bufsize = false;
2284 bool change_nperiods = false;
2285 bool change_latency = false;
2286 bool change_channels = false;
2287 bool change_midi = false;
2288 bool change_buffered_io = false;
2290 uint32_t ochan = get_output_channels ();
2291 uint32_t ichan = get_input_channels ();
2293 if (_have_control) {
2295 if (started_at_least_once) {
2297 /* we can control the backend */
2299 if (backend->requires_driver_selection()) {
2300 if (get_driver() != backend->driver_name()) {
2301 change_driver = true;
2305 if (backend->use_separate_input_and_output_devices()) {
2306 if (get_input_device_name() != backend->input_device_name()) {
2307 change_device = true;
2309 if (get_output_device_name() != backend->output_device_name()) {
2310 change_device = true;
2313 if (get_device_name() != backend->device_name()) {
2314 change_device = true;
2318 if (queue_device_changed) {
2319 change_device = true;
2322 if (get_rate() != backend->sample_rate()) {
2326 if (get_buffer_size() != backend->buffer_size()) {
2327 change_bufsize = true;
2330 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2331 && get_nperiods() != backend->period_size()) {
2332 change_nperiods = true;
2335 if (get_midi_option() != backend->midi_option()) {
2339 if (backend->can_use_buffered_io()) {
2340 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2341 change_buffered_io = true;
2345 /* zero-requested channels means "all available" */
2348 ichan = backend->input_channels();
2352 ochan = backend->output_channels();
2355 if (ichan != backend->input_channels()) {
2356 change_channels = true;
2359 if (ochan != backend->output_channels()) {
2360 change_channels = true;
2363 if (get_input_latency() != backend->systemic_input_latency() ||
2364 get_output_latency() != backend->systemic_output_latency()) {
2365 change_latency = true;
2368 /* backend never started, so we have to force a group
2371 change_device = true;
2372 if (backend->requires_driver_selection()) {
2373 change_driver = true;
2376 change_bufsize = true;
2377 change_channels = true;
2378 change_latency = true;
2380 change_buffered_io = backend->can_use_buffered_io();
2381 change_channels = true;
2382 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2387 /* we have no control over the backend, meaning that we can
2388 * only possibly change sample rate and buffer size.
2392 if (get_rate() != backend->sample_rate()) {
2393 change_bufsize = true;
2396 if (get_buffer_size() != backend->buffer_size()) {
2397 change_bufsize = true;
2401 queue_device_changed = false;
2403 if (!_have_control) {
2405 /* We do not have control over the backend, so the best we can
2406 * do is try to change the sample rate and/or bufsize and get
2410 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2414 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2419 backend->set_sample_rate (get_rate());
2422 if (change_bufsize) {
2423 backend->set_buffer_size (get_buffer_size());
2427 if (ARDOUR::AudioEngine::instance()->start ()) {
2428 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2438 /* determine if we need to stop the backend before changing parameters */
2440 if (change_driver || change_device || change_channels || change_nperiods ||
2441 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2442 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2443 change_midi || change_buffered_io ||
2444 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2445 restart_required = true;
2447 restart_required = false;
2452 if (restart_required) {
2453 if (ARDOUR::AudioEngine::instance()->stop()) {
2459 if (change_driver && backend->set_driver (get_driver())) {
2460 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2463 if (backend->use_separate_input_and_output_devices()) {
2464 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2465 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2468 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2469 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2473 if (change_device && backend->set_device_name (get_device_name())) {
2474 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2478 if (change_rate && backend->set_sample_rate (get_rate())) {
2479 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2482 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2483 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2486 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2487 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2491 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2492 if (backend->set_input_channels (get_input_channels())) {
2493 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2496 if (backend->set_output_channels (get_output_channels())) {
2497 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2501 if (change_latency) {
2502 if (backend->set_systemic_input_latency (get_input_latency())) {
2503 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2506 if (backend->set_systemic_output_latency (get_output_latency())) {
2507 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2513 backend->set_midi_option (get_midi_option());
2516 if (change_buffered_io) {
2517 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2521 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2522 if (_measure_midi) {
2523 if (*p == _measure_midi) {
2524 backend->set_midi_device_enabled ((*p)->name, true);
2526 backend->set_midi_device_enabled ((*p)->name, false);
2528 if (backend->can_change_systemic_latency_when_running ()) {
2529 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2530 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2534 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2535 if (backend->can_set_systemic_midi_latencies()) {
2536 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2537 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2542 if (start || (was_running && restart_required)) {
2543 if (ARDOUR::AudioEngine::instance()->start()) {
2554 EngineControl::post_push ()
2556 /* get a pointer to the current state object, creating one if
2560 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2563 state = save_state ();
2569 states.sort (state_sort_cmp);
2573 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2574 (*i)->active = false;
2577 /* mark this one active (to be used next time the dialog is
2581 state->active = true;
2583 if (_have_control) { // XXX
2584 manage_control_app_sensitivity ();
2587 /* schedule a redisplay of MIDI ports */
2588 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2593 EngineControl::get_rate () const
2595 float r = atof (sample_rate_combo.get_active_text ());
2596 /* the string may have been translated with an abbreviation for
2597 * thousands, so use a crude heuristic to fix this.
2607 EngineControl::get_buffer_size () const
2609 string txt = buffer_size_combo.get_active_text ();
2612 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2613 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2614 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2622 EngineControl::get_nperiods () const
2624 string txt = nperiods_combo.get_active_text ();
2625 return atoi (txt.c_str());
2629 EngineControl::get_midi_option () const
2631 return midi_option_combo.get_active_text();
2635 EngineControl::get_use_buffered_io () const
2637 return use_buffered_io_button.get_active();
2641 EngineControl::get_input_channels() const
2643 if (ARDOUR::Profile->get_mixbus()) {
2644 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2645 if (!backend) return 0;
2646 return backend->input_channels();
2648 return (uint32_t) input_channels_adjustment.get_value();
2652 EngineControl::get_output_channels() const
2654 if (ARDOUR::Profile->get_mixbus()) {
2655 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2656 if (!backend) return 0;
2657 return backend->input_channels();
2659 return (uint32_t) output_channels_adjustment.get_value();
2663 EngineControl::get_input_latency() const
2665 return (uint32_t) input_latency_adjustment.get_value();
2669 EngineControl::get_output_latency() const
2671 return (uint32_t) output_latency_adjustment.get_value();
2675 EngineControl::get_backend () const
2677 return backend_combo.get_active_text ();
2681 EngineControl::get_driver () const
2683 if (driver_combo.get_parent()) {
2684 return driver_combo.get_active_text ();
2691 EngineControl::get_device_name () const
2693 return device_combo.get_active_text ();
2697 EngineControl::get_input_device_name () const
2699 return input_device_combo.get_active_text ();
2703 EngineControl::get_output_device_name () const
2705 return output_device_combo.get_active_text ();
2709 EngineControl::control_app_button_clicked ()
2711 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2717 backend->launch_control_app ();
2721 EngineControl::start_stop_button_clicked ()
2723 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2729 if (ARDOUR::AudioEngine::instance()->running()) {
2730 ARDOUR::AudioEngine::instance()->stop ();
2732 if (!ARDOUR_UI::instance()->session_loaded) {
2736 if (!ARDOUR_UI::instance()->session_loaded) {
2737 ArdourDialog::on_response (RESPONSE_OK);
2738 if (Splash::instance()) {
2739 Splash::instance()->pop_front ();
2746 EngineControl::update_devices_button_clicked ()
2748 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2754 if (backend->update_devices()) {
2755 device_list_changed ();
2760 EngineControl::use_buffered_io_button_clicked ()
2762 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2768 bool set_buffered_io = !use_buffered_io_button.get_active();
2769 use_buffered_io_button.set_active (set_buffered_io);
2770 backend->set_use_buffered_io (set_buffered_io);
2774 EngineControl::manage_control_app_sensitivity ()
2776 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2782 string appname = backend->control_app_name();
2784 if (appname.empty()) {
2785 control_app_button.set_sensitive (false);
2787 control_app_button.set_sensitive (true);
2792 EngineControl::set_desired_sample_rate (uint32_t sr)
2794 _desired_sample_rate = sr;
2795 if (ARDOUR::AudioEngine::instance ()->running ()
2796 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2803 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2805 if (page_num == 0) {
2806 _measure_midi.reset();
2807 update_sensitivity ();
2810 if (page_num == midi_tab) {
2812 refresh_midi_display ();
2815 if (page_num == latency_tab) {
2818 if (ARDOUR::AudioEngine::instance()->running()) {
2823 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2825 /* save any existing latency values */
2827 uint32_t il = (uint32_t) input_latency.get_value ();
2828 uint32_t ol = (uint32_t) input_latency.get_value ();
2830 /* reset to zero so that our new test instance
2831 will be clean of any existing latency measures.
2833 NB. this should really be done by the backend
2834 when stated for latency measurement.
2837 input_latency.set_value (0);
2838 output_latency.set_value (0);
2840 push_state_to_backend (false);
2844 input_latency.set_value (il);
2845 output_latency.set_value (ol);
2848 // This should be done in push_state_to_backend()
2849 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2850 disable_latency_tab ();
2853 enable_latency_tab ();
2857 end_latency_detection ();
2858 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2863 /* latency measurement */
2866 EngineControl::check_audio_latency_measurement ()
2868 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2870 if (mtdm->resolve () < 0) {
2871 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2875 if (mtdm->get_peak () > 0.707f) {
2876 // get_peak() resets the peak-hold in the detector.
2877 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2878 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2882 if (mtdm->err () > 0.3) {
2888 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2890 if (sample_rate == 0) {
2891 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2892 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2896 int frames_total = mtdm->del();
2897 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2899 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2900 _("Detected roundtrip latency: "),
2901 frames_total, frames_total * 1000.0f/sample_rate,
2902 _("Systemic latency: "),
2903 extra, extra * 1000.0f/sample_rate);
2907 if (mtdm->err () > 0.2) {
2909 strcat (buf, _("(signal detection error)"));
2915 strcat (buf, _("(inverted - bad wiring)"));
2919 lm_results.set_markup (string_compose (results_markup, buf));
2922 have_lm_results = true;
2923 end_latency_detection ();
2924 lm_use_button.set_sensitive (true);
2932 EngineControl::check_midi_latency_measurement ()
2934 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2936 if (!mididm->have_signal () || mididm->latency () == 0) {
2937 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2942 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2944 if (sample_rate == 0) {
2945 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2946 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2950 ARDOUR::framecnt_t frames_total = mididm->latency();
2951 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2952 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2953 _("Detected roundtrip latency: "),
2954 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2955 _("Systemic latency: "),
2956 extra, extra * 1000.0f / sample_rate);
2960 if (!mididm->ok ()) {
2962 strcat (buf, _("(averaging)"));
2966 if (mididm->deviation () > 50.0) {
2968 strcat (buf, _("(too large jitter)"));
2970 } else if (mididm->deviation () > 10.0) {
2972 strcat (buf, _("(large jitter)"));
2976 have_lm_results = true;
2977 end_latency_detection ();
2978 lm_use_button.set_sensitive (true);
2979 lm_results.set_markup (string_compose (results_markup, buf));
2981 } else if (mididm->processed () > 400) {
2982 have_lm_results = false;
2983 end_latency_detection ();
2984 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2988 lm_results.set_markup (string_compose (results_markup, buf));
2994 EngineControl::start_latency_detection ()
2996 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2997 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2999 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3000 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3001 if (_measure_midi) {
3002 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3004 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3006 lm_measure_label.set_text (_("Cancel"));
3007 have_lm_results = false;
3008 lm_use_button.set_sensitive (false);
3009 lm_input_channel_combo.set_sensitive (false);
3010 lm_output_channel_combo.set_sensitive (false);
3016 EngineControl::end_latency_detection ()
3018 latency_timeout.disconnect ();
3019 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3020 lm_measure_label.set_text (_("Measure"));
3021 if (!have_lm_results) {
3022 lm_use_button.set_sensitive (false);
3024 lm_input_channel_combo.set_sensitive (true);
3025 lm_output_channel_combo.set_sensitive (true);
3030 EngineControl::latency_button_clicked ()
3033 start_latency_detection ();
3035 end_latency_detection ();
3040 EngineControl::latency_back_button_clicked ()
3042 ARDOUR::AudioEngine::instance()->stop(true);
3043 notebook.set_current_page(0);
3047 EngineControl::use_latency_button_clicked ()
3049 if (_measure_midi) {
3050 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3054 ARDOUR::framecnt_t frames_total = mididm->latency();
3055 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3056 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3057 _measure_midi->input_latency = one_way;
3058 _measure_midi->output_latency = one_way;
3059 notebook.set_current_page (midi_tab);
3061 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3067 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3068 one_way = std::max (0., one_way);
3070 input_latency_adjustment.set_value (one_way);
3071 output_latency_adjustment.set_value (one_way);
3073 /* back to settings page */
3074 notebook.set_current_page (0);
3079 EngineControl::on_delete_event (GdkEventAny* ev)
3081 if (notebook.get_current_page() == 2) {
3082 /* currently on latency tab - be sure to clean up */
3083 end_latency_detection ();
3085 return ArdourDialog::on_delete_event (ev);
3089 EngineControl::engine_running ()
3091 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3094 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3095 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3097 if (backend->can_set_period_size ()) {
3098 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3101 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3102 connect_disconnect_button.show();
3104 started_at_least_once = true;
3105 if (_have_control) {
3106 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3108 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3110 update_sensitivity();
3114 EngineControl::engine_stopped ()
3116 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3119 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3120 connect_disconnect_button.show();
3122 if (_have_control) {
3123 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3125 engine_status.set_markup(X_(""));
3128 update_sensitivity();
3132 EngineControl::device_list_changed ()
3134 if (ignore_device_changes) {
3137 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3139 midi_option_changed();
3143 EngineControl::connect_disconnect_click()
3145 if (ARDOUR::AudioEngine::instance()->running()) {
3148 if (!ARDOUR_UI::instance()->session_loaded) {
3152 if (!ARDOUR_UI::instance()->session_loaded) {
3153 ArdourDialog::on_response (RESPONSE_OK);
3154 if (Splash::instance()) {
3155 Splash::instance()->pop_front ();
3162 EngineControl::calibrate_audio_latency ()
3164 _measure_midi.reset ();
3165 have_lm_results = false;
3166 lm_use_button.set_sensitive (false);
3167 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3168 notebook.set_current_page (latency_tab);
3172 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3175 have_lm_results = false;
3176 lm_use_button.set_sensitive (false);
3177 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3178 notebook.set_current_page (latency_tab);
3182 EngineControl::configure_midi_devices ()
3184 notebook.set_current_page (midi_tab);