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);
284 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
285 update_devices_button.set_sensitive (false);
286 update_devices_button.set_name ("generic button");
287 update_devices_button.set_can_focus(true);
289 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
290 use_buffered_io_button.set_sensitive (false);
291 use_buffered_io_button.set_name ("generic button");
292 use_buffered_io_button.set_can_focus(true);
294 /* Pick up any existing audio setup configuration, if appropriate */
296 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
298 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
299 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
300 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
301 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
304 if (!set_state (*audio_setup)) {
305 set_default_state ();
308 set_default_state ();
311 update_sensitivity ();
312 connect_changed_signals ();
314 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
316 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
318 connect_disconnect_button.set_no_show_all();
319 use_buffered_io_button.set_no_show_all();
320 update_devices_button.set_no_show_all();
321 start_stop_button.set_no_show_all();
322 midi_devices_button.set_no_show_all();
326 EngineControl::connect_changed_signals ()
328 backend_combo_connection = backend_combo.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::backend_changed));
330 driver_combo_connection = driver_combo.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::driver_changed));
332 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
333 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
334 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
336 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
338 device_combo_connection = device_combo.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::device_changed));
340 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
343 input_device_combo_connection = input_device_combo.signal_changed ().connect (
344 sigc::mem_fun (*this, &EngineControl::input_device_changed));
345 output_device_combo_connection = output_device_combo.signal_changed ().connect (
346 sigc::mem_fun (*this, &EngineControl::output_device_changed));
348 input_latency_connection = input_latency.signal_changed ().connect (
349 sigc::mem_fun (*this, &EngineControl::parameter_changed));
350 output_latency_connection = output_latency.signal_changed ().connect (
351 sigc::mem_fun (*this, &EngineControl::parameter_changed));
352 input_channels_connection = input_channels.signal_changed ().connect (
353 sigc::mem_fun (*this, &EngineControl::parameter_changed));
354 output_channels_connection = output_channels.signal_changed ().connect (
355 sigc::mem_fun (*this, &EngineControl::parameter_changed));
359 EngineControl::block_changed_signals ()
361 if (block_signals++ == 0) {
362 DEBUG_ECONTROL ("Blocking changed signals");
363 backend_combo_connection.block ();
364 driver_combo_connection.block ();
365 sample_rate_combo_connection.block ();
366 buffer_size_combo_connection.block ();
367 nperiods_combo_connection.block ();
368 device_combo_connection.block ();
369 input_device_combo_connection.block ();
370 output_device_combo_connection.block ();
371 midi_option_combo_connection.block ();
372 input_latency_connection.block ();
373 output_latency_connection.block ();
374 input_channels_connection.block ();
375 output_channels_connection.block ();
380 EngineControl::unblock_changed_signals ()
382 if (--block_signals == 0) {
383 DEBUG_ECONTROL ("Unblocking changed signals");
384 backend_combo_connection.unblock ();
385 driver_combo_connection.unblock ();
386 sample_rate_combo_connection.unblock ();
387 buffer_size_combo_connection.unblock ();
388 nperiods_combo_connection.unblock ();
389 device_combo_connection.unblock ();
390 input_device_combo_connection.unblock ();
391 output_device_combo_connection.unblock ();
392 midi_option_combo_connection.unblock ();
393 input_latency_connection.unblock ();
394 output_latency_connection.unblock ();
395 input_channels_connection.unblock ();
396 output_channels_connection.unblock ();
400 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
401 const std::string& reason)
402 : ec (engine_control)
405 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
406 ec.block_changed_signals ();
409 EngineControl::SignalBlocker::~SignalBlocker ()
411 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
412 ec.unblock_changed_signals ();
416 EngineControl::on_show ()
418 ArdourDialog::on_show ();
419 if (Splash::instance()) {
420 Splash::instance()->hide ();
422 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
423 // re-check _have_control (jackd running) see #6041
427 start_stop_button.grab_focus();
431 EngineControl::on_map ()
433 if (!ARDOUR_UI::instance()->session_loaded && !PublicEditor::_instance) {
434 set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
435 } else if (UIConfiguration::instance().get_all_floating_windows_are_dialogs()) {
436 set_type_hint (Gdk::WINDOW_TYPE_HINT_DIALOG);
438 set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY);
440 ArdourDialog::on_map ();
444 EngineControl::try_autostart ()
446 if (!start_stop_button.get_sensitive()) {
449 if (ARDOUR::AudioEngine::instance()->running()) {
452 return start_engine ();
456 EngineControl::start_engine ()
458 if (push_state_to_backend(true) != 0) {
459 MessageDialog msg(*this,
460 ARDOUR::AudioEngine::instance()->get_last_backend_error());
468 EngineControl::stop_engine (bool for_latency)
470 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
471 MessageDialog msg(*this,
472 ARDOUR::AudioEngine::instance()->get_last_backend_error());
480 EngineControl::build_notebook ()
483 AttachOptions xopt = AttachOptions (FILL|EXPAND);
485 /* clear the table */
487 Gtkmm2ext::container_clear (basic_vbox);
488 Gtkmm2ext::container_clear (basic_packer);
490 if (control_app_button.get_parent()) {
491 control_app_button.get_parent()->remove (control_app_button);
494 label = manage (left_aligned_label (_("Audio System:")));
495 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
496 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
498 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
499 engine_status.show();
501 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
502 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
503 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
505 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
506 lm_button_audio.set_name ("generic button");
507 lm_button_audio.set_can_focus(true);
510 build_full_control_notebook ();
512 build_no_control_notebook ();
515 basic_vbox.pack_start (basic_hbox, false, false);
518 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
519 basic_vbox.show_all ();
524 EngineControl::build_full_control_notebook ()
526 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
529 using namespace Notebook_Helpers;
531 vector<string> strings;
532 AttachOptions xopt = AttachOptions (FILL|EXPAND);
533 int row = 1; // row zero == backend combo
535 /* start packing it up */
537 if (backend->requires_driver_selection()) {
538 label = manage (left_aligned_label (_("Driver:")));
539 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
540 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
544 if (backend->use_separate_input_and_output_devices()) {
545 label = manage (left_aligned_label (_("Input Device:")));
546 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
547 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
549 label = manage (left_aligned_label (_("Output Device:")));
550 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
551 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
553 // reset so it isn't used in state comparisons
554 device_combo.set_active_text ("");
556 label = manage (left_aligned_label (_("Device:")));
557 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
558 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
560 // reset these so they don't get used in state comparisons
561 input_device_combo.set_active_text ("");
562 output_device_combo.set_active_text ("");
565 label = manage (left_aligned_label (_("Sample rate:")));
566 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
567 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
571 label = manage (left_aligned_label (_("Buffer size:")));
572 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 buffer_size_duration_label.set_alignment (0.0); /* left-align */
575 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
577 int ctrl_btn_span = 1;
578 if (backend->can_set_period_size ()) {
580 label = manage (left_aligned_label (_("Periods:")));
581 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
582 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
586 /* button spans 2 or 3 rows */
588 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
591 input_channels.set_name ("InputChannels");
592 input_channels.set_flags (Gtk::CAN_FOCUS);
593 input_channels.set_digits (0);
594 input_channels.set_wrap (false);
595 output_channels.set_editable (true);
597 if (!ARDOUR::Profile->get_mixbus()) {
598 label = manage (left_aligned_label (_("Input Channels:")));
599 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
600 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
604 output_channels.set_name ("OutputChannels");
605 output_channels.set_flags (Gtk::CAN_FOCUS);
606 output_channels.set_digits (0);
607 output_channels.set_wrap (false);
608 output_channels.set_editable (true);
610 if (!ARDOUR::Profile->get_mixbus()) {
611 label = manage (left_aligned_label (_("Output Channels:")));
612 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
613 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
617 input_latency.set_name ("InputLatency");
618 input_latency.set_flags (Gtk::CAN_FOCUS);
619 input_latency.set_digits (0);
620 input_latency.set_wrap (false);
621 input_latency.set_editable (true);
623 label = manage (left_aligned_label (_("Hardware input latency:")));
624 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
625 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
626 label = manage (left_aligned_label (_("samples")));
627 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
630 output_latency.set_name ("OutputLatency");
631 output_latency.set_flags (Gtk::CAN_FOCUS);
632 output_latency.set_digits (0);
633 output_latency.set_wrap (false);
634 output_latency.set_editable (true);
636 label = manage (left_aligned_label (_("Hardware output latency:")));
637 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
638 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
639 label = manage (left_aligned_label (_("samples")));
640 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
642 /* button spans 2 rows */
644 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
647 label = manage (left_aligned_label (_("MIDI System:")));
648 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
649 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
650 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
655 EngineControl::build_no_control_notebook ()
657 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
660 using namespace Notebook_Helpers;
662 vector<string> strings;
663 AttachOptions xopt = AttachOptions (FILL|EXPAND);
664 int row = 1; // row zero == backend combo
665 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
667 label = manage (new Label);
668 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
669 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
672 if (backend->can_change_sample_rate_when_running()) {
673 label = manage (left_aligned_label (_("Sample rate:")));
674 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
675 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
679 if (backend->can_change_buffer_size_when_running()) {
680 label = manage (left_aligned_label (_("Buffer size:")));
681 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
682 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
683 buffer_size_duration_label.set_alignment (0.0); /* left-align */
684 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
688 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
692 EngineControl::~EngineControl ()
694 ignore_changes = true;
698 EngineControl::disable_latency_tab ()
700 vector<string> empty;
701 set_popdown_strings (lm_output_channel_combo, empty);
702 set_popdown_strings (lm_input_channel_combo, empty);
703 lm_measure_button.set_sensitive (false);
704 lm_use_button.set_sensitive (false);
708 EngineControl::enable_latency_tab ()
710 vector<string> outputs;
711 vector<string> inputs;
713 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
714 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
715 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
717 if (!ARDOUR::AudioEngine::instance()->running()) {
718 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
719 notebook.set_current_page (0);
723 else if (inputs.empty() || outputs.empty()) {
724 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
725 notebook.set_current_page (0);
730 lm_back_button_signal.disconnect();
732 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
735 lm_back_button_signal = lm_back_button.signal_clicked().connect(
736 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
740 set_popdown_strings (lm_output_channel_combo, outputs);
741 lm_output_channel_combo.set_active_text (outputs.front());
742 lm_output_channel_combo.set_sensitive (true);
744 set_popdown_strings (lm_input_channel_combo, inputs);
745 lm_input_channel_combo.set_active_text (inputs.front());
746 lm_input_channel_combo.set_sensitive (true);
748 lm_measure_button.set_sensitive (true);
752 EngineControl::setup_midi_tab_for_backend ()
754 string backend = backend_combo.get_active_text ();
756 Gtkmm2ext::container_clear (midi_vbox);
758 midi_vbox.set_border_width (12);
759 midi_device_table.set_border_width (12);
761 if (backend == "JACK") {
762 setup_midi_tab_for_jack ();
765 midi_vbox.pack_start (midi_device_table, true, true);
766 midi_vbox.pack_start (midi_back_button, false, false);
767 midi_vbox.show_all ();
771 EngineControl::update_sensitivity ()
773 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
775 start_stop_button.set_sensitive (false);
780 size_t devices_available = 0;
782 if (backend->use_separate_input_and_output_devices ()) {
783 devices_available += get_popdown_string_count (input_device_combo);
784 devices_available += get_popdown_string_count (output_device_combo);
786 devices_available += get_popdown_string_count (device_combo);
789 if (devices_available == 0) {
791 input_latency.set_sensitive (false);
792 output_latency.set_sensitive (false);
793 input_channels.set_sensitive (false);
794 output_channels.set_sensitive (false);
796 input_latency.set_sensitive (true);
797 output_latency.set_sensitive (true);
798 input_channels.set_sensitive (true);
799 output_channels.set_sensitive (true);
802 if (get_popdown_string_count (buffer_size_combo) > 0) {
803 if (!ARDOUR::AudioEngine::instance()->running()) {
804 buffer_size_combo.set_sensitive (valid);
805 } else if (backend->can_change_sample_rate_when_running()) {
806 buffer_size_combo.set_sensitive (valid || !_have_control);
810 * Currently there is no way to manually stop the
811 * engine in order to re-configure it.
812 * This needs to remain sensitive for now.
814 * (it's also handy to implicily
815 * re-start the engine)
817 buffer_size_combo.set_sensitive (true);
819 buffer_size_combo.set_sensitive (false);
823 buffer_size_combo.set_sensitive (false);
827 if (get_popdown_string_count (sample_rate_combo) > 0) {
828 bool allow_to_set_rate = false;
829 if (!ARDOUR::AudioEngine::instance()->running()) {
830 if (!ARDOUR_UI::instance()->session_loaded) {
831 // engine is not running, no session loaded -> anything goes.
832 allow_to_set_rate = true;
833 } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
834 // only allow to change if the current setting is not the native session rate.
835 allow_to_set_rate = true;
838 sample_rate_combo.set_sensitive (allow_to_set_rate);
840 sample_rate_combo.set_sensitive (false);
844 if (get_popdown_string_count (nperiods_combo) > 0) {
845 if (!ARDOUR::AudioEngine::instance()->running()) {
846 nperiods_combo.set_sensitive (true);
848 nperiods_combo.set_sensitive (false);
851 nperiods_combo.set_sensitive (false);
855 start_stop_button.set_sensitive(true);
856 start_stop_button.show();
857 if (ARDOUR::AudioEngine::instance()->running()) {
858 start_stop_button.set_text("Stop");
859 update_devices_button.set_sensitive(false);
860 use_buffered_io_button.set_sensitive(false);
862 if (backend->can_request_update_devices()) {
863 update_devices_button.show();
865 update_devices_button.hide();
867 if (backend->can_use_buffered_io()) {
868 use_buffered_io_button.show();
870 use_buffered_io_button.hide();
872 start_stop_button.set_text("Start");
873 update_devices_button.set_sensitive(true);
874 use_buffered_io_button.set_sensitive(true);
877 update_devices_button.set_sensitive(false);
878 update_devices_button.hide();
879 use_buffered_io_button.set_sensitive(false);
880 use_buffered_io_button.hide();
881 start_stop_button.set_sensitive(false);
882 start_stop_button.hide();
885 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
886 input_device_combo.set_sensitive (false);
887 output_device_combo.set_sensitive (false);
888 device_combo.set_sensitive (false);
889 driver_combo.set_sensitive (false);
891 input_device_combo.set_sensitive (true);
892 output_device_combo.set_sensitive (true);
893 device_combo.set_sensitive (true);
894 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
895 driver_combo.set_sensitive (true);
897 driver_combo.set_sensitive (false);
903 EngineControl::setup_midi_tab_for_jack ()
908 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
910 device->input_latency = a->get_value();
912 device->output_latency = a->get_value();
917 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
918 b->set_active (!b->get_active());
919 device->enabled = b->get_active();
920 refresh_midi_display(device->name);
924 EngineControl::refresh_midi_display (std::string focus)
926 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
930 AttachOptions xopt = AttachOptions (FILL|EXPAND);
933 Gtkmm2ext::container_clear (midi_device_table);
935 midi_device_table.set_spacings (6);
937 l = manage (new Label);
938 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
939 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
940 l->set_alignment (0.5, 0.5);
944 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
945 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
946 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
947 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
949 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
950 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
951 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
952 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
955 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
960 bool enabled = (*p)->enabled;
962 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
963 m->set_name ("midi device");
964 m->set_can_focus (Gtk::CAN_FOCUS);
965 m->add_events (Gdk::BUTTON_RELEASE_MASK);
966 m->set_active (enabled);
967 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
968 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
969 if ((*p)->name == focus) {
973 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
974 s = manage (new Gtk::SpinButton (*a));
975 a->set_value ((*p)->input_latency);
976 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
977 s->set_sensitive (_can_set_midi_latencies && enabled);
978 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
980 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
981 s = manage (new Gtk::SpinButton (*a));
982 a->set_value ((*p)->output_latency);
983 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
984 s->set_sensitive (_can_set_midi_latencies && enabled);
985 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
987 b = manage (new Button (_("Calibrate")));
988 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
989 b->set_sensitive (_can_set_midi_latencies && enabled);
990 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
997 EngineControl::backend_changed ()
999 SignalBlocker blocker (*this, "backend_changed");
1000 string backend_name = backend_combo.get_active_text();
1001 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1003 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1004 /* eh? setting the backend failed... how ? */
1005 /* A: stale config contains a backend that does not exist in current build */
1009 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1011 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1014 setup_midi_tab_for_backend ();
1015 _midi_devices.clear();
1017 if (backend->requires_driver_selection()) {
1018 if (set_driver_popdown_strings ()) {
1022 /* this will change the device text which will cause a call to
1023 * device changed which will set up parameters
1028 update_midi_options ();
1030 connect_disconnect_button.hide();
1032 midi_option_changed();
1034 started_at_least_once = false;
1036 /* changing the backend implies stopping the engine
1037 * ARDOUR::AudioEngine() may or may not emit this signal
1038 * depending on previous engine state
1040 engine_stopped (); // set "active/inactive"
1042 if (!_have_control) {
1043 // set settings from backend that we do have control over
1044 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1047 if (_have_control && !ignore_changes) {
1048 // set driver & devices
1049 State state = get_matching_state (backend_combo.get_active_text());
1051 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1052 set_current_state (state);
1056 if (!ignore_changes) {
1057 maybe_display_saved_state ();
1062 EngineControl::update_midi_options ()
1064 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1065 vector<string> midi_options = backend->enumerate_midi_options();
1067 if (midi_options.size() == 1) {
1068 /* only contains the "none" option */
1069 midi_option_combo.set_sensitive (false);
1071 if (_have_control) {
1072 set_popdown_strings (midi_option_combo, midi_options);
1073 midi_option_combo.set_active_text (midi_options.front());
1074 midi_option_combo.set_sensitive (true);
1076 midi_option_combo.set_sensitive (false);
1082 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1084 if (ARDOUR::Profile->get_mixbus()) {
1088 uint32_t cnt = (uint32_t) sb->get_value();
1090 sb->set_text (_("all available channels"));
1093 snprintf (buf, sizeof (buf), "%d", cnt);
1099 // @return true if there are drivers available
1101 EngineControl::set_driver_popdown_strings ()
1103 DEBUG_ECONTROL ("set_driver_popdown_strings");
1104 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1105 vector<string> drivers = backend->enumerate_drivers();
1107 if (drivers.empty ()) {
1108 // This is an error...?
1112 string current_driver = backend->driver_name ();
1114 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1116 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1119 current_driver = drivers.front ();
1122 set_popdown_strings (driver_combo, drivers);
1124 string_compose ("driver_combo.set_active_text: %1", current_driver));
1125 driver_combo.set_active_text (current_driver);
1130 EngineControl::get_default_device(const string& current_device_name,
1131 const vector<string>& available_devices)
1133 // If the current device is available, use it as default
1134 if (std::find (available_devices.begin (),
1135 available_devices.end (),
1136 current_device_name) != available_devices.end ()) {
1138 return current_device_name;
1141 using namespace ARDOUR;
1143 string default_device_name =
1144 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1146 vector<string>::const_iterator i;
1148 // If there is a "Default" device available, use it
1149 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1150 if (*i == default_device_name) {
1155 string none_device_name =
1156 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1158 // Use the first device that isn't "None"
1159 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1160 if (*i != none_device_name) {
1165 // Use "None" if there are no other available
1166 return available_devices.front();
1169 // @return true if there are devices available
1171 EngineControl::set_device_popdown_strings ()
1173 DEBUG_ECONTROL ("set_device_popdown_strings");
1174 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1175 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1177 /* NOTE: Ardour currently does not display the "available" field of the
1180 * Doing so would require a different GUI widget than the combo
1181 * box/popdown that we currently use, since it has no way to list
1182 * items that are not selectable. Something more like a popup menu,
1183 * which could have unselectable items, would be appropriate.
1186 vector<string> available_devices;
1188 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1189 available_devices.push_back (i->name);
1192 if (available_devices.empty ()) {
1196 set_popdown_strings (device_combo, available_devices);
1198 std::string default_device =
1199 get_default_device(backend->device_name(), available_devices);
1202 string_compose ("set device_combo active text: %1", default_device));
1204 device_combo.set_active_text(default_device);
1208 // @return true if there are input devices available
1210 EngineControl::set_input_device_popdown_strings ()
1212 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1213 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1214 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1216 vector<string> available_devices;
1218 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1219 available_devices.push_back (i->name);
1222 if (available_devices.empty()) {
1226 set_popdown_strings (input_device_combo, available_devices);
1228 std::string default_device =
1229 get_default_device(backend->input_device_name(), available_devices);
1232 string_compose ("set input_device_combo active text: %1", default_device));
1233 input_device_combo.set_active_text(default_device);
1237 // @return true if there are output devices available
1239 EngineControl::set_output_device_popdown_strings ()
1241 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1242 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1243 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1245 vector<string> available_devices;
1247 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1248 available_devices.push_back (i->name);
1251 if (available_devices.empty()) {
1255 set_popdown_strings (output_device_combo, available_devices);
1257 std::string default_device =
1258 get_default_device(backend->output_device_name(), available_devices);
1261 string_compose ("set output_device_combo active text: %1", default_device));
1262 output_device_combo.set_active_text(default_device);
1267 EngineControl::list_devices ()
1269 DEBUG_ECONTROL ("list_devices");
1270 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1273 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1275 bool devices_available = false;
1277 if (backend->use_separate_input_and_output_devices ()) {
1278 bool input_devices_available = set_input_device_popdown_strings ();
1279 bool output_devices_available = set_output_device_popdown_strings ();
1280 devices_available = input_devices_available || output_devices_available;
1282 devices_available = set_device_popdown_strings ();
1285 if (devices_available) {
1288 device_combo.clear();
1289 input_device_combo.clear();
1290 output_device_combo.clear();
1292 update_sensitivity ();
1296 EngineControl::driver_changed ()
1298 SignalBlocker blocker (*this, "driver_changed");
1299 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1302 backend->set_driver (driver_combo.get_active_text());
1305 // TODO load LRU device(s) for backend + driver combo
1307 if (!ignore_changes) {
1308 maybe_display_saved_state ();
1313 EngineControl::get_sample_rates_for_all_devices ()
1315 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1316 ARDOUR::AudioEngine::instance ()->current_backend ();
1317 vector<float> all_rates;
1319 if (backend->use_separate_input_and_output_devices ()) {
1320 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1322 all_rates = backend->available_sample_rates (get_device_name ());
1328 EngineControl::get_default_sample_rates ()
1330 vector<float> rates;
1331 rates.push_back (8000.0f);
1332 rates.push_back (16000.0f);
1333 rates.push_back (32000.0f);
1334 rates.push_back (44100.0f);
1335 rates.push_back (48000.0f);
1336 rates.push_back (88200.0f);
1337 rates.push_back (96000.0f);
1338 rates.push_back (192000.0f);
1339 rates.push_back (384000.0f);
1344 EngineControl::set_samplerate_popdown_strings ()
1346 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1347 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1352 if (_have_control) {
1353 sr = get_sample_rates_for_all_devices ();
1355 sr = get_default_sample_rates ();
1358 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1359 s.push_back (rate_as_string (*x));
1360 if (*x == _desired_sample_rate) {
1365 set_popdown_strings (sample_rate_combo, s);
1368 if (ARDOUR::AudioEngine::instance()->running()) {
1369 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1371 else if (desired.empty ()) {
1372 float new_active_sr = backend->default_sample_rate ();
1374 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1375 new_active_sr = sr.front ();
1378 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1380 sample_rate_combo.set_active_text (desired);
1384 update_sensitivity ();
1388 EngineControl::get_buffer_sizes_for_all_devices ()
1390 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1391 ARDOUR::AudioEngine::instance ()->current_backend ();
1392 vector<uint32_t> all_sizes;
1394 if (backend->use_separate_input_and_output_devices ()) {
1395 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1397 all_sizes = backend->available_buffer_sizes (get_device_name ());
1403 EngineControl::get_default_buffer_sizes ()
1405 vector<uint32_t> sizes;
1406 sizes.push_back (8);
1407 sizes.push_back (16);
1408 sizes.push_back (32);
1409 sizes.push_back (64);
1410 sizes.push_back (128);
1411 sizes.push_back (256);
1412 sizes.push_back (512);
1413 sizes.push_back (1024);
1414 sizes.push_back (2048);
1415 sizes.push_back (4096);
1416 sizes.push_back (8192);
1421 EngineControl::set_buffersize_popdown_strings ()
1423 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1424 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1425 vector<uint32_t> bs;
1428 if (_have_control) {
1429 bs = get_buffer_sizes_for_all_devices ();
1430 } else if (backend->can_change_buffer_size_when_running()) {
1431 bs = get_default_buffer_sizes ();
1434 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1435 s.push_back (bufsize_as_string (*x));
1438 uint32_t previous_size = 0;
1439 if (!buffer_size_combo.get_active_text().empty()) {
1440 previous_size = get_buffer_size ();
1443 set_popdown_strings (buffer_size_combo, s);
1447 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1448 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1451 buffer_size_combo.set_active_text(s.front());
1453 uint32_t period = backend->buffer_size();
1454 if (0 == period && backend->use_separate_input_and_output_devices()) {
1455 period = backend->default_buffer_size(get_input_device_name());
1457 if (0 == period && backend->use_separate_input_and_output_devices()) {
1458 period = backend->default_buffer_size(get_output_device_name());
1460 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1461 period = backend->default_buffer_size(get_device_name());
1464 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1466 show_buffer_duration ();
1468 update_sensitivity ();
1472 EngineControl::set_nperiods_popdown_strings ()
1474 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1475 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1476 vector<uint32_t> np;
1479 if (backend->can_set_period_size()) {
1480 np = backend->available_period_sizes (get_driver());
1483 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1484 s.push_back (nperiods_as_string (*x));
1487 set_popdown_strings (nperiods_combo, s);
1490 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1493 update_sensitivity ();
1497 EngineControl::device_changed ()
1499 SignalBlocker blocker (*this, "device_changed");
1500 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1503 string device_name_in;
1504 string device_name_out; // only used if backend support separate I/O devices
1506 if (backend->use_separate_input_and_output_devices()) {
1507 device_name_in = get_input_device_name ();
1508 device_name_out = get_output_device_name ();
1510 device_name_in = get_device_name ();
1513 /* we set the backend-device to query various device related intormation.
1514 * This has the side effect that backend->device_name() will match
1515 * the device_name and 'change_device' will never be true.
1516 * so work around this by setting...
1518 if (backend->use_separate_input_and_output_devices()) {
1519 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1520 queue_device_changed = true;
1523 if (device_name_in != backend->device_name()) {
1524 queue_device_changed = true;
1528 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1529 if (backend->use_separate_input_and_output_devices()) {
1530 backend->set_input_device_name (device_name_in);
1531 backend->set_output_device_name (device_name_out);
1533 backend->set_device_name(device_name_in);
1537 /* don't allow programmatic change to combos to cause a
1538 recursive call to this method.
1540 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1542 set_samplerate_popdown_strings ();
1543 set_buffersize_popdown_strings ();
1544 set_nperiods_popdown_strings ();
1546 /* TODO set min + max channel counts here */
1548 manage_control_app_sensitivity ();
1551 /* pick up any saved state for this device */
1553 if (!ignore_changes) {
1554 maybe_display_saved_state ();
1559 EngineControl::input_device_changed ()
1561 DEBUG_ECONTROL ("input_device_changed");
1563 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1564 if (backend && backend->match_input_output_devices_or_none ()) {
1565 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1567 if (get_output_device_name () != dev_none
1568 && get_input_device_name () != dev_none
1569 && get_input_device_name () != get_output_device_name ()) {
1570 block_changed_signals ();
1571 if (contains_value (output_device_combo, get_input_device_name ())) {
1572 output_device_combo.set_active_text (get_input_device_name ());
1574 assert (contains_value (output_device_combo, dev_none));
1575 output_device_combo.set_active_text (dev_none);
1577 unblock_changed_signals ();
1584 EngineControl::output_device_changed ()
1586 DEBUG_ECONTROL ("output_device_changed");
1587 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1588 if (backend && backend->match_input_output_devices_or_none ()) {
1589 const std::string& dev_none = ARDOUR::AudioBackend::get_standard_device_name (ARDOUR::AudioBackend::DeviceNone);
1591 if (get_input_device_name () != dev_none
1592 && get_input_device_name () != dev_none
1593 && get_input_device_name () != get_output_device_name ()) {
1594 block_changed_signals ();
1595 if (contains_value (input_device_combo, get_output_device_name ())) {
1596 input_device_combo.set_active_text (get_output_device_name ());
1598 assert (contains_value (input_device_combo, dev_none));
1599 input_device_combo.set_active_text (dev_none);
1601 unblock_changed_signals ();
1608 EngineControl::bufsize_as_string (uint32_t sz)
1610 return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1614 EngineControl::nperiods_as_string (uint32_t np)
1617 snprintf (buf, sizeof (buf), "%u", np);
1623 EngineControl::sample_rate_changed ()
1625 DEBUG_ECONTROL ("sample_rate_changed");
1626 /* reset the strings for buffer size to show the correct msec value
1627 (reflecting the new sample rate).
1630 show_buffer_duration ();
1635 EngineControl::buffer_size_changed ()
1637 DEBUG_ECONTROL ("buffer_size_changed");
1638 show_buffer_duration ();
1642 EngineControl::nperiods_changed ()
1644 DEBUG_ECONTROL ("nperiods_changed");
1645 show_buffer_duration ();
1649 EngineControl::show_buffer_duration ()
1651 DEBUG_ECONTROL ("show_buffer_duration");
1652 /* buffer sizes - convert from just samples to samples + msecs for
1653 * the displayed string
1656 string bs_text = buffer_size_combo.get_active_text ();
1657 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1658 uint32_t rate = get_rate();
1660 /* Except for ALSA and Dummy backends, we don't know the number of periods
1661 * per cycle and settings.
1663 * jack1 vs jack2 have different default latencies since jack2 start
1664 * in async-mode unless --sync is given which adds an extra cycle
1665 * of latency. The value is not known if jackd is started externally..
1667 * So just display the period size, that's also what
1668 * ARDOUR_UI::update_sample_rate() does for the status bar.
1669 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1670 * but still, that's the buffer period, not [round-trip] latency)
1673 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1674 buffer_size_duration_label.set_text (buf);
1678 EngineControl::midi_option_changed ()
1680 DEBUG_ECONTROL ("midi_option_changed");
1681 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1684 backend->set_midi_option (get_midi_option());
1686 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1688 //_midi_devices.clear(); // TODO merge with state-saved settings..
1689 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1690 std::vector<MidiDeviceSettings> new_devices;
1692 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1693 MidiDeviceSettings mds = find_midi_device (i->name);
1694 if (i->available && !mds) {
1695 uint32_t input_latency = 0;
1696 uint32_t output_latency = 0;
1697 if (_can_set_midi_latencies) {
1698 input_latency = backend->systemic_midi_input_latency (i->name);
1699 output_latency = backend->systemic_midi_output_latency (i->name);
1701 bool enabled = backend->midi_device_enabled (i->name);
1702 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1703 new_devices.push_back (ptr);
1704 } else if (i->available) {
1705 new_devices.push_back (mds);
1708 _midi_devices = new_devices;
1710 if (_midi_devices.empty()) {
1711 midi_devices_button.hide ();
1713 midi_devices_button.show ();
1718 EngineControl::parameter_changed ()
1722 EngineControl::State
1723 EngineControl::get_matching_state (const string& backend)
1725 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1726 if ((*i)->backend == backend) {
1733 EngineControl::State
1734 EngineControl::get_matching_state (
1735 const string& backend,
1736 const string& driver,
1737 const string& device)
1739 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1740 if ((*i)->backend == backend &&
1741 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1749 EngineControl::State
1750 EngineControl::get_matching_state (
1751 const string& backend,
1752 const string& driver,
1753 const string& input_device,
1754 const string& output_device)
1756 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1757 if ((*i)->backend == backend &&
1758 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1766 EngineControl::State
1767 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1769 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1772 if (backend->use_separate_input_and_output_devices ()) {
1773 return get_matching_state (backend_combo.get_active_text(),
1774 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1775 input_device_combo.get_active_text(),
1776 output_device_combo.get_active_text());
1778 return get_matching_state (backend_combo.get_active_text(),
1779 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1780 device_combo.get_active_text());
1784 return get_matching_state (backend_combo.get_active_text(),
1786 device_combo.get_active_text());
1789 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1790 const EngineControl::State& state2)
1792 if (state1->backend == state2->backend &&
1793 state1->driver == state2->driver &&
1794 state1->device == state2->device &&
1795 state1->input_device == state2->input_device &&
1796 state1->output_device == state2->output_device) {
1803 EngineControl::state_sort_cmp (const State &a, const State &b) {
1807 else if (b->active) {
1811 return a->lru < b->lru;
1815 EngineControl::State
1816 EngineControl::save_state ()
1820 if (!_have_control) {
1821 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1823 state->lru = time (NULL) ;
1826 state.reset(new StateStruct);
1827 state->backend = get_backend ();
1829 state.reset(new StateStruct);
1830 store_state (state);
1833 for (StateList::iterator i = states.begin(); i != states.end();) {
1834 if (equivalent_states (*i, state)) {
1835 i = states.erase(i);
1841 states.push_back (state);
1843 states.sort (state_sort_cmp);
1849 EngineControl::store_state (State state)
1851 state->backend = get_backend ();
1852 state->driver = get_driver ();
1853 state->device = get_device_name ();
1854 state->input_device = get_input_device_name ();
1855 state->output_device = get_output_device_name ();
1856 state->sample_rate = get_rate ();
1857 state->buffer_size = get_buffer_size ();
1858 state->n_periods = get_nperiods ();
1859 state->input_latency = get_input_latency ();
1860 state->output_latency = get_output_latency ();
1861 state->input_channels = get_input_channels ();
1862 state->output_channels = get_output_channels ();
1863 state->midi_option = get_midi_option ();
1864 state->midi_devices = _midi_devices;
1865 state->use_buffered_io = get_use_buffered_io ();
1866 state->lru = time (NULL) ;
1870 EngineControl::maybe_display_saved_state ()
1872 if (!_have_control) {
1876 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1879 DEBUG_ECONTROL ("Restoring saved state");
1880 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1882 if (!_desired_sample_rate) {
1883 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1885 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1887 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1888 /* call this explicitly because we're ignoring changes to
1889 the controls at this point.
1891 show_buffer_duration ();
1892 input_latency.set_value (state->input_latency);
1893 output_latency.set_value (state->output_latency);
1895 use_buffered_io_button.set_active (state->use_buffered_io);
1897 if (!state->midi_option.empty()) {
1898 midi_option_combo.set_active_text (state->midi_option);
1899 _midi_devices = state->midi_devices;
1902 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1907 EngineControl::get_state ()
1911 XMLNode* root = new XMLNode ("AudioMIDISetup");
1914 if (!states.empty()) {
1915 XMLNode* state_nodes = new XMLNode ("EngineStates");
1917 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1919 XMLNode* node = new XMLNode ("State");
1921 node->add_property ("backend", (*i)->backend);
1922 node->add_property ("driver", (*i)->driver);
1923 node->add_property ("device", (*i)->device);
1924 node->add_property ("input-device", (*i)->input_device);
1925 node->add_property ("output-device", (*i)->output_device);
1926 node->add_property ("sample-rate", (*i)->sample_rate);
1927 node->add_property ("buffer-size", (*i)->buffer_size);
1928 node->add_property ("n-periods", (*i)->n_periods);
1929 node->add_property ("input-latency", (*i)->input_latency);
1930 node->add_property ("output-latency", (*i)->output_latency);
1931 node->add_property ("input-channels", (*i)->input_channels);
1932 node->add_property ("output-channels", (*i)->output_channels);
1933 node->add_property ("active", (*i)->active ? "yes" : "no");
1934 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1935 node->add_property ("midi-option", (*i)->midi_option);
1936 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1938 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1939 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1940 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1941 midi_device_stuff->add_property (X_("name"), (*p)->name);
1942 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1943 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1944 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1945 midi_devices->add_child_nocopy (*midi_device_stuff);
1947 node->add_child_nocopy (*midi_devices);
1949 state_nodes->add_child_nocopy (*node);
1952 root->add_child_nocopy (*state_nodes);
1959 EngineControl::set_default_state ()
1961 vector<string> backend_names;
1962 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1964 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1965 backend_names.push_back ((*b)->name);
1967 backend_combo.set_active_text (backend_names.front());
1969 // We could set default backends per platform etc here
1975 EngineControl::set_state (const XMLNode& root)
1977 XMLNodeList clist, cclist;
1978 XMLNodeConstIterator citer, cciter;
1979 XMLNode const * child;
1980 XMLNode const * grandchild;
1981 XMLProperty const * prop = NULL;
1983 if (root.name() != "AudioMIDISetup") {
1987 clist = root.children();
1991 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1995 if (child->name() != "EngineStates") {
1999 cclist = child->children();
2001 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2002 State state (new StateStruct);
2004 grandchild = *cciter;
2006 if (grandchild->name() != "State") {
2010 if ((prop = grandchild->property ("backend")) == 0) {
2013 state->backend = prop->value ();
2015 if ((prop = grandchild->property ("driver")) == 0) {
2018 state->driver = prop->value ();
2020 if ((prop = grandchild->property ("device")) == 0) {
2023 state->device = prop->value ();
2025 if ((prop = grandchild->property ("input-device")) == 0) {
2028 state->input_device = prop->value ();
2030 if ((prop = grandchild->property ("output-device")) == 0) {
2033 state->output_device = prop->value ();
2035 if ((prop = grandchild->property ("sample-rate")) == 0) {
2038 state->sample_rate = atof (prop->value ());
2040 if ((prop = grandchild->property ("buffer-size")) == 0) {
2043 state->buffer_size = atoi (prop->value ());
2045 if ((prop = grandchild->property ("n-periods")) == 0) {
2046 // optional (new value in 4.5)
2047 state->n_periods = 0;
2049 state->n_periods = atoi (prop->value ());
2052 if ((prop = grandchild->property ("input-latency")) == 0) {
2055 state->input_latency = atoi (prop->value ());
2057 if ((prop = grandchild->property ("output-latency")) == 0) {
2060 state->output_latency = atoi (prop->value ());
2062 if ((prop = grandchild->property ("input-channels")) == 0) {
2065 state->input_channels = atoi (prop->value ());
2067 if ((prop = grandchild->property ("output-channels")) == 0) {
2070 state->output_channels = atoi (prop->value ());
2072 if ((prop = grandchild->property ("active")) == 0) {
2075 state->active = string_is_affirmative (prop->value ());
2077 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2080 state->use_buffered_io = string_is_affirmative (prop->value ());
2082 if ((prop = grandchild->property ("midi-option")) == 0) {
2085 state->midi_option = prop->value ();
2087 state->midi_devices.clear();
2089 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2090 const XMLNodeList mnc = midinode->children();
2091 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2092 if ((*n)->property (X_("name")) == 0
2093 || (*n)->property (X_("enabled")) == 0
2094 || (*n)->property (X_("input-latency")) == 0
2095 || (*n)->property (X_("output-latency")) == 0
2100 MidiDeviceSettings ptr (new MidiDeviceSetting(
2101 (*n)->property (X_("name"))->value (),
2102 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2103 atoi ((*n)->property (X_("input-latency"))->value ()),
2104 atoi ((*n)->property (X_("output-latency"))->value ())
2106 state->midi_devices.push_back (ptr);
2110 if ((prop = grandchild->property ("lru"))) {
2111 state->lru = atoi (prop->value ());
2115 /* remove accumulated duplicates (due to bug in ealier version)
2116 * this can be removed again before release
2118 for (StateList::iterator i = states.begin(); i != states.end();) {
2119 if ((*i)->backend == state->backend &&
2120 (*i)->driver == state->driver &&
2121 (*i)->device == state->device) {
2122 i = states.erase(i);
2129 states.push_back (state);
2133 /* now see if there was an active state and switch the setup to it */
2135 // purge states of backend that are not available in this built
2136 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2137 vector<std::string> backend_names;
2139 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2140 backend_names.push_back((*i)->name);
2142 for (StateList::iterator i = states.begin(); i != states.end();) {
2143 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2144 i = states.erase(i);
2150 states.sort (state_sort_cmp);
2152 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2155 return set_current_state (*i);
2162 EngineControl::set_current_state (const State& state)
2164 DEBUG_ECONTROL ("set_current_state");
2166 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2168 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2169 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2170 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2171 // this shouldn't happen as the invalid backend names should have been
2172 // removed from the list of states.
2176 // now reflect the change in the backend in the GUI so backend_changed will
2177 // do the right thing
2178 backend_combo.set_active_text (state->backend);
2180 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2182 // we don't have control don't restore state
2187 if (!state->driver.empty ()) {
2188 if (!backend->requires_driver_selection ()) {
2189 DEBUG_ECONTROL ("Backend should require driver selection");
2190 // A backend has changed from having driver selection to not having
2191 // it or someone has been manually editing a config file and messed
2196 if (backend->set_driver (state->driver) != 0) {
2197 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2198 // Driver names for a backend have changed and the name in the
2199 // config file is now invalid or support for driver is no longer
2200 // included in the backend
2203 // no need to set the driver_combo as backend_changed will use
2204 // backend->driver_name to set the active driver
2207 if (!state->device.empty ()) {
2208 if (backend->set_device_name (state->device) != 0) {
2210 string_compose ("Unable to set device name %1", state->device));
2211 // device is no longer available on the system
2214 // no need to set active device as it will be picked up in
2215 // via backend_changed ()/set_device_popdown_strings
2218 // backend supports separate input/output devices
2219 if (backend->set_input_device_name (state->input_device) != 0) {
2220 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2221 state->input_device));
2222 // input device is no longer available on the system
2226 if (backend->set_output_device_name (state->output_device) != 0) {
2227 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2228 state->input_device));
2229 // output device is no longer available on the system
2232 // no need to set active devices as it will be picked up in via
2233 // backend_changed ()/set_*_device_popdown_strings
2238 // Now restore the state of the rest of the controls
2240 // We don't use a SignalBlocker as set_current_state is currently only
2241 // called from set_state before any signals are connected. If at some point
2242 // a more general named state mechanism is implemented and
2243 // set_current_state is called while signals are connected then a
2244 // SignalBlocker will need to be instantiated before setting these.
2246 device_combo.set_active_text (state->device);
2247 input_device_combo.set_active_text (state->input_device);
2248 output_device_combo.set_active_text (state->output_device);
2249 if (!_desired_sample_rate) {
2250 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2252 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2253 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2254 input_latency.set_value (state->input_latency);
2255 output_latency.set_value (state->output_latency);
2256 midi_option_combo.set_active_text (state->midi_option);
2257 use_buffered_io_button.set_active (state->use_buffered_io);
2262 EngineControl::push_state_to_backend (bool start)
2264 DEBUG_ECONTROL ("push_state_to_backend");
2265 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2266 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2272 /* figure out what is going to change */
2274 bool restart_required = false;
2275 bool was_running = ARDOUR::AudioEngine::instance()->running();
2276 bool change_driver = false;
2277 bool change_device = false;
2278 bool change_rate = false;
2279 bool change_bufsize = false;
2280 bool change_nperiods = false;
2281 bool change_latency = false;
2282 bool change_channels = false;
2283 bool change_midi = false;
2284 bool change_buffered_io = false;
2286 uint32_t ochan = get_output_channels ();
2287 uint32_t ichan = get_input_channels ();
2289 if (_have_control) {
2291 if (started_at_least_once) {
2293 /* we can control the backend */
2295 if (backend->requires_driver_selection()) {
2296 if (get_driver() != backend->driver_name()) {
2297 change_driver = true;
2301 if (backend->use_separate_input_and_output_devices()) {
2302 if (get_input_device_name() != backend->input_device_name()) {
2303 change_device = true;
2305 if (get_output_device_name() != backend->output_device_name()) {
2306 change_device = true;
2309 if (get_device_name() != backend->device_name()) {
2310 change_device = true;
2314 if (queue_device_changed) {
2315 change_device = true;
2318 if (get_rate() != backend->sample_rate()) {
2322 if (get_buffer_size() != backend->buffer_size()) {
2323 change_bufsize = true;
2326 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2327 && get_nperiods() != backend->period_size()) {
2328 change_nperiods = true;
2331 if (get_midi_option() != backend->midi_option()) {
2335 if (backend->can_use_buffered_io()) {
2336 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2337 change_buffered_io = true;
2341 /* zero-requested channels means "all available" */
2344 ichan = backend->input_channels();
2348 ochan = backend->output_channels();
2351 if (ichan != backend->input_channels()) {
2352 change_channels = true;
2355 if (ochan != backend->output_channels()) {
2356 change_channels = true;
2359 if (get_input_latency() != backend->systemic_input_latency() ||
2360 get_output_latency() != backend->systemic_output_latency()) {
2361 change_latency = true;
2364 /* backend never started, so we have to force a group
2367 change_device = true;
2368 if (backend->requires_driver_selection()) {
2369 change_driver = true;
2372 change_bufsize = true;
2373 change_channels = true;
2374 change_latency = true;
2376 change_buffered_io = backend->can_use_buffered_io();
2377 change_channels = true;
2378 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2383 /* we have no control over the backend, meaning that we can
2384 * only possibly change sample rate and buffer size.
2388 if (get_rate() != backend->sample_rate()) {
2389 change_bufsize = true;
2392 if (get_buffer_size() != backend->buffer_size()) {
2393 change_bufsize = true;
2397 queue_device_changed = false;
2399 if (!_have_control) {
2401 /* We do not have control over the backend, so the best we can
2402 * do is try to change the sample rate and/or bufsize and get
2406 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2410 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2415 backend->set_sample_rate (get_rate());
2418 if (change_bufsize) {
2419 backend->set_buffer_size (get_buffer_size());
2423 if (ARDOUR::AudioEngine::instance()->start ()) {
2424 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2434 /* determine if we need to stop the backend before changing parameters */
2436 if (change_driver || change_device || change_channels || change_nperiods ||
2437 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2438 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2439 change_midi || change_buffered_io ||
2440 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2441 restart_required = true;
2443 restart_required = false;
2448 if (restart_required) {
2449 if (ARDOUR::AudioEngine::instance()->stop()) {
2455 if (change_driver && backend->set_driver (get_driver())) {
2456 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2459 if (backend->use_separate_input_and_output_devices()) {
2460 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2461 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2464 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2465 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2469 if (change_device && backend->set_device_name (get_device_name())) {
2470 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2474 if (change_rate && backend->set_sample_rate (get_rate())) {
2475 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2478 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2479 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2482 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2483 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2487 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2488 if (backend->set_input_channels (get_input_channels())) {
2489 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2492 if (backend->set_output_channels (get_output_channels())) {
2493 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2497 if (change_latency) {
2498 if (backend->set_systemic_input_latency (get_input_latency())) {
2499 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2502 if (backend->set_systemic_output_latency (get_output_latency())) {
2503 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2509 backend->set_midi_option (get_midi_option());
2512 if (change_buffered_io) {
2513 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2517 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2518 if (_measure_midi) {
2519 if (*p == _measure_midi) {
2520 backend->set_midi_device_enabled ((*p)->name, true);
2522 backend->set_midi_device_enabled ((*p)->name, false);
2524 if (backend->can_change_systemic_latency_when_running ()) {
2525 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2526 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2530 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2531 if (backend->can_set_systemic_midi_latencies()) {
2532 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2533 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2538 if (start || (was_running && restart_required)) {
2539 if (ARDOUR::AudioEngine::instance()->start()) {
2550 EngineControl::post_push ()
2552 /* get a pointer to the current state object, creating one if
2556 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2559 state = save_state ();
2565 states.sort (state_sort_cmp);
2569 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2570 (*i)->active = false;
2573 /* mark this one active (to be used next time the dialog is
2577 state->active = true;
2579 if (_have_control) { // XXX
2580 manage_control_app_sensitivity ();
2583 /* schedule a redisplay of MIDI ports */
2584 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2589 EngineControl::get_rate () const
2591 float r = atof (sample_rate_combo.get_active_text ());
2592 /* the string may have been translated with an abbreviation for
2593 * thousands, so use a crude heuristic to fix this.
2603 EngineControl::get_buffer_size () const
2605 string txt = buffer_size_combo.get_active_text ();
2608 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2609 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2610 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2618 EngineControl::get_nperiods () const
2620 string txt = nperiods_combo.get_active_text ();
2621 return atoi (txt.c_str());
2625 EngineControl::get_midi_option () const
2627 return midi_option_combo.get_active_text();
2631 EngineControl::get_use_buffered_io () const
2633 return use_buffered_io_button.get_active();
2637 EngineControl::get_input_channels() const
2639 if (ARDOUR::Profile->get_mixbus()) {
2640 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2641 if (!backend) return 0;
2642 return backend->input_channels();
2644 return (uint32_t) input_channels_adjustment.get_value();
2648 EngineControl::get_output_channels() const
2650 if (ARDOUR::Profile->get_mixbus()) {
2651 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2652 if (!backend) return 0;
2653 return backend->input_channels();
2655 return (uint32_t) output_channels_adjustment.get_value();
2659 EngineControl::get_input_latency() const
2661 return (uint32_t) input_latency_adjustment.get_value();
2665 EngineControl::get_output_latency() const
2667 return (uint32_t) output_latency_adjustment.get_value();
2671 EngineControl::get_backend () const
2673 return backend_combo.get_active_text ();
2677 EngineControl::get_driver () const
2679 if (driver_combo.get_parent()) {
2680 return driver_combo.get_active_text ();
2687 EngineControl::get_device_name () const
2689 return device_combo.get_active_text ();
2693 EngineControl::get_input_device_name () const
2695 return input_device_combo.get_active_text ();
2699 EngineControl::get_output_device_name () const
2701 return output_device_combo.get_active_text ();
2705 EngineControl::control_app_button_clicked ()
2707 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2713 backend->launch_control_app ();
2717 EngineControl::start_stop_button_clicked ()
2719 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2725 if (ARDOUR::AudioEngine::instance()->running()) {
2726 ARDOUR::AudioEngine::instance()->stop ();
2728 if (!ARDOUR_UI::instance()->session_loaded) {
2732 if (!ARDOUR_UI::instance()->session_loaded) {
2733 ArdourDialog::on_response (RESPONSE_OK);
2734 if (Splash::instance()) {
2735 Splash::instance()->pop_front ();
2742 EngineControl::update_devices_button_clicked ()
2744 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2750 if (backend->update_devices()) {
2751 device_list_changed ();
2756 EngineControl::use_buffered_io_button_clicked ()
2758 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2764 bool set_buffered_io = !use_buffered_io_button.get_active();
2765 use_buffered_io_button.set_active (set_buffered_io);
2766 backend->set_use_buffered_io (set_buffered_io);
2770 EngineControl::manage_control_app_sensitivity ()
2772 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2778 string appname = backend->control_app_name();
2780 if (appname.empty()) {
2781 control_app_button.set_sensitive (false);
2783 control_app_button.set_sensitive (true);
2788 EngineControl::set_desired_sample_rate (uint32_t sr)
2790 _desired_sample_rate = sr;
2791 if (ARDOUR::AudioEngine::instance ()->running ()
2792 && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2799 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2801 if (page_num == 0) {
2802 _measure_midi.reset();
2803 update_sensitivity ();
2806 if (page_num == midi_tab) {
2808 refresh_midi_display ();
2811 if (page_num == latency_tab) {
2814 if (ARDOUR::AudioEngine::instance()->running()) {
2819 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2821 /* save any existing latency values */
2823 uint32_t il = (uint32_t) input_latency.get_value ();
2824 uint32_t ol = (uint32_t) input_latency.get_value ();
2826 /* reset to zero so that our new test instance
2827 will be clean of any existing latency measures.
2829 NB. this should really be done by the backend
2830 when stated for latency measurement.
2833 input_latency.set_value (0);
2834 output_latency.set_value (0);
2836 push_state_to_backend (false);
2840 input_latency.set_value (il);
2841 output_latency.set_value (ol);
2844 // This should be done in push_state_to_backend()
2845 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2846 disable_latency_tab ();
2849 enable_latency_tab ();
2853 end_latency_detection ();
2854 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2859 /* latency measurement */
2862 EngineControl::check_audio_latency_measurement ()
2864 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2866 if (mtdm->resolve () < 0) {
2867 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2871 if (mtdm->get_peak () > 0.707f) {
2872 // get_peak() resets the peak-hold in the detector.
2873 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2874 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2878 if (mtdm->err () > 0.3) {
2884 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2886 if (sample_rate == 0) {
2887 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2888 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2892 int frames_total = mtdm->del();
2893 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2895 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2896 _("Detected roundtrip latency: "),
2897 frames_total, frames_total * 1000.0f/sample_rate,
2898 _("Systemic latency: "),
2899 extra, extra * 1000.0f/sample_rate);
2903 if (mtdm->err () > 0.2) {
2905 strcat (buf, _("(signal detection error)"));
2911 strcat (buf, _("(inverted - bad wiring)"));
2915 lm_results.set_markup (string_compose (results_markup, buf));
2918 have_lm_results = true;
2919 end_latency_detection ();
2920 lm_use_button.set_sensitive (true);
2928 EngineControl::check_midi_latency_measurement ()
2930 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2932 if (!mididm->have_signal () || mididm->latency () == 0) {
2933 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2938 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2940 if (sample_rate == 0) {
2941 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2942 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2946 ARDOUR::framecnt_t frames_total = mididm->latency();
2947 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2948 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2949 _("Detected roundtrip latency: "),
2950 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2951 _("Systemic latency: "),
2952 extra, extra * 1000.0f / sample_rate);
2956 if (!mididm->ok ()) {
2958 strcat (buf, _("(averaging)"));
2962 if (mididm->deviation () > 50.0) {
2964 strcat (buf, _("(too large jitter)"));
2966 } else if (mididm->deviation () > 10.0) {
2968 strcat (buf, _("(large jitter)"));
2972 have_lm_results = true;
2973 end_latency_detection ();
2974 lm_use_button.set_sensitive (true);
2975 lm_results.set_markup (string_compose (results_markup, buf));
2977 } else if (mididm->processed () > 400) {
2978 have_lm_results = false;
2979 end_latency_detection ();
2980 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2984 lm_results.set_markup (string_compose (results_markup, buf));
2990 EngineControl::start_latency_detection ()
2992 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2993 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2995 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2996 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2997 if (_measure_midi) {
2998 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3000 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3002 lm_measure_label.set_text (_("Cancel"));
3003 have_lm_results = false;
3004 lm_use_button.set_sensitive (false);
3005 lm_input_channel_combo.set_sensitive (false);
3006 lm_output_channel_combo.set_sensitive (false);
3012 EngineControl::end_latency_detection ()
3014 latency_timeout.disconnect ();
3015 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3016 lm_measure_label.set_text (_("Measure"));
3017 if (!have_lm_results) {
3018 lm_use_button.set_sensitive (false);
3020 lm_input_channel_combo.set_sensitive (true);
3021 lm_output_channel_combo.set_sensitive (true);
3026 EngineControl::latency_button_clicked ()
3029 start_latency_detection ();
3031 end_latency_detection ();
3036 EngineControl::latency_back_button_clicked ()
3038 ARDOUR::AudioEngine::instance()->stop(true);
3039 notebook.set_current_page(0);
3043 EngineControl::use_latency_button_clicked ()
3045 if (_measure_midi) {
3046 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3050 ARDOUR::framecnt_t frames_total = mididm->latency();
3051 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3052 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3053 _measure_midi->input_latency = one_way;
3054 _measure_midi->output_latency = one_way;
3055 notebook.set_current_page (midi_tab);
3057 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3063 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3064 one_way = std::max (0., one_way);
3066 input_latency_adjustment.set_value (one_way);
3067 output_latency_adjustment.set_value (one_way);
3069 /* back to settings page */
3070 notebook.set_current_page (0);
3075 EngineControl::on_delete_event (GdkEventAny* ev)
3077 if (notebook.get_current_page() == 2) {
3078 /* currently on latency tab - be sure to clean up */
3079 end_latency_detection ();
3081 return ArdourDialog::on_delete_event (ev);
3085 EngineControl::engine_running ()
3087 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3090 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3091 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3093 if (backend->can_set_period_size ()) {
3094 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3097 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3098 connect_disconnect_button.show();
3100 started_at_least_once = true;
3101 if (_have_control) {
3102 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3104 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3106 update_sensitivity();
3110 EngineControl::engine_stopped ()
3112 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3115 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3116 connect_disconnect_button.show();
3118 if (_have_control) {
3119 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3121 engine_status.set_markup(X_(""));
3124 update_sensitivity();
3128 EngineControl::device_list_changed ()
3130 if (ignore_device_changes) {
3133 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3135 midi_option_changed();
3139 EngineControl::connect_disconnect_click()
3141 if (ARDOUR::AudioEngine::instance()->running()) {
3144 if (!ARDOUR_UI::instance()->session_loaded) {
3148 if (!ARDOUR_UI::instance()->session_loaded) {
3149 ArdourDialog::on_response (RESPONSE_OK);
3150 if (Splash::instance()) {
3151 Splash::instance()->pop_front ();
3158 EngineControl::calibrate_audio_latency ()
3160 _measure_midi.reset ();
3161 have_lm_results = false;
3162 lm_use_button.set_sensitive (false);
3163 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3164 notebook.set_current_page (latency_tab);
3168 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3171 have_lm_results = false;
3172 lm_use_button.set_sensitive (false);
3173 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3174 notebook.set_current_page (latency_tab);
3178 EngineControl::configure_midi_devices ()
3180 notebook.set_current_page (midi_tab);