2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
91 , lm_measure_label (_("Measure"))
92 , lm_use_button (_("Use results"))
93 , lm_back_button (_("Back to settings ... (ignore results)"))
94 , lm_button_audio (_("Calibrate Audio"))
96 , have_lm_results (false)
98 , midi_back_button (_("Back to settings"))
100 , ignore_device_changes (0)
101 , _desired_sample_rate (0)
102 , started_at_least_once (false)
103 , queue_device_changed (false)
104 , _have_control (true)
107 using namespace Notebook_Helpers;
108 vector<string> backend_names;
110 AttachOptions xopt = AttachOptions (FILL|EXPAND);
113 set_name (X_("AudioMIDISetup"));
115 /* the backend combo is the one thing that is ALWAYS visible */
117 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
119 if (backends.empty()) {
120 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
122 throw failed_constructor ();
125 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
126 backend_names.push_back ((*b)->name);
129 set_popdown_strings (backend_combo, backend_names);
131 /* setup basic packing characteristics for the table used on the main
132 * tab of the notebook
135 basic_packer.set_spacings (6);
136 basic_packer.set_border_width (12);
137 basic_packer.set_homogeneous (false);
141 basic_hbox.pack_start (basic_packer, false, false);
143 /* latency measurement tab */
145 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
148 lm_table.set_row_spacings (12);
149 lm_table.set_col_spacings (6);
150 lm_table.set_homogeneous (false);
152 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
155 lm_preamble.set_width_chars (60);
156 lm_preamble.set_line_wrap (true);
157 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
159 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162 Gtk::Label* preamble;
163 preamble = manage (new Label);
164 preamble->set_width_chars (60);
165 preamble->set_line_wrap (true);
166 preamble->set_markup (_("Select two channels below and connect them using a cable."));
168 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
171 label = manage (new Label (_("Output channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_output_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
179 label = manage (new Label (_("Input channel")));
180 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
182 misc_align = manage (new Alignment (0.0, 0.5));
183 misc_align->add (lm_input_channel_combo);
184 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
187 lm_measure_label.set_padding (10, 10);
188 lm_measure_button.add (lm_measure_label);
189 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
190 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
191 lm_back_button_signal = lm_back_button.signal_clicked().connect(
192 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
194 lm_use_button.set_sensitive (false);
196 /* Increase the default spacing around the labels of these three
202 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
203 l->set_padding (10, 10);
206 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
207 l->set_padding (10, 10);
210 preamble = manage (new Label);
211 preamble->set_width_chars (60);
212 preamble->set_line_wrap (true);
213 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
214 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 preamble = manage (new Label);
218 preamble->set_width_chars (60);
219 preamble->set_line_wrap (true);
220 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
221 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 ++row; // skip a row in the table
224 ++row; // skip a row in the table
226 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 ++row; // skip a row in the table
229 ++row; // skip a row in the table
231 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
235 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
237 lm_vbox.set_border_width (12);
238 lm_vbox.pack_start (lm_table, false, false);
240 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
244 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
245 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
246 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
247 notebook.set_border_width (12);
249 notebook.set_show_tabs (false);
250 notebook.show_all ();
252 notebook.set_name ("SettingsNotebook");
254 /* packup the notebook */
256 get_vbox()->set_border_width (12);
257 get_vbox()->pack_start (notebook);
259 /* need a special function to print "all available channels" when the
260 * channel counts hit zero.
263 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
264 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
266 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
267 midi_devices_button.set_name ("generic button");
268 midi_devices_button.set_can_focus(true);
270 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
271 control_app_button.set_name ("generic button");
272 control_app_button.set_can_focus(true);
273 manage_control_app_sensitivity ();
275 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
276 start_stop_button.set_sensitive (false);
277 start_stop_button.set_name ("generic button");
278 start_stop_button.set_can_focus(true);
280 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
281 update_devices_button.set_sensitive (false);
282 update_devices_button.set_name ("generic button");
283 update_devices_button.set_can_focus(true);
285 use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
286 use_buffered_io_button.set_sensitive (false);
287 use_buffered_io_button.set_name ("generic button");
288 use_buffered_io_button.set_can_focus(true);
290 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
291 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
293 /* Pick up any existing audio setup configuration, if appropriate */
295 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
297 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
298 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
299 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
300 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
303 if (!set_state (*audio_setup)) {
304 set_default_state ();
307 set_default_state ();
310 update_sensitivity ();
311 connect_changed_signals ();
313 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
315 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
317 connect_disconnect_button.set_no_show_all();
318 use_buffered_io_button.set_no_show_all();
319 update_devices_button.set_no_show_all();
320 start_stop_button.set_no_show_all();
321 midi_devices_button.set_no_show_all();
325 EngineControl::connect_changed_signals ()
327 backend_combo_connection = backend_combo.signal_changed ().connect (
328 sigc::mem_fun (*this, &EngineControl::backend_changed));
329 driver_combo_connection = driver_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::driver_changed));
331 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
333 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
335 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
337 device_combo_connection = device_combo.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::device_changed));
339 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
342 input_device_combo_connection = input_device_combo.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::input_device_changed));
344 output_device_combo_connection = output_device_combo.signal_changed ().connect (
345 sigc::mem_fun (*this, &EngineControl::output_device_changed));
347 input_latency_connection = input_latency.signal_changed ().connect (
348 sigc::mem_fun (*this, &EngineControl::parameter_changed));
349 output_latency_connection = output_latency.signal_changed ().connect (
350 sigc::mem_fun (*this, &EngineControl::parameter_changed));
351 input_channels_connection = input_channels.signal_changed ().connect (
352 sigc::mem_fun (*this, &EngineControl::parameter_changed));
353 output_channels_connection = output_channels.signal_changed ().connect (
354 sigc::mem_fun (*this, &EngineControl::parameter_changed));
358 EngineControl::block_changed_signals ()
360 if (block_signals++ == 0) {
361 DEBUG_ECONTROL ("Blocking changed signals");
362 backend_combo_connection.block ();
363 driver_combo_connection.block ();
364 sample_rate_combo_connection.block ();
365 buffer_size_combo_connection.block ();
366 nperiods_combo_connection.block ();
367 device_combo_connection.block ();
368 input_device_combo_connection.block ();
369 output_device_combo_connection.block ();
370 midi_option_combo_connection.block ();
371 input_latency_connection.block ();
372 output_latency_connection.block ();
373 input_channels_connection.block ();
374 output_channels_connection.block ();
379 EngineControl::unblock_changed_signals ()
381 if (--block_signals == 0) {
382 DEBUG_ECONTROL ("Unblocking changed signals");
383 backend_combo_connection.unblock ();
384 driver_combo_connection.unblock ();
385 sample_rate_combo_connection.unblock ();
386 buffer_size_combo_connection.unblock ();
387 nperiods_combo_connection.unblock ();
388 device_combo_connection.unblock ();
389 input_device_combo_connection.unblock ();
390 output_device_combo_connection.unblock ();
391 midi_option_combo_connection.unblock ();
392 input_latency_connection.unblock ();
393 output_latency_connection.unblock ();
394 input_channels_connection.unblock ();
395 output_channels_connection.unblock ();
399 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
400 const std::string& reason)
401 : ec (engine_control)
404 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
405 ec.block_changed_signals ();
408 EngineControl::SignalBlocker::~SignalBlocker ()
410 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
411 ec.unblock_changed_signals ();
415 EngineControl::on_show ()
417 ArdourDialog::on_show ();
418 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
419 // re-check _have_control (jackd running) see #6041
423 ok_button->grab_focus();
427 EngineControl::start_engine ()
429 if (push_state_to_backend(true) != 0) {
430 MessageDialog msg(*this,
431 ARDOUR::AudioEngine::instance()->get_last_backend_error());
439 EngineControl::stop_engine (bool for_latency)
441 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
442 MessageDialog msg(*this,
443 ARDOUR::AudioEngine::instance()->get_last_backend_error());
451 EngineControl::on_response (int response_id)
453 ArdourDialog::on_response (response_id);
455 switch (response_id) {
457 if (!start_engine()) {
462 #ifdef PLATFORM_WINDOWS
464 // But if there's no session open, this can produce
465 // a long gap when nothing appears to be happening.
466 // Let's show the splash image while we're waiting.
467 if (!ARDOUR_COMMAND_LINE::no_splash) {
468 if (ARDOUR_UI::instance()) {
469 if (!ARDOUR_UI::instance()->session_loaded) {
470 ARDOUR_UI::instance()->show_splash();
476 case RESPONSE_DELETE_EVENT: {
478 ev.type = GDK_BUTTON_PRESS;
480 on_delete_event((GdkEventAny*)&ev);
483 case RESPONSE_CANCEL:
484 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
485 ARDOUR_UI::instance()->check_audioengine(*this);
494 EngineControl::build_notebook ()
497 AttachOptions xopt = AttachOptions (FILL|EXPAND);
499 /* clear the table */
501 Gtkmm2ext::container_clear (basic_vbox);
502 Gtkmm2ext::container_clear (basic_packer);
504 if (control_app_button.get_parent()) {
505 control_app_button.get_parent()->remove (control_app_button);
508 label = manage (left_aligned_label (_("Audio System:")));
509 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
510 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
512 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
513 engine_status.show();
515 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
516 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
517 basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
519 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
520 lm_button_audio.set_name ("generic button");
521 lm_button_audio.set_can_focus(true);
524 build_full_control_notebook ();
526 build_no_control_notebook ();
529 basic_vbox.pack_start (basic_hbox, false, false);
532 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
533 basic_vbox.show_all ();
538 EngineControl::build_full_control_notebook ()
540 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
543 using namespace Notebook_Helpers;
545 vector<string> strings;
546 AttachOptions xopt = AttachOptions (FILL|EXPAND);
547 int row = 1; // row zero == backend combo
549 /* start packing it up */
551 if (backend->requires_driver_selection()) {
552 label = manage (left_aligned_label (_("Driver:")));
553 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
554 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
558 if (backend->use_separate_input_and_output_devices()) {
559 label = manage (left_aligned_label (_("Input Device:")));
560 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
561 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
563 label = manage (left_aligned_label (_("Output Device:")));
564 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
565 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
567 // reset so it isn't used in state comparisons
568 device_combo.set_active_text ("");
570 label = manage (left_aligned_label (_("Device:")));
571 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
572 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 // reset these so they don't get used in state comparisons
575 input_device_combo.set_active_text ("");
576 output_device_combo.set_active_text ("");
579 label = manage (left_aligned_label (_("Sample rate:")));
580 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
581 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
585 label = manage (left_aligned_label (_("Buffer size:")));
586 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
587 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
588 buffer_size_duration_label.set_alignment (0.0); /* left-align */
589 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
591 int ctrl_btn_span = 1;
592 if (backend->can_set_period_size ()) {
594 label = manage (left_aligned_label (_("Periods:")));
595 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
596 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
600 /* button spans 2 or 3 rows */
602 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
605 input_channels.set_name ("InputChannels");
606 input_channels.set_flags (Gtk::CAN_FOCUS);
607 input_channels.set_digits (0);
608 input_channels.set_wrap (false);
609 output_channels.set_editable (true);
611 if (!ARDOUR::Profile->get_mixbus()) {
612 label = manage (left_aligned_label (_("Input Channels:")));
613 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
614 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
618 output_channels.set_name ("OutputChannels");
619 output_channels.set_flags (Gtk::CAN_FOCUS);
620 output_channels.set_digits (0);
621 output_channels.set_wrap (false);
622 output_channels.set_editable (true);
624 if (!ARDOUR::Profile->get_mixbus()) {
625 label = manage (left_aligned_label (_("Output Channels:")));
626 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
627 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
631 input_latency.set_name ("InputLatency");
632 input_latency.set_flags (Gtk::CAN_FOCUS);
633 input_latency.set_digits (0);
634 input_latency.set_wrap (false);
635 input_latency.set_editable (true);
637 label = manage (left_aligned_label (_("Hardware input latency:")));
638 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
639 basic_packer.attach (input_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);
644 output_latency.set_name ("OutputLatency");
645 output_latency.set_flags (Gtk::CAN_FOCUS);
646 output_latency.set_digits (0);
647 output_latency.set_wrap (false);
648 output_latency.set_editable (true);
650 label = manage (left_aligned_label (_("Hardware output latency:")));
651 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
652 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
653 label = manage (left_aligned_label (_("samples")));
654 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
656 /* button spans 2 rows */
658 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
661 label = manage (left_aligned_label (_("MIDI System:")));
662 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
663 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
664 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
669 EngineControl::build_no_control_notebook ()
671 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
674 using namespace Notebook_Helpers;
676 vector<string> strings;
677 AttachOptions xopt = AttachOptions (FILL|EXPAND);
678 int row = 1; // row zero == backend combo
679 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
681 label = manage (new Label);
682 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
683 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
686 if (backend->can_change_sample_rate_when_running()) {
687 label = manage (left_aligned_label (_("Sample rate:")));
688 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
689 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
693 if (backend->can_change_buffer_size_when_running()) {
694 label = manage (left_aligned_label (_("Buffer size:")));
695 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
696 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
697 buffer_size_duration_label.set_alignment (0.0); /* left-align */
698 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
702 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
706 EngineControl::~EngineControl ()
708 ignore_changes = true;
712 EngineControl::disable_latency_tab ()
714 vector<string> empty;
715 set_popdown_strings (lm_output_channel_combo, empty);
716 set_popdown_strings (lm_input_channel_combo, empty);
717 lm_measure_button.set_sensitive (false);
718 lm_use_button.set_sensitive (false);
722 EngineControl::enable_latency_tab ()
724 vector<string> outputs;
725 vector<string> inputs;
727 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
728 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
729 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
731 if (!ARDOUR::AudioEngine::instance()->running()) {
732 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
733 notebook.set_current_page (0);
737 else if (inputs.empty() || outputs.empty()) {
738 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
739 notebook.set_current_page (0);
744 lm_back_button_signal.disconnect();
746 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
749 lm_back_button_signal = lm_back_button.signal_clicked().connect(
750 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
754 set_popdown_strings (lm_output_channel_combo, outputs);
755 lm_output_channel_combo.set_active_text (outputs.front());
756 lm_output_channel_combo.set_sensitive (true);
758 set_popdown_strings (lm_input_channel_combo, inputs);
759 lm_input_channel_combo.set_active_text (inputs.front());
760 lm_input_channel_combo.set_sensitive (true);
762 lm_measure_button.set_sensitive (true);
766 EngineControl::setup_midi_tab_for_backend ()
768 string backend = backend_combo.get_active_text ();
770 Gtkmm2ext::container_clear (midi_vbox);
772 midi_vbox.set_border_width (12);
773 midi_device_table.set_border_width (12);
775 if (backend == "JACK") {
776 setup_midi_tab_for_jack ();
779 midi_vbox.pack_start (midi_device_table, true, true);
780 midi_vbox.pack_start (midi_back_button, false, false);
781 midi_vbox.show_all ();
785 EngineControl::update_sensitivity ()
787 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
789 ok_button->set_sensitive (false);
790 start_stop_button.set_sensitive (false);
795 size_t devices_available = 0;
797 if (backend->use_separate_input_and_output_devices ()) {
798 devices_available += get_popdown_string_count (input_device_combo);
799 devices_available += get_popdown_string_count (output_device_combo);
801 devices_available += get_popdown_string_count (device_combo);
804 if (devices_available == 0) {
806 input_latency.set_sensitive (false);
807 output_latency.set_sensitive (false);
808 input_channels.set_sensitive (false);
809 output_channels.set_sensitive (false);
811 input_latency.set_sensitive (true);
812 output_latency.set_sensitive (true);
813 input_channels.set_sensitive (true);
814 output_channels.set_sensitive (true);
817 if (get_popdown_string_count (buffer_size_combo) > 0) {
818 if (!ARDOUR::AudioEngine::instance()->running()) {
819 buffer_size_combo.set_sensitive (valid);
820 } else if (backend->can_change_sample_rate_when_running()) {
821 buffer_size_combo.set_sensitive (valid || !_have_control);
825 * Currently there is no way to manually stop the
826 * engine in order to re-configure it.
827 * This needs to remain sensitive for now.
829 * (it's also handy to implicily
830 * re-start the engine)
832 buffer_size_combo.set_sensitive (true);
834 buffer_size_combo.set_sensitive (false);
838 buffer_size_combo.set_sensitive (false);
842 if (get_popdown_string_count (sample_rate_combo) > 0) {
843 if (!ARDOUR::AudioEngine::instance()->running()) {
844 sample_rate_combo.set_sensitive (true);
846 sample_rate_combo.set_sensitive (false);
849 sample_rate_combo.set_sensitive (false);
853 if (get_popdown_string_count (nperiods_combo) > 0) {
854 if (!ARDOUR::AudioEngine::instance()->running()) {
855 nperiods_combo.set_sensitive (true);
857 nperiods_combo.set_sensitive (false);
860 nperiods_combo.set_sensitive (false);
864 start_stop_button.set_sensitive(true);
865 start_stop_button.show();
866 if (ARDOUR::AudioEngine::instance()->running()) {
867 start_stop_button.set_text("Stop");
868 update_devices_button.set_sensitive(false);
869 use_buffered_io_button.set_sensitive(false);
871 if (backend->can_request_update_devices()) {
872 update_devices_button.show();
874 update_devices_button.hide();
876 if (backend->can_use_buffered_io()) {
877 use_buffered_io_button.show();
879 use_buffered_io_button.hide();
881 start_stop_button.set_text("Start");
882 update_devices_button.set_sensitive(true);
883 use_buffered_io_button.set_sensitive(true);
886 update_devices_button.set_sensitive(false);
887 update_devices_button.hide();
888 use_buffered_io_button.set_sensitive(false);
889 use_buffered_io_button.hide();
890 start_stop_button.set_sensitive(false);
891 start_stop_button.hide();
894 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
895 input_device_combo.set_sensitive (false);
896 output_device_combo.set_sensitive (false);
897 device_combo.set_sensitive (false);
898 driver_combo.set_sensitive (false);
900 input_device_combo.set_sensitive (true);
901 output_device_combo.set_sensitive (true);
902 device_combo.set_sensitive (true);
903 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
904 driver_combo.set_sensitive (true);
906 driver_combo.set_sensitive (false);
910 if (valid || !_have_control) {
911 ok_button->set_sensitive (true);
913 ok_button->set_sensitive (false);
918 EngineControl::setup_midi_tab_for_jack ()
923 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
925 device->input_latency = a->get_value();
927 device->output_latency = a->get_value();
932 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
933 b->set_active (!b->get_active());
934 device->enabled = b->get_active();
935 refresh_midi_display(device->name);
939 EngineControl::refresh_midi_display (std::string focus)
941 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
945 AttachOptions xopt = AttachOptions (FILL|EXPAND);
948 Gtkmm2ext::container_clear (midi_device_table);
950 midi_device_table.set_spacings (6);
952 l = manage (new Label);
953 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
954 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
955 l->set_alignment (0.5, 0.5);
959 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
960 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
961 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
962 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
964 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
965 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
966 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
967 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
970 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
975 bool enabled = (*p)->enabled;
977 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
978 m->set_name ("midi device");
979 m->set_can_focus (Gtk::CAN_FOCUS);
980 m->add_events (Gdk::BUTTON_RELEASE_MASK);
981 m->set_active (enabled);
982 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
983 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
984 if ((*p)->name == focus) {
988 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
989 s = manage (new Gtk::SpinButton (*a));
990 a->set_value ((*p)->input_latency);
991 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
992 s->set_sensitive (_can_set_midi_latencies && enabled);
993 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
995 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
996 s = manage (new Gtk::SpinButton (*a));
997 a->set_value ((*p)->output_latency);
998 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
999 s->set_sensitive (_can_set_midi_latencies && enabled);
1000 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1002 b = manage (new Button (_("Calibrate")));
1003 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1004 b->set_sensitive (_can_set_midi_latencies && enabled);
1005 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1012 EngineControl::backend_changed ()
1014 SignalBlocker blocker (*this, "backend_changed");
1015 string backend_name = backend_combo.get_active_text();
1016 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1018 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1019 /* eh? setting the backend failed... how ? */
1020 /* A: stale config contains a backend that does not exist in current build */
1024 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1026 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1029 setup_midi_tab_for_backend ();
1030 _midi_devices.clear();
1032 if (backend->requires_driver_selection()) {
1033 if (set_driver_popdown_strings ()) {
1037 /* this will change the device text which will cause a call to
1038 * device changed which will set up parameters
1043 update_midi_options ();
1045 connect_disconnect_button.hide();
1047 midi_option_changed();
1049 started_at_least_once = false;
1051 /* changing the backend implies stopping the engine
1052 * ARDOUR::AudioEngine() may or may not emit this signal
1053 * depending on previous engine state
1055 engine_stopped (); // set "active/inactive"
1057 if (!_have_control) {
1058 // set settings from backend that we do have control over
1059 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1062 if (_have_control && !ignore_changes) {
1063 // set driver & devices
1064 State state = get_matching_state (backend_combo.get_active_text());
1066 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1067 set_current_state (state);
1071 if (!ignore_changes) {
1072 maybe_display_saved_state ();
1077 EngineControl::update_midi_options ()
1079 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1080 vector<string> midi_options = backend->enumerate_midi_options();
1082 if (midi_options.size() == 1) {
1083 /* only contains the "none" option */
1084 midi_option_combo.set_sensitive (false);
1086 if (_have_control) {
1087 set_popdown_strings (midi_option_combo, midi_options);
1088 midi_option_combo.set_active_text (midi_options.front());
1089 midi_option_combo.set_sensitive (true);
1091 midi_option_combo.set_sensitive (false);
1097 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1099 if (ARDOUR::Profile->get_mixbus()) {
1103 uint32_t cnt = (uint32_t) sb->get_value();
1105 sb->set_text (_("all available channels"));
1108 snprintf (buf, sizeof (buf), "%d", cnt);
1114 // @return true if there are drivers available
1116 EngineControl::set_driver_popdown_strings ()
1118 DEBUG_ECONTROL ("set_driver_popdown_strings");
1119 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1120 vector<string> drivers = backend->enumerate_drivers();
1122 if (drivers.empty ()) {
1123 // This is an error...?
1127 string current_driver = backend->driver_name ();
1129 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1131 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1134 current_driver = drivers.front ();
1137 set_popdown_strings (driver_combo, drivers);
1139 string_compose ("driver_combo.set_active_text: %1", current_driver));
1140 driver_combo.set_active_text (current_driver);
1145 EngineControl::get_default_device(const string& current_device_name,
1146 const vector<string>& available_devices)
1148 // If the current device is available, use it as default
1149 if (std::find (available_devices.begin (),
1150 available_devices.end (),
1151 current_device_name) != available_devices.end ()) {
1153 return current_device_name;
1156 using namespace ARDOUR;
1158 string default_device_name =
1159 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1161 vector<string>::const_iterator i;
1163 // If there is a "Default" device available, use it
1164 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1165 if (*i == default_device_name) {
1170 string none_device_name =
1171 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1173 // Use the first device that isn't "None"
1174 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1175 if (*i != none_device_name) {
1180 // Use "None" if there are no other available
1181 return available_devices.front();
1184 // @return true if there are devices available
1186 EngineControl::set_device_popdown_strings ()
1188 DEBUG_ECONTROL ("set_device_popdown_strings");
1189 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1190 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1192 /* NOTE: Ardour currently does not display the "available" field of the
1195 * Doing so would require a different GUI widget than the combo
1196 * box/popdown that we currently use, since it has no way to list
1197 * items that are not selectable. Something more like a popup menu,
1198 * which could have unselectable items, would be appropriate.
1201 vector<string> available_devices;
1203 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1204 available_devices.push_back (i->name);
1207 if (available_devices.empty ()) {
1211 set_popdown_strings (device_combo, available_devices);
1213 std::string default_device =
1214 get_default_device(backend->device_name(), available_devices);
1217 string_compose ("set device_combo active text: %1", default_device));
1219 device_combo.set_active_text(default_device);
1223 // @return true if there are input devices available
1225 EngineControl::set_input_device_popdown_strings ()
1227 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1228 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1229 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1231 vector<string> available_devices;
1233 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1234 available_devices.push_back (i->name);
1237 if (available_devices.empty()) {
1241 set_popdown_strings (input_device_combo, available_devices);
1243 std::string default_device =
1244 get_default_device(backend->input_device_name(), available_devices);
1247 string_compose ("set input_device_combo active text: %1", default_device));
1248 input_device_combo.set_active_text(default_device);
1252 // @return true if there are output devices available
1254 EngineControl::set_output_device_popdown_strings ()
1256 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1257 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1258 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1260 vector<string> available_devices;
1262 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1263 available_devices.push_back (i->name);
1266 if (available_devices.empty()) {
1270 set_popdown_strings (output_device_combo, available_devices);
1272 std::string default_device =
1273 get_default_device(backend->output_device_name(), available_devices);
1276 string_compose ("set output_device_combo active text: %1", default_device));
1277 output_device_combo.set_active_text(default_device);
1282 EngineControl::list_devices ()
1284 DEBUG_ECONTROL ("list_devices");
1285 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1288 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1290 bool devices_available = false;
1292 if (backend->use_separate_input_and_output_devices ()) {
1293 bool input_devices_available = set_input_device_popdown_strings ();
1294 bool output_devices_available = set_output_device_popdown_strings ();
1295 devices_available = input_devices_available || output_devices_available;
1297 devices_available = set_device_popdown_strings ();
1300 if (devices_available) {
1303 device_combo.clear();
1304 input_device_combo.clear();
1305 output_device_combo.clear();
1307 update_sensitivity ();
1311 EngineControl::driver_changed ()
1313 SignalBlocker blocker (*this, "driver_changed");
1314 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1317 backend->set_driver (driver_combo.get_active_text());
1320 // TODO load LRU device(s) for backend + driver combo
1322 if (!ignore_changes) {
1323 maybe_display_saved_state ();
1328 EngineControl::get_sample_rates_for_all_devices ()
1330 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1331 ARDOUR::AudioEngine::instance ()->current_backend ();
1332 vector<float> all_rates;
1334 if (backend->use_separate_input_and_output_devices ()) {
1335 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1337 all_rates = backend->available_sample_rates (get_device_name ());
1343 EngineControl::get_default_sample_rates ()
1345 vector<float> rates;
1346 rates.push_back (8000.0f);
1347 rates.push_back (16000.0f);
1348 rates.push_back (32000.0f);
1349 rates.push_back (44100.0f);
1350 rates.push_back (48000.0f);
1351 rates.push_back (88200.0f);
1352 rates.push_back (96000.0f);
1353 rates.push_back (192000.0f);
1354 rates.push_back (384000.0f);
1359 EngineControl::set_samplerate_popdown_strings ()
1361 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1362 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1367 if (_have_control) {
1368 sr = get_sample_rates_for_all_devices ();
1370 sr = get_default_sample_rates ();
1373 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1374 s.push_back (rate_as_string (*x));
1375 if (*x == _desired_sample_rate) {
1380 set_popdown_strings (sample_rate_combo, s);
1383 if (desired.empty ()) {
1384 float new_active_sr = backend->default_sample_rate ();
1386 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1387 new_active_sr = sr.front ();
1390 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1392 sample_rate_combo.set_active_text (desired);
1396 update_sensitivity ();
1400 EngineControl::get_buffer_sizes_for_all_devices ()
1402 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1403 ARDOUR::AudioEngine::instance ()->current_backend ();
1404 vector<uint32_t> all_sizes;
1406 if (backend->use_separate_input_and_output_devices ()) {
1407 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1409 all_sizes = backend->available_buffer_sizes (get_device_name ());
1415 EngineControl::get_default_buffer_sizes ()
1417 vector<uint32_t> sizes;
1418 sizes.push_back (8);
1419 sizes.push_back (16);
1420 sizes.push_back (32);
1421 sizes.push_back (64);
1422 sizes.push_back (128);
1423 sizes.push_back (256);
1424 sizes.push_back (512);
1425 sizes.push_back (1024);
1426 sizes.push_back (2048);
1427 sizes.push_back (4096);
1428 sizes.push_back (8192);
1433 EngineControl::set_buffersize_popdown_strings ()
1435 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1436 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1437 vector<uint32_t> bs;
1440 if (_have_control) {
1441 bs = get_buffer_sizes_for_all_devices ();
1442 } else if (backend->can_change_buffer_size_when_running()) {
1443 bs = get_default_buffer_sizes ();
1446 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1447 s.push_back (bufsize_as_string (*x));
1450 uint32_t previous_size = 0;
1451 if (!buffer_size_combo.get_active_text().empty()) {
1452 previous_size = get_buffer_size ();
1455 set_popdown_strings (buffer_size_combo, s);
1459 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1460 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1463 buffer_size_combo.set_active_text(s.front());
1465 uint32_t period = backend->buffer_size();
1466 if (0 == period && backend->use_separate_input_and_output_devices()) {
1467 period = backend->default_buffer_size(get_input_device_name());
1469 if (0 == period && backend->use_separate_input_and_output_devices()) {
1470 period = backend->default_buffer_size(get_output_device_name());
1472 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1473 period = backend->default_buffer_size(get_device_name());
1476 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1478 show_buffer_duration ();
1480 update_sensitivity ();
1484 EngineControl::set_nperiods_popdown_strings ()
1486 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1487 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1488 vector<uint32_t> np;
1491 if (backend->can_set_period_size()) {
1492 np = backend->available_period_sizes (get_driver());
1495 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1496 s.push_back (nperiods_as_string (*x));
1499 set_popdown_strings (nperiods_combo, s);
1502 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1505 update_sensitivity ();
1509 EngineControl::device_changed ()
1511 SignalBlocker blocker (*this, "device_changed");
1512 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1515 string device_name_in;
1516 string device_name_out; // only used if backend support separate I/O devices
1518 if (backend->use_separate_input_and_output_devices()) {
1519 device_name_in = get_input_device_name ();
1520 device_name_out = get_output_device_name ();
1522 device_name_in = get_device_name ();
1525 /* we set the backend-device to query various device related intormation.
1526 * This has the side effect that backend->device_name() will match
1527 * the device_name and 'change_device' will never be true.
1528 * so work around this by setting...
1530 if (backend->use_separate_input_and_output_devices()) {
1531 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1532 queue_device_changed = true;
1535 if (device_name_in != backend->device_name()) {
1536 queue_device_changed = true;
1540 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1541 if (backend->use_separate_input_and_output_devices()) {
1542 backend->set_input_device_name (device_name_in);
1543 backend->set_output_device_name (device_name_out);
1545 backend->set_device_name(device_name_in);
1549 /* don't allow programmatic change to combos to cause a
1550 recursive call to this method.
1552 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1554 set_samplerate_popdown_strings ();
1555 set_buffersize_popdown_strings ();
1556 set_nperiods_popdown_strings ();
1558 /* TODO set min + max channel counts here */
1560 manage_control_app_sensitivity ();
1563 /* pick up any saved state for this device */
1565 if (!ignore_changes) {
1566 maybe_display_saved_state ();
1571 EngineControl::input_device_changed ()
1573 DEBUG_ECONTROL ("input_device_changed");
1578 EngineControl::output_device_changed ()
1580 DEBUG_ECONTROL ("output_device_changed");
1585 EngineControl::bufsize_as_string (uint32_t sz)
1587 /* Translators: "samples" is always plural here, so no
1588 need for plural+singular forms.
1591 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1596 EngineControl::nperiods_as_string (uint32_t np)
1599 snprintf (buf, sizeof (buf), "%u", np);
1605 EngineControl::sample_rate_changed ()
1607 DEBUG_ECONTROL ("sample_rate_changed");
1608 /* reset the strings for buffer size to show the correct msec value
1609 (reflecting the new sample rate).
1612 show_buffer_duration ();
1617 EngineControl::buffer_size_changed ()
1619 DEBUG_ECONTROL ("buffer_size_changed");
1620 show_buffer_duration ();
1624 EngineControl::nperiods_changed ()
1626 DEBUG_ECONTROL ("nperiods_changed");
1627 show_buffer_duration ();
1631 EngineControl::show_buffer_duration ()
1633 DEBUG_ECONTROL ("show_buffer_duration");
1634 /* buffer sizes - convert from just samples to samples + msecs for
1635 * the displayed string
1638 string bs_text = buffer_size_combo.get_active_text ();
1639 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1640 uint32_t rate = get_rate();
1642 /* Except for ALSA and Dummy backends, we don't know the number of periods
1643 * per cycle and settings.
1645 * jack1 vs jack2 have different default latencies since jack2 start
1646 * in async-mode unless --sync is given which adds an extra cycle
1647 * of latency. The value is not known if jackd is started externally..
1649 * So just display the period size, that's also what
1650 * ARDOUR_UI::update_sample_rate() does for the status bar.
1651 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1652 * but still, that's the buffer period, not [round-trip] latency)
1655 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1656 buffer_size_duration_label.set_text (buf);
1660 EngineControl::midi_option_changed ()
1662 DEBUG_ECONTROL ("midi_option_changed");
1663 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1666 backend->set_midi_option (get_midi_option());
1668 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1670 //_midi_devices.clear(); // TODO merge with state-saved settings..
1671 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1672 std::vector<MidiDeviceSettings> new_devices;
1674 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1675 MidiDeviceSettings mds = find_midi_device (i->name);
1676 if (i->available && !mds) {
1677 uint32_t input_latency = 0;
1678 uint32_t output_latency = 0;
1679 if (_can_set_midi_latencies) {
1680 input_latency = backend->systemic_midi_input_latency (i->name);
1681 output_latency = backend->systemic_midi_output_latency (i->name);
1683 bool enabled = backend->midi_device_enabled (i->name);
1684 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1685 new_devices.push_back (ptr);
1686 } else if (i->available) {
1687 new_devices.push_back (mds);
1690 _midi_devices = new_devices;
1692 if (_midi_devices.empty()) {
1693 midi_devices_button.hide ();
1695 midi_devices_button.show ();
1700 EngineControl::parameter_changed ()
1704 EngineControl::State
1705 EngineControl::get_matching_state (const string& backend)
1707 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1708 if ((*i)->backend == backend) {
1715 EngineControl::State
1716 EngineControl::get_matching_state (
1717 const string& backend,
1718 const string& driver,
1719 const string& device)
1721 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1722 if ((*i)->backend == backend &&
1723 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1731 EngineControl::State
1732 EngineControl::get_matching_state (
1733 const string& backend,
1734 const string& driver,
1735 const string& input_device,
1736 const string& output_device)
1738 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1739 if ((*i)->backend == backend &&
1740 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1748 EngineControl::State
1749 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1751 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1754 if (backend->use_separate_input_and_output_devices ()) {
1755 return get_matching_state (backend_combo.get_active_text(),
1756 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1757 input_device_combo.get_active_text(),
1758 output_device_combo.get_active_text());
1760 return get_matching_state (backend_combo.get_active_text(),
1761 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1762 device_combo.get_active_text());
1766 return get_matching_state (backend_combo.get_active_text(),
1768 device_combo.get_active_text());
1771 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1772 const EngineControl::State& state2)
1774 if (state1->backend == state2->backend &&
1775 state1->driver == state2->driver &&
1776 state1->device == state2->device &&
1777 state1->input_device == state2->input_device &&
1778 state1->output_device == state2->output_device) {
1785 EngineControl::state_sort_cmp (const State &a, const State &b) {
1789 else if (b->active) {
1793 return a->lru < b->lru;
1797 EngineControl::State
1798 EngineControl::save_state ()
1802 if (!_have_control) {
1803 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1805 state->lru = time (NULL) ;
1808 state.reset(new StateStruct);
1809 state->backend = get_backend ();
1811 state.reset(new StateStruct);
1812 store_state (state);
1815 for (StateList::iterator i = states.begin(); i != states.end();) {
1816 if (equivalent_states (*i, state)) {
1817 i = states.erase(i);
1823 states.push_back (state);
1825 states.sort (state_sort_cmp);
1831 EngineControl::store_state (State state)
1833 state->backend = get_backend ();
1834 state->driver = get_driver ();
1835 state->device = get_device_name ();
1836 state->input_device = get_input_device_name ();
1837 state->output_device = get_output_device_name ();
1838 state->sample_rate = get_rate ();
1839 state->buffer_size = get_buffer_size ();
1840 state->n_periods = get_nperiods ();
1841 state->input_latency = get_input_latency ();
1842 state->output_latency = get_output_latency ();
1843 state->input_channels = get_input_channels ();
1844 state->output_channels = get_output_channels ();
1845 state->midi_option = get_midi_option ();
1846 state->midi_devices = _midi_devices;
1847 state->use_buffered_io = get_use_buffered_io ();
1848 state->lru = time (NULL) ;
1852 EngineControl::maybe_display_saved_state ()
1854 if (!_have_control) {
1858 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1861 DEBUG_ECONTROL ("Restoring saved state");
1862 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1864 if (!_desired_sample_rate) {
1865 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1867 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1869 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1870 /* call this explicitly because we're ignoring changes to
1871 the controls at this point.
1873 show_buffer_duration ();
1874 input_latency.set_value (state->input_latency);
1875 output_latency.set_value (state->output_latency);
1877 use_buffered_io_button.set_active (state->use_buffered_io);
1879 if (!state->midi_option.empty()) {
1880 midi_option_combo.set_active_text (state->midi_option);
1881 _midi_devices = state->midi_devices;
1884 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1889 EngineControl::get_state ()
1891 LocaleGuard lg (X_("C"));
1893 XMLNode* root = new XMLNode ("AudioMIDISetup");
1896 if (!states.empty()) {
1897 XMLNode* state_nodes = new XMLNode ("EngineStates");
1899 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1901 XMLNode* node = new XMLNode ("State");
1903 node->add_property ("backend", (*i)->backend);
1904 node->add_property ("driver", (*i)->driver);
1905 node->add_property ("device", (*i)->device);
1906 node->add_property ("input-device", (*i)->input_device);
1907 node->add_property ("output-device", (*i)->output_device);
1908 node->add_property ("sample-rate", (*i)->sample_rate);
1909 node->add_property ("buffer-size", (*i)->buffer_size);
1910 node->add_property ("n-periods", (*i)->n_periods);
1911 node->add_property ("input-latency", (*i)->input_latency);
1912 node->add_property ("output-latency", (*i)->output_latency);
1913 node->add_property ("input-channels", (*i)->input_channels);
1914 node->add_property ("output-channels", (*i)->output_channels);
1915 node->add_property ("active", (*i)->active ? "yes" : "no");
1916 node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1917 node->add_property ("midi-option", (*i)->midi_option);
1918 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1920 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1921 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1922 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1923 midi_device_stuff->add_property (X_("name"), (*p)->name);
1924 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1925 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1926 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1927 midi_devices->add_child_nocopy (*midi_device_stuff);
1929 node->add_child_nocopy (*midi_devices);
1931 state_nodes->add_child_nocopy (*node);
1934 root->add_child_nocopy (*state_nodes);
1941 EngineControl::set_default_state ()
1943 vector<string> backend_names;
1944 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1946 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1947 backend_names.push_back ((*b)->name);
1949 backend_combo.set_active_text (backend_names.front());
1951 // We could set default backends per platform etc here
1957 EngineControl::set_state (const XMLNode& root)
1959 XMLNodeList clist, cclist;
1960 XMLNodeConstIterator citer, cciter;
1962 XMLNode* grandchild;
1963 XMLProperty* prop = NULL;
1965 fprintf (stderr, "EngineControl::set_state\n");
1967 if (root.name() != "AudioMIDISetup") {
1971 clist = root.children();
1975 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1979 if (child->name() != "EngineStates") {
1983 cclist = child->children();
1985 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1986 State state (new StateStruct);
1988 grandchild = *cciter;
1990 if (grandchild->name() != "State") {
1994 if ((prop = grandchild->property ("backend")) == 0) {
1997 state->backend = prop->value ();
1999 if ((prop = grandchild->property ("driver")) == 0) {
2002 state->driver = prop->value ();
2004 if ((prop = grandchild->property ("device")) == 0) {
2007 state->device = prop->value ();
2009 if ((prop = grandchild->property ("input-device")) == 0) {
2012 state->input_device = prop->value ();
2014 if ((prop = grandchild->property ("output-device")) == 0) {
2017 state->output_device = prop->value ();
2019 if ((prop = grandchild->property ("sample-rate")) == 0) {
2022 state->sample_rate = atof (prop->value ());
2024 if ((prop = grandchild->property ("buffer-size")) == 0) {
2027 state->buffer_size = atoi (prop->value ());
2029 if ((prop = grandchild->property ("n-periods")) == 0) {
2030 // optional (new value in 4.5)
2031 state->n_periods = 0;
2033 state->n_periods = atoi (prop->value ());
2036 if ((prop = grandchild->property ("input-latency")) == 0) {
2039 state->input_latency = atoi (prop->value ());
2041 if ((prop = grandchild->property ("output-latency")) == 0) {
2044 state->output_latency = atoi (prop->value ());
2046 if ((prop = grandchild->property ("input-channels")) == 0) {
2049 state->input_channels = atoi (prop->value ());
2051 if ((prop = grandchild->property ("output-channels")) == 0) {
2054 state->output_channels = atoi (prop->value ());
2056 if ((prop = grandchild->property ("active")) == 0) {
2059 state->active = string_is_affirmative (prop->value ());
2061 if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2064 state->use_buffered_io = string_is_affirmative (prop->value ());
2066 if ((prop = grandchild->property ("midi-option")) == 0) {
2069 state->midi_option = prop->value ();
2071 state->midi_devices.clear();
2073 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2074 const XMLNodeList mnc = midinode->children();
2075 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2076 if ((*n)->property (X_("name")) == 0
2077 || (*n)->property (X_("enabled")) == 0
2078 || (*n)->property (X_("input-latency")) == 0
2079 || (*n)->property (X_("output-latency")) == 0
2084 MidiDeviceSettings ptr (new MidiDeviceSetting(
2085 (*n)->property (X_("name"))->value (),
2086 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2087 atoi ((*n)->property (X_("input-latency"))->value ()),
2088 atoi ((*n)->property (X_("output-latency"))->value ())
2090 state->midi_devices.push_back (ptr);
2094 if ((prop = grandchild->property ("lru"))) {
2095 state->lru = atoi (prop->value ());
2099 /* remove accumulated duplicates (due to bug in ealier version)
2100 * this can be removed again before release
2102 for (StateList::iterator i = states.begin(); i != states.end();) {
2103 if ((*i)->backend == state->backend &&
2104 (*i)->driver == state->driver &&
2105 (*i)->device == state->device) {
2106 i = states.erase(i);
2113 states.push_back (state);
2117 /* now see if there was an active state and switch the setup to it */
2119 // purge states of backend that are not available in this built
2120 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2121 vector<std::string> backend_names;
2123 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2124 backend_names.push_back((*i)->name);
2126 for (StateList::iterator i = states.begin(); i != states.end();) {
2127 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2128 i = states.erase(i);
2134 states.sort (state_sort_cmp);
2136 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2139 return set_current_state (*i);
2146 EngineControl::set_current_state (const State& state)
2148 DEBUG_ECONTROL ("set_current_state");
2150 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2152 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2153 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2154 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2155 // this shouldn't happen as the invalid backend names should have been
2156 // removed from the list of states.
2160 // now reflect the change in the backend in the GUI so backend_changed will
2161 // do the right thing
2162 backend_combo.set_active_text (state->backend);
2164 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2166 // we don't have control don't restore state
2171 if (!state->driver.empty ()) {
2172 if (!backend->requires_driver_selection ()) {
2173 DEBUG_ECONTROL ("Backend should require driver selection");
2174 // A backend has changed from having driver selection to not having
2175 // it or someone has been manually editing a config file and messed
2180 if (backend->set_driver (state->driver) != 0) {
2181 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2182 // Driver names for a backend have changed and the name in the
2183 // config file is now invalid or support for driver is no longer
2184 // included in the backend
2187 // no need to set the driver_combo as backend_changed will use
2188 // backend->driver_name to set the active driver
2191 if (!state->device.empty ()) {
2192 if (backend->set_device_name (state->device) != 0) {
2194 string_compose ("Unable to set device name %1", state->device));
2195 // device is no longer available on the system
2198 // no need to set active device as it will be picked up in
2199 // via backend_changed ()/set_device_popdown_strings
2202 // backend supports separate input/output devices
2203 if (backend->set_input_device_name (state->input_device) != 0) {
2204 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2205 state->input_device));
2206 // input device is no longer available on the system
2210 if (backend->set_output_device_name (state->output_device) != 0) {
2211 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2212 state->input_device));
2213 // output device is no longer available on the system
2216 // no need to set active devices as it will be picked up in via
2217 // backend_changed ()/set_*_device_popdown_strings
2222 // Now restore the state of the rest of the controls
2224 // We don't use a SignalBlocker as set_current_state is currently only
2225 // called from set_state before any signals are connected. If at some point
2226 // a more general named state mechanism is implemented and
2227 // set_current_state is called while signals are connected then a
2228 // SignalBlocker will need to be instantiated before setting these.
2230 device_combo.set_active_text (state->device);
2231 input_device_combo.set_active_text (state->input_device);
2232 output_device_combo.set_active_text (state->output_device);
2233 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2234 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2235 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2236 input_latency.set_value (state->input_latency);
2237 output_latency.set_value (state->output_latency);
2238 midi_option_combo.set_active_text (state->midi_option);
2239 use_buffered_io_button.set_active (state->use_buffered_io);
2244 EngineControl::push_state_to_backend (bool start)
2246 DEBUG_ECONTROL ("push_state_to_backend");
2247 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2248 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2254 /* figure out what is going to change */
2256 bool restart_required = false;
2257 bool was_running = ARDOUR::AudioEngine::instance()->running();
2258 bool change_driver = false;
2259 bool change_device = false;
2260 bool change_rate = false;
2261 bool change_bufsize = false;
2262 bool change_nperiods = false;
2263 bool change_latency = false;
2264 bool change_channels = false;
2265 bool change_midi = false;
2266 bool change_buffered_io = false;
2268 uint32_t ochan = get_output_channels ();
2269 uint32_t ichan = get_input_channels ();
2271 if (_have_control) {
2273 if (started_at_least_once) {
2275 /* we can control the backend */
2277 if (backend->requires_driver_selection()) {
2278 if (get_driver() != backend->driver_name()) {
2279 change_driver = true;
2283 if (backend->use_separate_input_and_output_devices()) {
2284 if (get_input_device_name() != backend->input_device_name()) {
2285 change_device = true;
2287 if (get_output_device_name() != backend->output_device_name()) {
2288 change_device = true;
2291 if (get_device_name() != backend->device_name()) {
2292 change_device = true;
2296 if (queue_device_changed) {
2297 change_device = true;
2300 if (get_rate() != backend->sample_rate()) {
2304 if (get_buffer_size() != backend->buffer_size()) {
2305 change_bufsize = true;
2308 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2309 && get_nperiods() != backend->period_size()) {
2310 change_nperiods = true;
2313 if (get_midi_option() != backend->midi_option()) {
2317 if (backend->can_use_buffered_io()) {
2318 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2319 change_buffered_io = true;
2323 /* zero-requested channels means "all available" */
2326 ichan = backend->input_channels();
2330 ochan = backend->output_channels();
2333 if (ichan != backend->input_channels()) {
2334 change_channels = true;
2337 if (ochan != backend->output_channels()) {
2338 change_channels = true;
2341 if (get_input_latency() != backend->systemic_input_latency() ||
2342 get_output_latency() != backend->systemic_output_latency()) {
2343 change_latency = true;
2346 /* backend never started, so we have to force a group
2349 change_device = true;
2350 if (backend->requires_driver_selection()) {
2351 change_driver = true;
2354 change_bufsize = true;
2355 change_channels = true;
2356 change_latency = true;
2358 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2363 /* we have no control over the backend, meaning that we can
2364 * only possibly change sample rate and buffer size.
2368 if (get_rate() != backend->sample_rate()) {
2369 change_bufsize = true;
2372 if (get_buffer_size() != backend->buffer_size()) {
2373 change_bufsize = true;
2377 queue_device_changed = false;
2379 if (!_have_control) {
2381 /* We do not have control over the backend, so the best we can
2382 * do is try to change the sample rate and/or bufsize and get
2386 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2390 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2395 backend->set_sample_rate (get_rate());
2398 if (change_bufsize) {
2399 backend->set_buffer_size (get_buffer_size());
2403 if (ARDOUR::AudioEngine::instance()->start ()) {
2404 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2414 /* determine if we need to stop the backend before changing parameters */
2416 if (change_driver || change_device || change_channels || change_nperiods ||
2417 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2418 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2420 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2421 restart_required = true;
2423 restart_required = false;
2428 if (restart_required) {
2429 if (ARDOUR::AudioEngine::instance()->stop()) {
2435 if (change_driver && backend->set_driver (get_driver())) {
2436 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2439 if (backend->use_separate_input_and_output_devices()) {
2440 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2441 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2444 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2445 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2449 if (change_device && backend->set_device_name (get_device_name())) {
2450 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2454 if (change_rate && backend->set_sample_rate (get_rate())) {
2455 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2458 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2459 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2462 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2463 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2467 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2468 if (backend->set_input_channels (get_input_channels())) {
2469 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2472 if (backend->set_output_channels (get_output_channels())) {
2473 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2477 if (change_latency) {
2478 if (backend->set_systemic_input_latency (get_input_latency())) {
2479 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2482 if (backend->set_systemic_output_latency (get_output_latency())) {
2483 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2489 backend->set_midi_option (get_midi_option());
2492 if (change_buffered_io) {
2493 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2497 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2498 if (_measure_midi) {
2499 if (*p == _measure_midi) {
2500 backend->set_midi_device_enabled ((*p)->name, true);
2502 backend->set_midi_device_enabled ((*p)->name, false);
2504 if (backend->can_change_systemic_latency_when_running ()) {
2505 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2506 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2510 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2511 if (backend->can_set_systemic_midi_latencies()) {
2512 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2513 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2518 if (start || (was_running && restart_required)) {
2519 if (ARDOUR::AudioEngine::instance()->start()) {
2530 EngineControl::post_push ()
2532 /* get a pointer to the current state object, creating one if
2536 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2539 state = save_state ();
2545 states.sort (state_sort_cmp);
2549 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2550 (*i)->active = false;
2553 /* mark this one active (to be used next time the dialog is
2557 state->active = true;
2559 if (_have_control) { // XXX
2560 manage_control_app_sensitivity ();
2563 /* schedule a redisplay of MIDI ports */
2564 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2569 EngineControl::get_rate () const
2571 float r = atof (sample_rate_combo.get_active_text ());
2572 /* the string may have been translated with an abbreviation for
2573 * thousands, so use a crude heuristic to fix this.
2583 EngineControl::get_buffer_size () const
2585 string txt = buffer_size_combo.get_active_text ();
2588 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2589 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2590 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2598 EngineControl::get_nperiods () const
2600 string txt = nperiods_combo.get_active_text ();
2601 return atoi (txt.c_str());
2605 EngineControl::get_midi_option () const
2607 return midi_option_combo.get_active_text();
2611 EngineControl::get_use_buffered_io () const
2613 return use_buffered_io_button.get_active();
2617 EngineControl::get_input_channels() const
2619 if (ARDOUR::Profile->get_mixbus()) {
2620 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2621 if (!backend) return 0;
2622 return backend->input_channels();
2624 return (uint32_t) input_channels_adjustment.get_value();
2628 EngineControl::get_output_channels() const
2630 if (ARDOUR::Profile->get_mixbus()) {
2631 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2632 if (!backend) return 0;
2633 return backend->input_channels();
2635 return (uint32_t) output_channels_adjustment.get_value();
2639 EngineControl::get_input_latency() const
2641 return (uint32_t) input_latency_adjustment.get_value();
2645 EngineControl::get_output_latency() const
2647 return (uint32_t) output_latency_adjustment.get_value();
2651 EngineControl::get_backend () const
2653 return backend_combo.get_active_text ();
2657 EngineControl::get_driver () const
2659 if (driver_combo.get_parent()) {
2660 return driver_combo.get_active_text ();
2667 EngineControl::get_device_name () const
2669 return device_combo.get_active_text ();
2673 EngineControl::get_input_device_name () const
2675 return input_device_combo.get_active_text ();
2679 EngineControl::get_output_device_name () const
2681 return output_device_combo.get_active_text ();
2685 EngineControl::control_app_button_clicked ()
2687 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2693 backend->launch_control_app ();
2697 EngineControl::start_stop_button_clicked ()
2699 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2705 if (ARDOUR::AudioEngine::instance()->running()) {
2706 ARDOUR::AudioEngine::instance()->stop ();
2713 EngineControl::update_devices_button_clicked ()
2715 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2721 if (backend->update_devices()) {
2722 device_list_changed ();
2727 EngineControl::use_buffered_io_button_clicked ()
2729 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2735 bool set_buffered_io = !use_buffered_io_button.get_active();
2736 use_buffered_io_button.set_active (set_buffered_io);
2737 backend->set_use_buffered_io (set_buffered_io);
2741 EngineControl::manage_control_app_sensitivity ()
2743 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2749 string appname = backend->control_app_name();
2751 if (appname.empty()) {
2752 control_app_button.set_sensitive (false);
2754 control_app_button.set_sensitive (true);
2759 EngineControl::set_desired_sample_rate (uint32_t sr)
2761 _desired_sample_rate = sr;
2766 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2768 if (page_num == 0) {
2769 cancel_button->set_sensitive (true);
2770 _measure_midi.reset();
2771 update_sensitivity ();
2773 cancel_button->set_sensitive (false);
2774 ok_button->set_sensitive (false);
2777 if (page_num == midi_tab) {
2779 refresh_midi_display ();
2782 if (page_num == latency_tab) {
2785 if (ARDOUR::AudioEngine::instance()->running()) {
2790 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2792 /* save any existing latency values */
2794 uint32_t il = (uint32_t) input_latency.get_value ();
2795 uint32_t ol = (uint32_t) input_latency.get_value ();
2797 /* reset to zero so that our new test instance
2798 will be clean of any existing latency measures.
2800 NB. this should really be done by the backend
2801 when stated for latency measurement.
2804 input_latency.set_value (0);
2805 output_latency.set_value (0);
2807 push_state_to_backend (false);
2811 input_latency.set_value (il);
2812 output_latency.set_value (ol);
2815 // This should be done in push_state_to_backend()
2816 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2817 disable_latency_tab ();
2820 enable_latency_tab ();
2824 end_latency_detection ();
2825 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2830 /* latency measurement */
2833 EngineControl::check_audio_latency_measurement ()
2835 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2837 if (mtdm->resolve () < 0) {
2838 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2842 if (mtdm->get_peak () > 0.707f) {
2843 // get_peak() resets the peak-hold in the detector.
2844 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2845 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2849 if (mtdm->err () > 0.3) {
2855 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2857 if (sample_rate == 0) {
2858 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2859 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2863 int frames_total = mtdm->del();
2864 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2866 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2867 _("Detected roundtrip latency: "),
2868 frames_total, frames_total * 1000.0f/sample_rate,
2869 _("Systemic latency: "),
2870 extra, extra * 1000.0f/sample_rate);
2874 if (mtdm->err () > 0.2) {
2876 strcat (buf, _("(signal detection error)"));
2882 strcat (buf, _("(inverted - bad wiring)"));
2886 lm_results.set_markup (string_compose (results_markup, buf));
2889 have_lm_results = true;
2890 end_latency_detection ();
2891 lm_use_button.set_sensitive (true);
2899 EngineControl::check_midi_latency_measurement ()
2901 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2903 if (!mididm->have_signal () || mididm->latency () == 0) {
2904 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2909 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2911 if (sample_rate == 0) {
2912 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2913 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2917 ARDOUR::framecnt_t frames_total = mididm->latency();
2918 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2919 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2920 _("Detected roundtrip latency: "),
2921 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2922 _("Systemic latency: "),
2923 extra, extra * 1000.0f / sample_rate);
2927 if (!mididm->ok ()) {
2929 strcat (buf, _("(averaging)"));
2933 if (mididm->deviation () > 50.0) {
2935 strcat (buf, _("(too large jitter)"));
2937 } else if (mididm->deviation () > 10.0) {
2939 strcat (buf, _("(large jitter)"));
2943 have_lm_results = true;
2944 end_latency_detection ();
2945 lm_use_button.set_sensitive (true);
2946 lm_results.set_markup (string_compose (results_markup, buf));
2948 } else if (mididm->processed () > 400) {
2949 have_lm_results = false;
2950 end_latency_detection ();
2951 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2955 lm_results.set_markup (string_compose (results_markup, buf));
2961 EngineControl::start_latency_detection ()
2963 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2964 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2966 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2967 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2968 if (_measure_midi) {
2969 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2971 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2973 lm_measure_label.set_text (_("Cancel"));
2974 have_lm_results = false;
2975 lm_use_button.set_sensitive (false);
2976 lm_input_channel_combo.set_sensitive (false);
2977 lm_output_channel_combo.set_sensitive (false);
2983 EngineControl::end_latency_detection ()
2985 latency_timeout.disconnect ();
2986 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2987 lm_measure_label.set_text (_("Measure"));
2988 if (!have_lm_results) {
2989 lm_use_button.set_sensitive (false);
2991 lm_input_channel_combo.set_sensitive (true);
2992 lm_output_channel_combo.set_sensitive (true);
2997 EngineControl::latency_button_clicked ()
3000 start_latency_detection ();
3002 end_latency_detection ();
3007 EngineControl::latency_back_button_clicked ()
3009 ARDOUR::AudioEngine::instance()->stop(true);
3010 notebook.set_current_page(0);
3014 EngineControl::use_latency_button_clicked ()
3016 if (_measure_midi) {
3017 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3021 ARDOUR::framecnt_t frames_total = mididm->latency();
3022 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3023 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3024 _measure_midi->input_latency = one_way;
3025 _measure_midi->output_latency = one_way;
3026 notebook.set_current_page (midi_tab);
3028 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3034 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3035 one_way = std::max (0., one_way);
3037 input_latency_adjustment.set_value (one_way);
3038 output_latency_adjustment.set_value (one_way);
3040 /* back to settings page */
3041 notebook.set_current_page (0);
3046 EngineControl::on_delete_event (GdkEventAny* ev)
3048 if (notebook.get_current_page() == 2) {
3049 /* currently on latency tab - be sure to clean up */
3050 end_latency_detection ();
3052 return ArdourDialog::on_delete_event (ev);
3056 EngineControl::engine_running ()
3058 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3061 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3062 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3064 if (backend->can_set_period_size ()) {
3065 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3068 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3069 connect_disconnect_button.show();
3071 started_at_least_once = true;
3072 if (_have_control) {
3073 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3075 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3077 update_sensitivity();
3081 EngineControl::engine_stopped ()
3083 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3086 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3087 connect_disconnect_button.show();
3089 if (_have_control) {
3090 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3092 engine_status.set_markup(X_(""));
3095 update_sensitivity();
3099 EngineControl::device_list_changed ()
3101 if (ignore_device_changes) {
3104 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3106 midi_option_changed();
3110 EngineControl::connect_disconnect_click()
3112 if (ARDOUR::AudioEngine::instance()->running()) {
3120 EngineControl::calibrate_audio_latency ()
3122 _measure_midi.reset ();
3123 have_lm_results = false;
3124 lm_use_button.set_sensitive (false);
3125 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3126 notebook.set_current_page (latency_tab);
3130 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3133 have_lm_results = false;
3134 lm_use_button.set_sensitive (false);
3135 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3136 notebook.set_current_page (latency_tab);
3140 EngineControl::configure_midi_devices ()
3142 notebook.set_current_page (midi_tab);