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) {
1806 // sort active first, then most recently used to the beginning of the list
1808 EngineControl::state_sort_cmp (const State &a, const State &b) {
1812 else if (b->active) {
1816 return a->lru > b->lru;
1820 EngineControl::State
1821 EngineControl::save_state ()
1825 if (!_have_control) {
1826 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1828 state->lru = time (NULL) ;
1831 state.reset(new StateStruct);
1832 state->backend = get_backend ();
1834 state.reset(new StateStruct);
1835 store_state (state);
1838 for (StateList::iterator i = states.begin(); i != states.end();) {
1839 if (equivalent_states (*i, state)) {
1840 i = states.erase(i);
1846 states.push_back (state);
1848 states.sort (state_sort_cmp);
1854 EngineControl::store_state (State state)
1856 state->backend = get_backend ();
1857 state->driver = get_driver ();
1858 state->device = get_device_name ();
1859 state->input_device = get_input_device_name ();
1860 state->output_device = get_output_device_name ();
1861 state->sample_rate = get_rate ();
1862 state->buffer_size = get_buffer_size ();
1863 state->n_periods = get_nperiods ();
1864 state->input_latency = get_input_latency ();
1865 state->output_latency = get_output_latency ();
1866 state->input_channels = get_input_channels ();
1867 state->output_channels = get_output_channels ();
1868 state->midi_option = get_midi_option ();
1869 state->midi_devices = _midi_devices;
1870 state->use_buffered_io = get_use_buffered_io ();
1871 state->lru = time (NULL) ;
1875 EngineControl::maybe_display_saved_state ()
1877 if (!_have_control) {
1881 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1884 DEBUG_ECONTROL ("Restoring saved state");
1885 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1887 if (!_desired_sample_rate) {
1888 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1890 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1892 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1893 /* call this explicitly because we're ignoring changes to
1894 the controls at this point.
1896 show_buffer_duration ();
1897 input_latency.set_value (state->input_latency);
1898 output_latency.set_value (state->output_latency);
1900 use_buffered_io_button.set_active (state->use_buffered_io);
1902 if (!state->midi_option.empty()) {
1903 midi_option_combo.set_active_text (state->midi_option);
1904 _midi_devices = state->midi_devices;
1907 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1912 EngineControl::get_state ()
1916 XMLNode* root = new XMLNode ("AudioMIDISetup");
1919 if (!states.empty()) {
1920 XMLNode* state_nodes = new XMLNode ("EngineStates");
1922 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1924 XMLNode* node = new XMLNode ("State");
1926 node->add_property ("backend", (*i)->backend);
1927 node->add_property ("driver", (*i)->driver);
1928 node->add_property ("device", (*i)->device);
1929 node->add_property ("input-device", (*i)->input_device);
1930 node->add_property ("output-device", (*i)->output_device);
1931 node->add_property ("sample-rate", (*i)->sample_rate);
1932 node->add_property ("buffer-size", (*i)->buffer_size);
1933 node->add_property ("n-periods", (*i)->n_periods);
1934 node->add_property ("input-latency", (*i)->input_latency);
1935 node->add_property ("output-latency", (*i)->output_latency);
1936 node->add_property ("input-channels", (*i)->input_channels);
1937 node->add_property ("output-channels", (*i)->output_channels);
1938 node->add_property ("active", (*i)->active ? "yes" : "no");
1939 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1940 node->add_property ("midi-option", (*i)->midi_option);
1941 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1943 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1944 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1945 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1946 midi_device_stuff->add_property (X_("name"), (*p)->name);
1947 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1948 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1949 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1950 midi_devices->add_child_nocopy (*midi_device_stuff);
1952 node->add_child_nocopy (*midi_devices);
1954 state_nodes->add_child_nocopy (*node);
1957 root->add_child_nocopy (*state_nodes);
1964 EngineControl::set_default_state ()
1966 vector<string> backend_names;
1967 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1969 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1970 backend_names.push_back ((*b)->name);
1972 backend_combo.set_active_text (backend_names.front());
1974 // We could set default backends per platform etc here
1980 EngineControl::set_state (const XMLNode& root)
1982 XMLNodeList clist, cclist;
1983 XMLNodeConstIterator citer, cciter;
1984 XMLNode const * child;
1985 XMLNode const * grandchild;
1986 XMLProperty const * prop = NULL;
1988 if (root.name() != "AudioMIDISetup") {
1992 clist = root.children();
1996 for (citer = clist.begin(); citer != clist.end(); ++citer) {
2000 if (child->name() != "EngineStates") {
2004 cclist = child->children();
2006 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2007 State state (new StateStruct);
2009 grandchild = *cciter;
2011 if (grandchild->name() != "State") {
2015 if ((prop = grandchild->property ("backend")) == 0) {
2018 state->backend = prop->value ();
2020 if ((prop = grandchild->property ("driver")) == 0) {
2023 state->driver = prop->value ();
2025 if ((prop = grandchild->property ("device")) == 0) {
2028 state->device = prop->value ();
2030 if ((prop = grandchild->property ("input-device")) == 0) {
2033 state->input_device = prop->value ();
2035 if ((prop = grandchild->property ("output-device")) == 0) {
2038 state->output_device = prop->value ();
2040 if ((prop = grandchild->property ("sample-rate")) == 0) {
2043 state->sample_rate = atof (prop->value ());
2045 if ((prop = grandchild->property ("buffer-size")) == 0) {
2048 state->buffer_size = atoi (prop->value ());
2050 if ((prop = grandchild->property ("n-periods")) == 0) {
2051 // optional (new value in 4.5)
2052 state->n_periods = 0;
2054 state->n_periods = atoi (prop->value ());
2057 if ((prop = grandchild->property ("input-latency")) == 0) {
2060 state->input_latency = atoi (prop->value ());
2062 if ((prop = grandchild->property ("output-latency")) == 0) {
2065 state->output_latency = atoi (prop->value ());
2067 if ((prop = grandchild->property ("input-channels")) == 0) {
2070 state->input_channels = atoi (prop->value ());
2072 if ((prop = grandchild->property ("output-channels")) == 0) {
2075 state->output_channels = atoi (prop->value ());
2077 if ((prop = grandchild->property ("active")) == 0) {
2080 state->active = string_is_affirmative (prop->value ());
2082 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2085 state->use_buffered_io = string_is_affirmative (prop->value ());
2087 if ((prop = grandchild->property ("midi-option")) == 0) {
2090 state->midi_option = prop->value ();
2092 state->midi_devices.clear();
2094 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2095 const XMLNodeList mnc = midinode->children();
2096 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2097 if ((*n)->property (X_("name")) == 0
2098 || (*n)->property (X_("enabled")) == 0
2099 || (*n)->property (X_("input-latency")) == 0
2100 || (*n)->property (X_("output-latency")) == 0
2105 MidiDeviceSettings ptr (new MidiDeviceSetting(
2106 (*n)->property (X_("name"))->value (),
2107 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2108 atoi ((*n)->property (X_("input-latency"))->value ()),
2109 atoi ((*n)->property (X_("output-latency"))->value ())
2111 state->midi_devices.push_back (ptr);
2115 if ((prop = grandchild->property ("lru"))) {
2116 state->lru = atoi (prop->value ());
2120 /* remove accumulated duplicates (due to bug in ealier version)
2121 * this can be removed again before release
2123 for (StateList::iterator i = states.begin(); i != states.end();) {
2124 if ((*i)->backend == state->backend &&
2125 (*i)->driver == state->driver &&
2126 (*i)->device == state->device) {
2127 i = states.erase(i);
2134 states.push_back (state);
2138 /* now see if there was an active state and switch the setup to it */
2140 // purge states of backend that are not available in this built
2141 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2142 vector<std::string> backend_names;
2144 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2145 backend_names.push_back((*i)->name);
2147 for (StateList::iterator i = states.begin(); i != states.end();) {
2148 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2149 i = states.erase(i);
2155 states.sort (state_sort_cmp);
2157 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2160 return set_current_state (*i);
2167 EngineControl::set_current_state (const State& state)
2169 DEBUG_ECONTROL ("set_current_state");
2171 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2173 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2174 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2175 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2176 // this shouldn't happen as the invalid backend names should have been
2177 // removed from the list of states.
2181 // now reflect the change in the backend in the GUI so backend_changed will
2182 // do the right thing
2183 backend_combo.set_active_text (state->backend);
2185 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2187 // we don't have control don't restore state
2192 if (!state->driver.empty ()) {
2193 if (!backend->requires_driver_selection ()) {
2194 DEBUG_ECONTROL ("Backend should require driver selection");
2195 // A backend has changed from having driver selection to not having
2196 // it or someone has been manually editing a config file and messed
2201 if (backend->set_driver (state->driver) != 0) {
2202 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2203 // Driver names for a backend have changed and the name in the
2204 // config file is now invalid or support for driver is no longer
2205 // included in the backend
2208 // no need to set the driver_combo as backend_changed will use
2209 // backend->driver_name to set the active driver
2212 if (!state->device.empty ()) {
2213 if (backend->set_device_name (state->device) != 0) {
2215 string_compose ("Unable to set device name %1", state->device));
2216 // device is no longer available on the system
2219 // no need to set active device as it will be picked up in
2220 // via backend_changed ()/set_device_popdown_strings
2223 // backend supports separate input/output devices
2224 if (backend->set_input_device_name (state->input_device) != 0) {
2225 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2226 state->input_device));
2227 // input device is no longer available on the system
2231 if (backend->set_output_device_name (state->output_device) != 0) {
2232 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2233 state->input_device));
2234 // output device is no longer available on the system
2237 // no need to set active devices as it will be picked up in via
2238 // backend_changed ()/set_*_device_popdown_strings
2243 // Now restore the state of the rest of the controls
2245 // We don't use a SignalBlocker as set_current_state is currently only
2246 // called from set_state before any signals are connected. If at some point
2247 // a more general named state mechanism is implemented and
2248 // set_current_state is called while signals are connected then a
2249 // SignalBlocker will need to be instantiated before setting these.
2251 device_combo.set_active_text (state->device);
2252 input_device_combo.set_active_text (state->input_device);
2253 output_device_combo.set_active_text (state->output_device);
2254 if (!_desired_sample_rate) {
2255 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2257 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2258 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2259 input_latency.set_value (state->input_latency);
2260 output_latency.set_value (state->output_latency);
2261 midi_option_combo.set_active_text (state->midi_option);
2262 use_buffered_io_button.set_active (state->use_buffered_io);
2267 EngineControl::push_state_to_backend (bool start)
2269 DEBUG_ECONTROL ("push_state_to_backend");
2270 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2271 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2277 /* figure out what is going to change */
2279 bool restart_required = false;
2280 bool was_running = ARDOUR::AudioEngine::instance()->running();
2281 bool change_driver = false;
2282 bool change_device = false;
2283 bool change_rate = false;
2284 bool change_bufsize = false;
2285 bool change_nperiods = false;
2286 bool change_latency = false;
2287 bool change_channels = false;
2288 bool change_midi = false;
2289 bool change_buffered_io = false;
2291 uint32_t ochan = get_output_channels ();
2292 uint32_t ichan = get_input_channels ();
2294 if (_have_control) {
2296 if (started_at_least_once) {
2298 /* we can control the backend */
2300 if (backend->requires_driver_selection()) {
2301 if (get_driver() != backend->driver_name()) {
2302 change_driver = true;
2306 if (backend->use_separate_input_and_output_devices()) {
2307 if (get_input_device_name() != backend->input_device_name()) {
2308 change_device = true;
2310 if (get_output_device_name() != backend->output_device_name()) {
2311 change_device = true;
2314 if (get_device_name() != backend->device_name()) {
2315 change_device = true;
2319 if (queue_device_changed) {
2320 change_device = true;
2323 if (get_rate() != backend->sample_rate()) {
2327 if (get_buffer_size() != backend->buffer_size()) {
2328 change_bufsize = true;
2331 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2332 && get_nperiods() != backend->period_size()) {
2333 change_nperiods = true;
2336 if (get_midi_option() != backend->midi_option()) {
2340 if (backend->can_use_buffered_io()) {
2341 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2342 change_buffered_io = true;
2346 /* zero-requested channels means "all available" */
2349 ichan = backend->input_channels();
2353 ochan = backend->output_channels();
2356 if (ichan != backend->input_channels()) {
2357 change_channels = true;
2360 if (ochan != backend->output_channels()) {
2361 change_channels = true;
2364 if (get_input_latency() != backend->systemic_input_latency() ||
2365 get_output_latency() != backend->systemic_output_latency()) {
2366 change_latency = true;
2369 /* backend never started, so we have to force a group
2372 change_device = true;
2373 if (backend->requires_driver_selection()) {
2374 change_driver = true;
2377 change_bufsize = true;
2378 change_channels = true;
2379 change_latency = true;
2381 change_buffered_io = backend->can_use_buffered_io();
2382 change_channels = true;
2383 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2388 /* we have no control over the backend, meaning that we can
2389 * only possibly change sample rate and buffer size.
2393 if (get_rate() != backend->sample_rate()) {
2394 change_bufsize = true;
2397 if (get_buffer_size() != backend->buffer_size()) {
2398 change_bufsize = true;
2402 queue_device_changed = false;
2404 if (!_have_control) {
2406 /* We do not have control over the backend, so the best we can
2407 * do is try to change the sample rate and/or bufsize and get
2411 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2415 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2420 backend->set_sample_rate (get_rate());
2423 if (change_bufsize) {
2424 backend->set_buffer_size (get_buffer_size());
2428 if (ARDOUR::AudioEngine::instance()->start ()) {
2429 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2439 /* determine if we need to stop the backend before changing parameters */
2441 if (change_driver || change_device || change_channels || change_nperiods ||
2442 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2443 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2444 change_midi || change_buffered_io ||
2445 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2446 restart_required = true;
2448 restart_required = false;
2453 if (restart_required) {
2454 if (ARDOUR::AudioEngine::instance()->stop()) {
2460 if (change_driver && backend->set_driver (get_driver())) {
2461 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2464 if (backend->use_separate_input_and_output_devices()) {
2465 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2466 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2469 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2470 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2474 if (change_device && backend->set_device_name (get_device_name())) {
2475 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2479 if (change_rate && backend->set_sample_rate (get_rate())) {
2480 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2483 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2484 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2487 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2488 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2492 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2493 if (backend->set_input_channels (get_input_channels())) {
2494 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2497 if (backend->set_output_channels (get_output_channels())) {
2498 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2502 if (change_latency) {
2503 if (backend->set_systemic_input_latency (get_input_latency())) {
2504 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2507 if (backend->set_systemic_output_latency (get_output_latency())) {
2508 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2514 backend->set_midi_option (get_midi_option());
2517 if (change_buffered_io) {
2518 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2522 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2523 if (_measure_midi) {
2524 if (*p == _measure_midi) {
2525 backend->set_midi_device_enabled ((*p)->name, true);
2527 backend->set_midi_device_enabled ((*p)->name, false);
2529 if (backend->can_change_systemic_latency_when_running ()) {
2530 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2531 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2535 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2536 if (backend->can_set_systemic_midi_latencies()) {
2537 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2538 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2543 if (start || (was_running && restart_required)) {
2544 if (ARDOUR::AudioEngine::instance()->start()) {
2555 EngineControl::post_push ()
2557 /* get a pointer to the current state object, creating one if
2561 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2564 state = save_state ();
2570 states.sort (state_sort_cmp);
2574 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2575 (*i)->active = false;
2578 /* mark this one active (to be used next time the dialog is
2582 state->active = true;
2584 if (_have_control) { // XXX
2585 manage_control_app_sensitivity ();
2588 /* schedule a redisplay of MIDI ports */
2589 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2594 EngineControl::get_rate () const
2596 float r = atof (sample_rate_combo.get_active_text ());
2597 /* the string may have been translated with an abbreviation for
2598 * thousands, so use a crude heuristic to fix this.
2608 EngineControl::get_buffer_size () const
2610 string txt = buffer_size_combo.get_active_text ();
2613 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2614 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2615 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2623 EngineControl::get_nperiods () const
2625 string txt = nperiods_combo.get_active_text ();
2626 return atoi (txt.c_str());
2630 EngineControl::get_midi_option () const
2632 return midi_option_combo.get_active_text();
2636 EngineControl::get_use_buffered_io () const
2638 return use_buffered_io_button.get_active();
2642 EngineControl::get_input_channels() const
2644 if (ARDOUR::Profile->get_mixbus()) {
2645 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2646 if (!backend) return 0;
2647 return backend->input_channels();
2649 return (uint32_t) input_channels_adjustment.get_value();
2653 EngineControl::get_output_channels() const
2655 if (ARDOUR::Profile->get_mixbus()) {
2656 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2657 if (!backend) return 0;
2658 return backend->input_channels();
2660 return (uint32_t) output_channels_adjustment.get_value();
2664 EngineControl::get_input_latency() const
2666 return (uint32_t) input_latency_adjustment.get_value();
2670 EngineControl::get_output_latency() const
2672 return (uint32_t) output_latency_adjustment.get_value();
2676 EngineControl::get_backend () const
2678 return backend_combo.get_active_text ();
2682 EngineControl::get_driver () const
2684 if (driver_combo.get_parent()) {
2685 return driver_combo.get_active_text ();
2692 EngineControl::get_device_name () const
2694 return device_combo.get_active_text ();
2698 EngineControl::get_input_device_name () const
2700 return input_device_combo.get_active_text ();
2704 EngineControl::get_output_device_name () const
2706 return output_device_combo.get_active_text ();
2710 EngineControl::control_app_button_clicked ()
2712 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2718 backend->launch_control_app ();
2722 EngineControl::start_stop_button_clicked ()
2724 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2730 if (ARDOUR::AudioEngine::instance()->running()) {
2731 ARDOUR::AudioEngine::instance()->stop ();
2733 if (!ARDOUR_UI::instance()->session_loaded) {
2737 if (!ARDOUR_UI::instance()->session_loaded) {
2738 ArdourDialog::on_response (RESPONSE_OK);
2739 if (Splash::instance()) {
2740 Splash::instance()->pop_front ();
2747 EngineControl::update_devices_button_clicked ()
2749 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2755 if (backend->update_devices()) {
2756 device_list_changed ();
2761 EngineControl::use_buffered_io_button_clicked ()
2763 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2769 bool set_buffered_io = !use_buffered_io_button.get_active();
2770 use_buffered_io_button.set_active (set_buffered_io);
2771 backend->set_use_buffered_io (set_buffered_io);
2775 EngineControl::manage_control_app_sensitivity ()
2777 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2783 string appname = backend->control_app_name();
2785 if (appname.empty()) {
2786 control_app_button.set_sensitive (false);
2788 control_app_button.set_sensitive (true);
2793 EngineControl::set_desired_sample_rate (uint32_t sr)
2795 _desired_sample_rate = sr;
2796 if (ARDOUR::AudioEngine::instance ()->running ()
2797 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2804 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2806 if (page_num == 0) {
2807 _measure_midi.reset();
2808 update_sensitivity ();
2811 if (page_num == midi_tab) {
2813 refresh_midi_display ();
2816 if (page_num == latency_tab) {
2819 if (ARDOUR::AudioEngine::instance()->running()) {
2824 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2826 /* save any existing latency values */
2828 uint32_t il = (uint32_t) input_latency.get_value ();
2829 uint32_t ol = (uint32_t) input_latency.get_value ();
2831 /* reset to zero so that our new test instance
2832 will be clean of any existing latency measures.
2834 NB. this should really be done by the backend
2835 when stated for latency measurement.
2838 input_latency.set_value (0);
2839 output_latency.set_value (0);
2841 push_state_to_backend (false);
2845 input_latency.set_value (il);
2846 output_latency.set_value (ol);
2849 // This should be done in push_state_to_backend()
2850 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2851 disable_latency_tab ();
2854 enable_latency_tab ();
2858 end_latency_detection ();
2859 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2864 /* latency measurement */
2867 EngineControl::check_audio_latency_measurement ()
2869 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2871 if (mtdm->resolve () < 0) {
2872 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2876 if (mtdm->get_peak () > 0.707f) {
2877 // get_peak() resets the peak-hold in the detector.
2878 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2879 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2883 if (mtdm->err () > 0.3) {
2889 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2891 if (sample_rate == 0) {
2892 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2893 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2897 int frames_total = mtdm->del();
2898 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2900 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2901 _("Detected roundtrip latency: "),
2902 frames_total, frames_total * 1000.0f/sample_rate,
2903 _("Systemic latency: "),
2904 extra, extra * 1000.0f/sample_rate);
2908 if (mtdm->err () > 0.2) {
2910 strcat (buf, _("(signal detection error)"));
2916 strcat (buf, _("(inverted - bad wiring)"));
2920 lm_results.set_markup (string_compose (results_markup, buf));
2923 have_lm_results = true;
2924 end_latency_detection ();
2925 lm_use_button.set_sensitive (true);
2933 EngineControl::check_midi_latency_measurement ()
2935 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2937 if (!mididm->have_signal () || mididm->latency () == 0) {
2938 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2943 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2945 if (sample_rate == 0) {
2946 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2947 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2951 ARDOUR::framecnt_t frames_total = mididm->latency();
2952 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2953 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2954 _("Detected roundtrip latency: "),
2955 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2956 _("Systemic latency: "),
2957 extra, extra * 1000.0f / sample_rate);
2961 if (!mididm->ok ()) {
2963 strcat (buf, _("(averaging)"));
2967 if (mididm->deviation () > 50.0) {
2969 strcat (buf, _("(too large jitter)"));
2971 } else if (mididm->deviation () > 10.0) {
2973 strcat (buf, _("(large jitter)"));
2977 have_lm_results = true;
2978 end_latency_detection ();
2979 lm_use_button.set_sensitive (true);
2980 lm_results.set_markup (string_compose (results_markup, buf));
2982 } else if (mididm->processed () > 400) {
2983 have_lm_results = false;
2984 end_latency_detection ();
2985 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2989 lm_results.set_markup (string_compose (results_markup, buf));
2995 EngineControl::start_latency_detection ()
2997 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2998 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
3000 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3001 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3002 if (_measure_midi) {
3003 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3005 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3007 lm_measure_label.set_text (_("Cancel"));
3008 have_lm_results = false;
3009 lm_use_button.set_sensitive (false);
3010 lm_input_channel_combo.set_sensitive (false);
3011 lm_output_channel_combo.set_sensitive (false);
3017 EngineControl::end_latency_detection ()
3019 latency_timeout.disconnect ();
3020 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3021 lm_measure_label.set_text (_("Measure"));
3022 if (!have_lm_results) {
3023 lm_use_button.set_sensitive (false);
3025 lm_input_channel_combo.set_sensitive (true);
3026 lm_output_channel_combo.set_sensitive (true);
3031 EngineControl::latency_button_clicked ()
3034 start_latency_detection ();
3036 end_latency_detection ();
3041 EngineControl::latency_back_button_clicked ()
3043 ARDOUR::AudioEngine::instance()->stop(true);
3044 notebook.set_current_page(0);
3048 EngineControl::use_latency_button_clicked ()
3050 if (_measure_midi) {
3051 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3055 ARDOUR::framecnt_t frames_total = mididm->latency();
3056 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3057 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3058 _measure_midi->input_latency = one_way;
3059 _measure_midi->output_latency = one_way;
3060 notebook.set_current_page (midi_tab);
3062 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3068 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3069 one_way = std::max (0., one_way);
3071 input_latency_adjustment.set_value (one_way);
3072 output_latency_adjustment.set_value (one_way);
3074 /* back to settings page */
3075 notebook.set_current_page (0);
3080 EngineControl::on_delete_event (GdkEventAny* ev)
3082 if (notebook.get_current_page() == 2) {
3083 /* currently on latency tab - be sure to clean up */
3084 end_latency_detection ();
3086 return ArdourDialog::on_delete_event (ev);
3090 EngineControl::engine_running ()
3092 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3095 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3096 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3098 if (backend->can_set_period_size ()) {
3099 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3102 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3103 connect_disconnect_button.show();
3105 started_at_least_once = true;
3106 if (_have_control) {
3107 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3109 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3111 update_sensitivity();
3115 EngineControl::engine_stopped ()
3117 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3120 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3121 connect_disconnect_button.show();
3123 if (_have_control) {
3124 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3126 engine_status.set_markup(X_(""));
3129 update_sensitivity();
3133 EngineControl::device_list_changed ()
3135 if (ignore_device_changes) {
3138 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3140 midi_option_changed();
3144 EngineControl::connect_disconnect_click()
3146 if (ARDOUR::AudioEngine::instance()->running()) {
3149 if (!ARDOUR_UI::instance()->session_loaded) {
3153 if (!ARDOUR_UI::instance()->session_loaded) {
3154 ArdourDialog::on_response (RESPONSE_OK);
3155 if (Splash::instance()) {
3156 Splash::instance()->pop_front ();
3163 EngineControl::calibrate_audio_latency ()
3165 _measure_midi.reset ();
3166 have_lm_results = false;
3167 lm_use_button.set_sensitive (false);
3168 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3169 notebook.set_current_page (latency_tab);
3173 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3176 have_lm_results = false;
3177 lm_use_button.set_sensitive (false);
3178 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3179 notebook.set_current_page (latency_tab);
3183 EngineControl::configure_midi_devices ()
3185 notebook.set_current_page (midi_tab);