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.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
53 #include "ardour_ui.h"
54 #include "engine_dialog.h"
55 #include "gui_thread.h"
61 using namespace Gtkmm2ext;
64 using namespace ARDOUR_UI_UTILS;
66 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
68 static const unsigned int midi_tab = 2;
69 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
71 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
73 EngineControl::EngineControl ()
74 : ArdourDialog (_("Audio/MIDI Setup"))
77 , input_latency_adjustment (0, 0, 99999, 1)
78 , input_latency (input_latency_adjustment)
79 , output_latency_adjustment (0, 0, 99999, 1)
80 , output_latency (output_latency_adjustment)
81 , input_channels_adjustment (0, 0, 256, 1)
82 , input_channels (input_channels_adjustment)
83 , output_channels_adjustment (0, 0, 256, 1)
84 , output_channels (output_channels_adjustment)
85 , ports_adjustment (128, 8, 1024, 1, 16)
86 , ports_spinner (ports_adjustment)
87 , control_app_button (_("Device Control Panel"))
88 , midi_devices_button (_("Midi Device Setup"))
89 , start_stop_button (_("Stop"))
90 , update_devices_button (_("Refresh Devices"))
91 , 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 , _desired_sample_rate (0)
101 , started_at_least_once (false)
102 , queue_device_changed (false)
105 using namespace Notebook_Helpers;
106 vector<string> backend_names;
108 AttachOptions xopt = AttachOptions (FILL|EXPAND);
111 set_name (X_("AudioMIDISetup"));
113 /* the backend combo is the one thing that is ALWAYS visible */
115 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
117 if (backends.empty()) {
118 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));
120 throw failed_constructor ();
123 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
124 backend_names.push_back ((*b)->name);
127 set_popdown_strings (backend_combo, backend_names);
129 /* setup basic packing characteristics for the table used on the main
130 * tab of the notebook
133 basic_packer.set_spacings (6);
134 basic_packer.set_border_width (12);
135 basic_packer.set_homogeneous (false);
139 basic_hbox.pack_start (basic_packer, false, false);
141 /* latency measurement tab */
143 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
146 lm_table.set_row_spacings (12);
147 lm_table.set_col_spacings (6);
148 lm_table.set_homogeneous (false);
150 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
153 lm_preamble.set_width_chars (60);
154 lm_preamble.set_line_wrap (true);
155 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
157 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
160 Gtk::Label* preamble;
161 preamble = manage (new Label);
162 preamble->set_width_chars (60);
163 preamble->set_line_wrap (true);
164 preamble->set_markup (_("Select two channels below and connect them using a cable."));
166 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
169 label = manage (new Label (_("Output channel")));
170 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
172 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
173 misc_align->add (lm_output_channel_combo);
174 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
177 label = manage (new Label (_("Input channel")));
178 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
180 misc_align = manage (new Alignment (0.0, 0.5));
181 misc_align->add (lm_input_channel_combo);
182 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
185 lm_measure_label.set_padding (10, 10);
186 lm_measure_button.add (lm_measure_label);
187 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
188 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
189 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
191 lm_use_button.set_sensitive (false);
193 /* Increase the default spacing around the labels of these three
199 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
200 l->set_padding (10, 10);
203 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
204 l->set_padding (10, 10);
207 preamble = manage (new Label);
208 preamble->set_width_chars (60);
209 preamble->set_line_wrap (true);
210 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
211 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
214 preamble = manage (new Label);
215 preamble->set_width_chars (60);
216 preamble->set_line_wrap (true);
217 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
218 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220 ++row; // skip a row in the table
221 ++row; // skip a row in the table
223 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 ++row; // skip a row in the table
226 ++row; // skip a row in the table
228 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
234 lm_vbox.set_border_width (12);
235 lm_vbox.pack_start (lm_table, false, false);
237 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
241 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
242 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
243 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
244 notebook.set_border_width (12);
246 notebook.set_show_tabs (false);
247 notebook.show_all ();
249 notebook.set_name ("SettingsNotebook");
251 /* packup the notebook */
253 get_vbox()->set_border_width (12);
254 get_vbox()->pack_start (notebook);
256 /* need a special function to print "all available channels" when the
257 * channel counts hit zero.
260 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
261 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
263 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
264 midi_devices_button.set_sensitive (false);
265 midi_devices_button.set_name ("generic button");
266 midi_devices_button.set_can_focus(true);
268 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
269 control_app_button.set_name ("generic button");
270 control_app_button.set_can_focus(true);
271 manage_control_app_sensitivity ();
273 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
274 start_stop_button.set_sensitive (false);
275 start_stop_button.set_name ("generic button");
276 start_stop_button.set_can_focus(true);
278 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
279 update_devices_button.set_sensitive (false);
280 update_devices_button.set_name ("generic button");
281 update_devices_button.set_can_focus(true);
283 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
284 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
286 /* Pick up any existing audio setup configuration, if appropriate */
288 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
290 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
291 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
292 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
293 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
296 if (!set_state (*audio_setup)) {
297 set_default_state ();
300 set_default_state ();
303 connect_changed_signals ();
305 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
307 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
308 connect_disconnect_button.set_no_show_all();
313 EngineControl::connect_changed_signals ()
315 backend_combo_connection = backend_combo.signal_changed ().connect (
316 sigc::mem_fun (*this, &EngineControl::backend_changed));
317 driver_combo_connection = driver_combo.signal_changed ().connect (
318 sigc::mem_fun (*this, &EngineControl::driver_changed));
319 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
320 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
321 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
322 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
323 device_combo_connection = device_combo.signal_changed ().connect (
324 sigc::mem_fun (*this, &EngineControl::device_changed));
325 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
326 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
328 input_device_combo_connection = input_device_combo.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::input_device_changed));
330 output_device_combo_connection = output_device_combo.signal_changed ().connect (
331 sigc::mem_fun (*this, &EngineControl::output_device_changed));
333 input_latency_connection = input_latency.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::parameter_changed));
335 output_latency_connection = output_latency.signal_changed ().connect (
336 sigc::mem_fun (*this, &EngineControl::parameter_changed));
337 input_channels_connection = input_channels.signal_changed ().connect (
338 sigc::mem_fun (*this, &EngineControl::parameter_changed));
339 output_channels_connection = output_channels.signal_changed ().connect (
340 sigc::mem_fun (*this, &EngineControl::parameter_changed));
344 EngineControl::block_changed_signals ()
346 if (block_signals++ == 0) {
347 DEBUG_ECONTROL ("Blocking changed signals");
348 backend_combo_connection.block ();
349 driver_combo_connection.block ();
350 sample_rate_combo_connection.block ();
351 buffer_size_combo_connection.block ();
352 device_combo_connection.block ();
353 input_device_combo_connection.block ();
354 output_device_combo_connection.block ();
355 midi_option_combo_connection.block ();
356 input_latency_connection.block ();
357 output_latency_connection.block ();
358 input_channels_connection.block ();
359 output_channels_connection.block ();
364 EngineControl::unblock_changed_signals ()
366 if (--block_signals == 0) {
367 DEBUG_ECONTROL ("Unblocking changed signals");
368 backend_combo_connection.unblock ();
369 driver_combo_connection.unblock ();
370 sample_rate_combo_connection.unblock ();
371 buffer_size_combo_connection.unblock ();
372 device_combo_connection.unblock ();
373 input_device_combo_connection.unblock ();
374 output_device_combo_connection.unblock ();
375 midi_option_combo_connection.unblock ();
376 input_latency_connection.unblock ();
377 output_latency_connection.unblock ();
378 input_channels_connection.unblock ();
379 output_channels_connection.unblock ();
383 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
384 const std::string& reason)
385 : ec (engine_control)
388 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
389 ec.block_changed_signals ();
392 EngineControl::SignalBlocker::~SignalBlocker ()
394 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
395 ec.unblock_changed_signals ();
399 EngineControl::on_show ()
401 ArdourDialog::on_show ();
402 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
403 // re-check _have_control (jackd running) see #6041
407 ok_button->grab_focus();
411 EngineControl::on_response (int response_id)
413 ArdourDialog::on_response (response_id);
415 switch (response_id) {
417 #ifdef PLATFORM_WINDOWS
418 // For some reason we don't understand, 'hide()'
419 // needs to get called first in Windows
422 // But if there's no session open, this can produce
423 // a long gap when nothing appears to be happening.
424 // Let's show the splash image while we're waiting.
425 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
426 if ( ARDOUR_UI::instance() ) {
427 if ( !ARDOUR_UI::instance()->session_loaded ) {
428 ARDOUR_UI::instance()->show_splash();
432 push_state_to_backend (true);
435 push_state_to_backend (true);
439 case RESPONSE_DELETE_EVENT:
442 ev.type = GDK_BUTTON_PRESS;
444 on_delete_event ((GdkEventAny*) &ev);
453 EngineControl::build_notebook ()
456 AttachOptions xopt = AttachOptions (FILL|EXPAND);
458 /* clear the table */
460 Gtkmm2ext::container_clear (basic_vbox);
461 Gtkmm2ext::container_clear (basic_packer);
463 if (control_app_button.get_parent()) {
464 control_app_button.get_parent()->remove (control_app_button);
467 label = manage (left_aligned_label (_("Audio System:")));
468 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
469 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
471 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
472 engine_status.show();
474 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
475 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
477 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
478 lm_button_audio.set_name ("generic button");
479 lm_button_audio.set_can_focus(true);
482 build_full_control_notebook ();
484 build_no_control_notebook ();
487 basic_vbox.pack_start (basic_hbox, false, false);
490 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
491 basic_vbox.show_all ();
496 EngineControl::build_full_control_notebook ()
498 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
501 using namespace Notebook_Helpers;
503 vector<string> strings;
504 AttachOptions xopt = AttachOptions (FILL|EXPAND);
505 int row = 1; // row zero == backend combo
507 /* start packing it up */
509 if (backend->requires_driver_selection()) {
510 label = manage (left_aligned_label (_("Driver:")));
511 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
512 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
516 if (backend->use_separate_input_and_output_devices()) {
517 label = manage (left_aligned_label (_("Input Device:")));
518 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
519 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
521 label = manage (left_aligned_label (_("Output Device:")));
522 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
523 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
525 // reset so it isn't used in state comparisons
526 device_combo.set_active_text ("");
528 label = manage (left_aligned_label (_("Device:")));
529 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
530 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
532 // reset these so they don't get used in state comparisons
533 input_device_combo.set_active_text ("");
534 output_device_combo.set_active_text ("");
537 label = manage (left_aligned_label (_("Sample rate:")));
538 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
539 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
543 label = manage (left_aligned_label (_("Buffer size:")));
544 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
545 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
546 buffer_size_duration_label.set_alignment (0.0); /* left-align */
547 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
549 /* button spans 2 rows */
551 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
554 input_channels.set_name ("InputChannels");
555 input_channels.set_flags (Gtk::CAN_FOCUS);
556 input_channels.set_digits (0);
557 input_channels.set_wrap (false);
558 output_channels.set_editable (true);
560 if (!ARDOUR::Profile->get_mixbus()) {
561 label = manage (left_aligned_label (_("Input Channels:")));
562 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
563 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
567 output_channels.set_name ("OutputChannels");
568 output_channels.set_flags (Gtk::CAN_FOCUS);
569 output_channels.set_digits (0);
570 output_channels.set_wrap (false);
571 output_channels.set_editable (true);
573 if (!ARDOUR::Profile->get_mixbus()) {
574 label = manage (left_aligned_label (_("Output Channels:")));
575 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
576 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
580 input_latency.set_name ("InputLatency");
581 input_latency.set_flags (Gtk::CAN_FOCUS);
582 input_latency.set_digits (0);
583 input_latency.set_wrap (false);
584 input_latency.set_editable (true);
586 label = manage (left_aligned_label (_("Hardware input latency:")));
587 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
588 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
589 label = manage (left_aligned_label (_("samples")));
590 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
593 output_latency.set_name ("OutputLatency");
594 output_latency.set_flags (Gtk::CAN_FOCUS);
595 output_latency.set_digits (0);
596 output_latency.set_wrap (false);
597 output_latency.set_editable (true);
599 label = manage (left_aligned_label (_("Hardware output latency:")));
600 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
601 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
602 label = manage (left_aligned_label (_("samples")));
603 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
605 /* button spans 2 rows */
607 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
610 label = manage (left_aligned_label (_("MIDI System:")));
611 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
612 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
613 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
614 /* Currently the only backend with dedicated Midi setup is ALSA.
615 * lot of people complain that this is greyed out
616 * "I can't use MIDI, the setup is greyed out"
618 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
624 EngineControl::build_no_control_notebook ()
626 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
629 using namespace Notebook_Helpers;
631 vector<string> strings;
632 AttachOptions xopt = AttachOptions (FILL|EXPAND);
633 int row = 1; // row zero == backend combo
634 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
636 label = manage (new Label);
637 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
638 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
641 if (backend->can_change_sample_rate_when_running()) {
642 label = manage (left_aligned_label (_("Sample rate:")));
643 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
644 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
648 if (backend->can_change_buffer_size_when_running()) {
649 label = manage (left_aligned_label (_("Buffer size:")));
650 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
651 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
652 buffer_size_duration_label.set_alignment (0.0); /* left-align */
653 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
657 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
661 EngineControl::~EngineControl ()
663 ignore_changes = true;
667 EngineControl::disable_latency_tab ()
669 vector<string> empty;
670 set_popdown_strings (lm_output_channel_combo, empty);
671 set_popdown_strings (lm_input_channel_combo, empty);
672 lm_measure_button.set_sensitive (false);
673 lm_use_button.set_sensitive (false);
677 EngineControl::enable_latency_tab ()
679 vector<string> outputs;
680 vector<string> inputs;
682 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
683 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
684 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
686 if (!ARDOUR::AudioEngine::instance()->running()) {
687 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
688 notebook.set_current_page (0);
692 else if (inputs.empty() || outputs.empty()) {
693 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
694 notebook.set_current_page (0);
699 lm_back_button_signal.disconnect();
701 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
704 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
708 set_popdown_strings (lm_output_channel_combo, outputs);
709 lm_output_channel_combo.set_active_text (outputs.front());
710 lm_output_channel_combo.set_sensitive (true);
712 set_popdown_strings (lm_input_channel_combo, inputs);
713 lm_input_channel_combo.set_active_text (inputs.front());
714 lm_input_channel_combo.set_sensitive (true);
716 lm_measure_button.set_sensitive (true);
720 EngineControl::setup_midi_tab_for_backend ()
722 string backend = backend_combo.get_active_text ();
724 Gtkmm2ext::container_clear (midi_vbox);
726 midi_vbox.set_border_width (12);
727 midi_device_table.set_border_width (12);
729 if (backend == "JACK") {
730 setup_midi_tab_for_jack ();
733 midi_vbox.pack_start (midi_device_table, true, true);
734 midi_vbox.pack_start (midi_back_button, false, false);
735 midi_vbox.show_all ();
739 EngineControl::update_sensitivity ()
741 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
743 ok_button->set_sensitive (false);
744 start_stop_button.set_sensitive (false);
749 size_t devices_available = 0;
751 if (backend->use_separate_input_and_output_devices ()) {
752 devices_available += get_popdown_string_count (input_device_combo);
753 devices_available += get_popdown_string_count (output_device_combo);
755 devices_available += get_popdown_string_count (device_combo);
758 if (devices_available == 0) {
760 input_latency.set_sensitive (false);
761 output_latency.set_sensitive (false);
762 input_channels.set_sensitive (false);
763 output_channels.set_sensitive (false);
765 input_latency.set_sensitive (true);
766 output_latency.set_sensitive (true);
767 input_channels.set_sensitive (true);
768 output_channels.set_sensitive (true);
771 if (get_popdown_string_count (buffer_size_combo) > 0) {
772 if (!ARDOUR::AudioEngine::instance()->running()) {
773 buffer_size_combo.set_sensitive (valid);
774 } else if (backend->can_change_sample_rate_when_running()) {
775 buffer_size_combo.set_sensitive (valid || !_have_control);
779 * Currently there is no way to manually stop the
780 * engine in order to re-configure it.
781 * This needs to remain sensitive for now.
783 * (it's also handy to implicily
784 * re-start the engine)
786 buffer_size_combo.set_sensitive (true);
788 buffer_size_combo.set_sensitive (false);
792 buffer_size_combo.set_sensitive (false);
796 if (get_popdown_string_count (sample_rate_combo) > 0) {
797 if (!ARDOUR::AudioEngine::instance()->running()) {
798 sample_rate_combo.set_sensitive (true);
800 sample_rate_combo.set_sensitive (false);
803 sample_rate_combo.set_sensitive (false);
808 start_stop_button.set_sensitive(true);
809 start_stop_button.show();
810 if (ARDOUR::AudioEngine::instance()->running()) {
811 start_stop_button.set_text("Stop");
812 update_devices_button.set_sensitive(false);
814 if (backend->can_request_update_devices()) {
815 update_devices_button.show();
817 update_devices_button.hide();
819 start_stop_button.set_text("Start");
820 update_devices_button.set_sensitive(true);
823 update_devices_button.set_sensitive(false);
824 update_devices_button.hide();
825 start_stop_button.set_sensitive(false);
826 start_stop_button.hide();
829 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
830 input_device_combo.set_sensitive (false);
831 output_device_combo.set_sensitive (false);
832 device_combo.set_sensitive (false);
833 driver_combo.set_sensitive (false);
835 input_device_combo.set_sensitive (true);
836 output_device_combo.set_sensitive (true);
837 device_combo.set_sensitive (true);
838 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
839 driver_combo.set_sensitive (true);
841 driver_combo.set_sensitive (false);
845 if (valid || !_have_control) {
846 ok_button->set_sensitive (true);
848 ok_button->set_sensitive (false);
853 EngineControl::setup_midi_tab_for_jack ()
858 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
860 device->input_latency = a->get_value();
862 device->output_latency = a->get_value();
867 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
868 b->set_active (!b->get_active());
869 device->enabled = b->get_active();
870 refresh_midi_display(device->name);
874 EngineControl::refresh_midi_display (std::string focus)
876 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
880 AttachOptions xopt = AttachOptions (FILL|EXPAND);
883 Gtkmm2ext::container_clear (midi_device_table);
885 midi_device_table.set_spacings (6);
887 l = manage (new Label);
888 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
889 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
890 l->set_alignment (0.5, 0.5);
894 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
895 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
896 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
897 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
899 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
900 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
901 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
902 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
905 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
910 bool enabled = (*p)->enabled;
912 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
913 m->set_name ("midi device");
914 m->set_can_focus (Gtk::CAN_FOCUS);
915 m->add_events (Gdk::BUTTON_RELEASE_MASK);
916 m->set_active (enabled);
917 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
918 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
919 if ((*p)->name == focus) {
923 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
924 s = manage (new Gtk::SpinButton (*a));
925 a->set_value ((*p)->input_latency);
926 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
927 s->set_sensitive (_can_set_midi_latencies && enabled);
928 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
930 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
931 s = manage (new Gtk::SpinButton (*a));
932 a->set_value ((*p)->output_latency);
933 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
934 s->set_sensitive (_can_set_midi_latencies && enabled);
935 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
937 b = manage (new Button (_("Calibrate")));
938 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
939 b->set_sensitive (_can_set_midi_latencies && enabled);
940 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
947 EngineControl::backend_changed ()
949 SignalBlocker blocker (*this, "backend_changed");
950 string backend_name = backend_combo.get_active_text();
951 boost::shared_ptr<ARDOUR::AudioBackend> backend;
953 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (PROGRAM_NAME), ""))) {
954 /* eh? setting the backend failed... how ? */
955 /* A: stale config contains a backend that does not exist in current build */
959 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
961 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
964 setup_midi_tab_for_backend ();
965 _midi_devices.clear();
967 if (backend->requires_driver_selection()) {
968 if (set_driver_popdown_strings ()) {
972 /* this will change the device text which will cause a call to
973 * device changed which will set up parameters
978 update_midi_options ();
980 connect_disconnect_button.hide();
982 midi_option_changed();
984 started_at_least_once = false;
986 /* changing the backend implies stopping the engine
987 * ARDOUR::AudioEngine() may or may not emit this signal
988 * depending on previous engine state
990 engine_stopped (); // set "active/inactive"
992 if (!ignore_changes) {
993 maybe_display_saved_state ();
998 EngineControl::update_midi_options ()
1000 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1001 vector<string> midi_options = backend->enumerate_midi_options();
1003 if (midi_options.size() == 1) {
1004 /* only contains the "none" option */
1005 midi_option_combo.set_sensitive (false);
1007 if (_have_control) {
1008 set_popdown_strings (midi_option_combo, midi_options);
1009 midi_option_combo.set_active_text (midi_options.front());
1010 midi_option_combo.set_sensitive (true);
1012 midi_option_combo.set_sensitive (false);
1018 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1020 if (ARDOUR::Profile->get_mixbus()) {
1024 uint32_t cnt = (uint32_t) sb->get_value();
1026 sb->set_text (_("all available channels"));
1029 snprintf (buf, sizeof (buf), "%d", cnt);
1035 // @return true if there are drivers available
1037 EngineControl::set_driver_popdown_strings ()
1039 DEBUG_ECONTROL ("set_driver_popdown_strings");
1040 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1041 vector<string> drivers = backend->enumerate_drivers();
1043 if (drivers.empty ()) {
1044 // This is an error...?
1048 string current_driver = backend->driver_name ();
1050 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1052 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1055 current_driver = drivers.front ();
1058 set_popdown_strings (driver_combo, drivers);
1060 string_compose ("driver_combo.set_active_text: %1", current_driver));
1061 driver_combo.set_active_text (current_driver);
1066 EngineControl::get_default_device(const string& current_device_name,
1067 const vector<string>& available_devices)
1069 // If the current device is available, use it as default
1070 if (std::find (available_devices.begin (),
1071 available_devices.end (),
1072 current_device_name) != available_devices.end ()) {
1074 return current_device_name;
1077 using namespace ARDOUR;
1079 string default_device_name =
1080 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1082 vector<string>::const_iterator i;
1084 // If there is a "Default" device available, use it
1085 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1086 if (*i == default_device_name) {
1091 string none_device_name =
1092 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1094 // Use the first device that isn't "None"
1095 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1096 if (*i != none_device_name) {
1101 // Use "None" if there are no other available
1102 return available_devices.front();
1105 // @return true if there are devices available
1107 EngineControl::set_device_popdown_strings ()
1109 DEBUG_ECONTROL ("set_device_popdown_strings");
1110 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1111 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1113 /* NOTE: Ardour currently does not display the "available" field of the
1116 * Doing so would require a different GUI widget than the combo
1117 * box/popdown that we currently use, since it has no way to list
1118 * items that are not selectable. Something more like a popup menu,
1119 * which could have unselectable items, would be appropriate.
1122 vector<string> available_devices;
1124 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1125 available_devices.push_back (i->name);
1128 if (available_devices.empty ()) {
1132 set_popdown_strings (device_combo, available_devices);
1134 std::string default_device =
1135 get_default_device(backend->device_name(), available_devices);
1138 string_compose ("set device_combo active text: %1", default_device));
1140 device_combo.set_active_text(default_device);
1144 // @return true if there are input devices available
1146 EngineControl::set_input_device_popdown_strings ()
1148 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1149 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1150 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1152 vector<string> available_devices;
1154 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1155 available_devices.push_back (i->name);
1158 if (available_devices.empty()) {
1162 set_popdown_strings (input_device_combo, available_devices);
1164 std::string default_device =
1165 get_default_device(backend->input_device_name(), available_devices);
1168 string_compose ("set input_device_combo active text: %1", default_device));
1169 input_device_combo.set_active_text(default_device);
1173 // @return true if there are output devices available
1175 EngineControl::set_output_device_popdown_strings ()
1177 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1178 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1179 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1181 vector<string> available_devices;
1183 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1184 available_devices.push_back (i->name);
1187 if (available_devices.empty()) {
1191 set_popdown_strings (output_device_combo, available_devices);
1193 std::string default_device =
1194 get_default_device(backend->output_device_name(), available_devices);
1197 string_compose ("set output_device_combo active text: %1", default_device));
1198 output_device_combo.set_active_text(default_device);
1203 EngineControl::list_devices ()
1205 DEBUG_ECONTROL ("list_devices");
1206 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1209 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1211 bool devices_available = false;
1213 if (backend->use_separate_input_and_output_devices ()) {
1214 bool input_devices_available = set_input_device_popdown_strings ();
1215 bool output_devices_available = set_output_device_popdown_strings ();
1216 devices_available = input_devices_available || output_devices_available;
1218 devices_available = set_device_popdown_strings ();
1221 if (devices_available) {
1224 device_combo.clear();
1225 input_device_combo.clear();
1226 output_device_combo.clear();
1228 update_sensitivity ();
1232 EngineControl::driver_changed ()
1234 SignalBlocker blocker (*this, "driver_changed");
1235 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1238 backend->set_driver (driver_combo.get_active_text());
1241 if (!ignore_changes) {
1242 maybe_display_saved_state ();
1247 EngineControl::get_sample_rates_for_all_devices ()
1249 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1250 ARDOUR::AudioEngine::instance ()->current_backend ();
1251 vector<float> all_rates;
1253 if (backend->use_separate_input_and_output_devices ()) {
1254 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1256 all_rates = backend->available_sample_rates (get_device_name ());
1262 EngineControl::get_default_sample_rates ()
1264 vector<float> rates;
1265 rates.push_back (8000.0f);
1266 rates.push_back (16000.0f);
1267 rates.push_back (32000.0f);
1268 rates.push_back (44100.0f);
1269 rates.push_back (48000.0f);
1270 rates.push_back (88200.0f);
1271 rates.push_back (96000.0f);
1272 rates.push_back (192000.0f);
1273 rates.push_back (384000.0f);
1278 EngineControl::set_samplerate_popdown_strings ()
1280 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1281 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1286 if (_have_control) {
1287 sr = get_sample_rates_for_all_devices ();
1289 sr = get_default_sample_rates ();
1292 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1293 s.push_back (rate_as_string (*x));
1294 if (*x == _desired_sample_rate) {
1299 set_popdown_strings (sample_rate_combo, s);
1302 if (desired.empty ()) {
1303 float new_active_sr = backend->default_sample_rate ();
1305 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1306 new_active_sr = sr.front ();
1309 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1311 sample_rate_combo.set_active_text (desired);
1315 update_sensitivity ();
1319 EngineControl::get_buffer_sizes_for_all_devices ()
1321 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1322 ARDOUR::AudioEngine::instance ()->current_backend ();
1323 vector<uint32_t> all_sizes;
1325 if (backend->use_separate_input_and_output_devices ()) {
1326 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1328 all_sizes = backend->available_buffer_sizes (get_device_name ());
1334 EngineControl::get_default_buffer_sizes ()
1336 vector<uint32_t> sizes;
1337 sizes.push_back (8);
1338 sizes.push_back (16);
1339 sizes.push_back (32);
1340 sizes.push_back (64);
1341 sizes.push_back (128);
1342 sizes.push_back (256);
1343 sizes.push_back (512);
1344 sizes.push_back (1024);
1345 sizes.push_back (2048);
1346 sizes.push_back (4096);
1347 sizes.push_back (8192);
1352 EngineControl::set_buffersize_popdown_strings ()
1354 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1355 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1356 vector<uint32_t> bs;
1359 if (_have_control) {
1360 bs = get_buffer_sizes_for_all_devices ();
1361 } else if (backend->can_change_buffer_size_when_running()) {
1362 bs = get_default_buffer_sizes ();
1365 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1366 s.push_back (bufsize_as_string (*x));
1369 uint32_t previous_size = 0;
1370 if (!buffer_size_combo.get_active_text().empty()) {
1371 previous_size = get_buffer_size ();
1374 set_popdown_strings (buffer_size_combo, s);
1378 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1379 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1382 buffer_size_combo.set_active_text(s.front());
1384 uint32_t period = backend->buffer_size();
1385 if (0 == period && backend->use_separate_input_and_output_devices()) {
1386 period = backend->default_buffer_size(get_input_device_name());
1388 if (0 == period && backend->use_separate_input_and_output_devices()) {
1389 period = backend->default_buffer_size(get_output_device_name());
1391 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1392 period = backend->default_buffer_size(get_device_name());
1395 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1397 show_buffer_duration ();
1399 update_sensitivity ();
1403 EngineControl::device_changed ()
1405 SignalBlocker blocker (*this, "device_changed");
1406 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1409 string device_name_in;
1410 string device_name_out; // only used if backend support separate I/O devices
1412 if (backend->use_separate_input_and_output_devices()) {
1413 device_name_in = get_input_device_name ();
1414 device_name_out = get_output_device_name ();
1416 device_name_in = get_device_name ();
1419 /* we set the backend-device to query various device related intormation.
1420 * This has the side effect that backend->device_name() will match
1421 * the device_name and 'change_device' will never be true.
1422 * so work around this by setting...
1424 if (backend->use_separate_input_and_output_devices()) {
1425 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1426 queue_device_changed = true;
1429 if (device_name_in != backend->device_name()) {
1430 queue_device_changed = true;
1434 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1435 if (backend->use_separate_input_and_output_devices()) {
1436 backend->set_input_device_name (device_name_in);
1437 backend->set_output_device_name (device_name_out);
1439 backend->set_device_name(device_name_in);
1443 /* don't allow programmatic change to combos to cause a
1444 recursive call to this method.
1446 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1448 set_samplerate_popdown_strings ();
1449 set_buffersize_popdown_strings ();
1451 /* TODO set min + max channel counts here */
1453 manage_control_app_sensitivity ();
1456 /* pick up any saved state for this device */
1458 if (!ignore_changes) {
1459 maybe_display_saved_state ();
1464 EngineControl::input_device_changed ()
1466 DEBUG_ECONTROL ("input_device_changed");
1471 EngineControl::output_device_changed ()
1473 DEBUG_ECONTROL ("output_device_changed");
1478 EngineControl::bufsize_as_string (uint32_t sz)
1480 /* Translators: "samples" is always plural here, so no
1481 need for plural+singular forms.
1484 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1489 EngineControl::sample_rate_changed ()
1491 DEBUG_ECONTROL ("sample_rate_changed");
1492 /* reset the strings for buffer size to show the correct msec value
1493 (reflecting the new sample rate).
1496 show_buffer_duration ();
1501 EngineControl::buffer_size_changed ()
1503 DEBUG_ECONTROL ("buffer_size_changed");
1504 show_buffer_duration ();
1508 EngineControl::show_buffer_duration ()
1510 DEBUG_ECONTROL ("show_buffer_duration");
1511 /* buffer sizes - convert from just samples to samples + msecs for
1512 * the displayed string
1515 string bs_text = buffer_size_combo.get_active_text ();
1516 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1517 uint32_t rate = get_rate();
1519 /* Developers: note the hard-coding of a double buffered model
1520 in the (2 * samples) computation of latency. we always start
1521 the audiobackend in this configuration.
1523 /* note to jack1 developers: ardour also always starts the engine
1524 * in async mode (no jack2 --sync option) which adds an extra cycle
1525 * of latency with jack2 (and *3 would be correct)
1526 * The value can also be wrong if jackd is started externally..
1528 * At the time of writing the ALSA backend always uses double-buffering *2,
1529 * The Dummy backend *1, and who knows what ASIO really does :)
1531 * So just display the period size, that's also what
1532 * ARDOUR_UI::update_sample_rate() does for the status bar.
1533 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1534 * but still, that's the buffer period, not [round-trip] latency)
1537 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1538 buffer_size_duration_label.set_text (buf);
1542 EngineControl::midi_option_changed ()
1544 DEBUG_ECONTROL ("midi_option_changed");
1545 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1548 backend->set_midi_option (get_midi_option());
1550 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1552 //_midi_devices.clear(); // TODO merge with state-saved settings..
1553 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1554 std::vector<MidiDeviceSettings> new_devices;
1556 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1557 MidiDeviceSettings mds = find_midi_device (i->name);
1558 if (i->available && !mds) {
1559 uint32_t input_latency = 0;
1560 uint32_t output_latency = 0;
1561 if (_can_set_midi_latencies) {
1562 input_latency = backend->systemic_midi_input_latency (i->name);
1563 output_latency = backend->systemic_midi_output_latency (i->name);
1565 bool enabled = backend->midi_device_enabled (i->name);
1566 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1567 new_devices.push_back (ptr);
1568 } else if (i->available) {
1569 new_devices.push_back (mds);
1572 _midi_devices = new_devices;
1574 if (_midi_devices.empty()) {
1575 midi_devices_button.set_sensitive (false);
1577 midi_devices_button.set_sensitive (true);
1582 EngineControl::parameter_changed ()
1586 EngineControl::State
1587 EngineControl::get_matching_state (
1588 const string& backend,
1589 const string& driver,
1590 const string& device)
1592 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1593 if ((*i)->backend == backend &&
1594 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1602 EngineControl::State
1603 EngineControl::get_matching_state (
1604 const string& backend,
1605 const string& driver,
1606 const string& input_device,
1607 const string& output_device)
1609 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1610 if ((*i)->backend == backend &&
1611 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1619 EngineControl::State
1620 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1622 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1625 if (backend->use_separate_input_and_output_devices ()) {
1626 return get_matching_state (backend_combo.get_active_text(),
1627 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1628 input_device_combo.get_active_text(),
1629 output_device_combo.get_active_text());
1631 return get_matching_state (backend_combo.get_active_text(),
1632 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1633 device_combo.get_active_text());
1637 return get_matching_state (backend_combo.get_active_text(),
1639 device_combo.get_active_text());
1642 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1643 const EngineControl::State& state2)
1645 if (state1->backend == state2->backend &&
1646 state1->driver == state2->driver &&
1647 state1->device == state2->device &&
1648 state1->input_device == state2->input_device &&
1649 state1->output_device == state2->output_device) {
1655 EngineControl::State
1656 EngineControl::save_state ()
1660 if (!_have_control) {
1661 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1665 state.reset(new StateStruct);
1666 state->backend = get_backend ();
1668 state.reset(new StateStruct);
1669 store_state (state);
1672 for (StateList::iterator i = states.begin(); i != states.end();) {
1673 if (equivalent_states (*i, state)) {
1674 i = states.erase(i);
1680 states.push_back (state);
1686 EngineControl::store_state (State state)
1688 state->backend = get_backend ();
1689 state->driver = get_driver ();
1690 state->device = get_device_name ();
1691 state->input_device = get_input_device_name ();
1692 state->output_device = get_output_device_name ();
1693 state->sample_rate = get_rate ();
1694 state->buffer_size = get_buffer_size ();
1695 state->input_latency = get_input_latency ();
1696 state->output_latency = get_output_latency ();
1697 state->input_channels = get_input_channels ();
1698 state->output_channels = get_output_channels ();
1699 state->midi_option = get_midi_option ();
1700 state->midi_devices = _midi_devices;
1704 EngineControl::maybe_display_saved_state ()
1706 if (!_have_control) {
1710 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1713 DEBUG_ECONTROL ("Restoring saved state");
1714 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1716 if (!_desired_sample_rate) {
1717 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1719 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1720 /* call this explicitly because we're ignoring changes to
1721 the controls at this point.
1723 show_buffer_duration ();
1724 input_latency.set_value (state->input_latency);
1725 output_latency.set_value (state->output_latency);
1727 if (!state->midi_option.empty()) {
1728 midi_option_combo.set_active_text (state->midi_option);
1729 _midi_devices = state->midi_devices;
1732 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1737 EngineControl::get_state ()
1739 LocaleGuard lg (X_("C"));
1741 XMLNode* root = new XMLNode ("AudioMIDISetup");
1744 if (!states.empty()) {
1745 XMLNode* state_nodes = new XMLNode ("EngineStates");
1747 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1749 XMLNode* node = new XMLNode ("State");
1751 node->add_property ("backend", (*i)->backend);
1752 node->add_property ("driver", (*i)->driver);
1753 node->add_property ("device", (*i)->device);
1754 node->add_property ("input-device", (*i)->input_device);
1755 node->add_property ("output-device", (*i)->output_device);
1756 node->add_property ("sample-rate", (*i)->sample_rate);
1757 node->add_property ("buffer-size", (*i)->buffer_size);
1758 node->add_property ("input-latency", (*i)->input_latency);
1759 node->add_property ("output-latency", (*i)->output_latency);
1760 node->add_property ("input-channels", (*i)->input_channels);
1761 node->add_property ("output-channels", (*i)->output_channels);
1762 node->add_property ("active", (*i)->active ? "yes" : "no");
1763 node->add_property ("midi-option", (*i)->midi_option);
1765 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1766 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1767 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1768 midi_device_stuff->add_property (X_("name"), (*p)->name);
1769 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1770 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1771 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1772 midi_devices->add_child_nocopy (*midi_device_stuff);
1774 node->add_child_nocopy (*midi_devices);
1776 state_nodes->add_child_nocopy (*node);
1779 root->add_child_nocopy (*state_nodes);
1786 EngineControl::set_default_state ()
1788 vector<string> backend_names;
1789 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1791 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1792 backend_names.push_back ((*b)->name);
1794 backend_combo.set_active_text (backend_names.front());
1796 // We could set default backends per platform etc here
1802 EngineControl::set_state (const XMLNode& root)
1804 XMLNodeList clist, cclist;
1805 XMLNodeConstIterator citer, cciter;
1807 XMLNode* grandchild;
1808 XMLProperty* prop = NULL;
1810 fprintf (stderr, "EngineControl::set_state\n");
1812 if (root.name() != "AudioMIDISetup") {
1816 clist = root.children();
1820 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1824 if (child->name() != "EngineStates") {
1828 cclist = child->children();
1830 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1831 State state (new StateStruct);
1833 grandchild = *cciter;
1835 if (grandchild->name() != "State") {
1839 if ((prop = grandchild->property ("backend")) == 0) {
1842 state->backend = prop->value ();
1844 if ((prop = grandchild->property ("driver")) == 0) {
1847 state->driver = prop->value ();
1849 if ((prop = grandchild->property ("device")) == 0) {
1852 state->device = prop->value ();
1854 if ((prop = grandchild->property ("input-device")) == 0) {
1857 state->input_device = prop->value ();
1859 if ((prop = grandchild->property ("output-device")) == 0) {
1862 state->output_device = prop->value ();
1864 if ((prop = grandchild->property ("sample-rate")) == 0) {
1867 state->sample_rate = atof (prop->value ());
1869 if ((prop = grandchild->property ("buffer-size")) == 0) {
1872 state->buffer_size = atoi (prop->value ());
1874 if ((prop = grandchild->property ("input-latency")) == 0) {
1877 state->input_latency = atoi (prop->value ());
1879 if ((prop = grandchild->property ("output-latency")) == 0) {
1882 state->output_latency = atoi (prop->value ());
1884 if ((prop = grandchild->property ("input-channels")) == 0) {
1887 state->input_channels = atoi (prop->value ());
1889 if ((prop = grandchild->property ("output-channels")) == 0) {
1892 state->output_channels = atoi (prop->value ());
1894 if ((prop = grandchild->property ("active")) == 0) {
1897 state->active = string_is_affirmative (prop->value ());
1899 if ((prop = grandchild->property ("midi-option")) == 0) {
1902 state->midi_option = prop->value ();
1904 state->midi_devices.clear();
1906 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1907 const XMLNodeList mnc = midinode->children();
1908 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1909 if ((*n)->property (X_("name")) == 0
1910 || (*n)->property (X_("enabled")) == 0
1911 || (*n)->property (X_("input-latency")) == 0
1912 || (*n)->property (X_("output-latency")) == 0
1917 MidiDeviceSettings ptr (new MidiDeviceSetting(
1918 (*n)->property (X_("name"))->value (),
1919 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1920 atoi ((*n)->property (X_("input-latency"))->value ()),
1921 atoi ((*n)->property (X_("output-latency"))->value ())
1923 state->midi_devices.push_back (ptr);
1928 /* remove accumulated duplicates (due to bug in ealier version)
1929 * this can be removed again before release
1931 for (StateList::iterator i = states.begin(); i != states.end();) {
1932 if ((*i)->backend == state->backend &&
1933 (*i)->driver == state->driver &&
1934 (*i)->device == state->device) {
1935 i = states.erase(i);
1942 states.push_back (state);
1946 /* now see if there was an active state and switch the setup to it */
1948 // purge states of backend that are not available in this built
1949 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1950 vector<std::string> backend_names;
1952 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1953 backend_names.push_back((*i)->name);
1955 for (StateList::iterator i = states.begin(); i != states.end();) {
1956 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1957 i = states.erase(i);
1963 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1966 return set_current_state (*i);
1973 EngineControl::set_current_state (const State& state)
1975 DEBUG_ECONTROL ("set_current_state");
1977 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1979 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1980 state->backend, downcase (PROGRAM_NAME), ""))) {
1981 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1982 // this shouldn't happen as the invalid backend names should have been
1983 // removed from the list of states.
1987 // now reflect the change in the backend in the GUI so backend_changed will
1988 // do the right thing
1989 backend_combo.set_active_text (state->backend);
1991 if (!state->driver.empty ()) {
1992 if (!backend->requires_driver_selection ()) {
1993 DEBUG_ECONTROL ("Backend should require driver selection");
1994 // A backend has changed from having driver selection to not having
1995 // it or someone has been manually editing a config file and messed
2000 if (backend->set_driver (state->driver) != 0) {
2001 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2002 // Driver names for a backend have changed and the name in the
2003 // config file is now invalid or support for driver is no longer
2004 // included in the backend
2007 // no need to set the driver_combo as backend_changed will use
2008 // backend->driver_name to set the active driver
2011 if (!state->device.empty ()) {
2012 if (backend->set_device_name (state->device) != 0) {
2014 string_compose ("Unable to set device name %1", state->device));
2015 // device is no longer available on the system
2018 // no need to set active device as it will be picked up in
2019 // via backend_changed ()/set_device_popdown_strings
2022 // backend supports separate input/output devices
2023 if (backend->set_input_device_name (state->input_device) != 0) {
2024 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2025 state->input_device));
2026 // input device is no longer available on the system
2030 if (backend->set_output_device_name (state->output_device) != 0) {
2031 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2032 state->input_device));
2033 // output device is no longer available on the system
2036 // no need to set active devices as it will be picked up in via
2037 // backend_changed ()/set_*_device_popdown_strings
2042 // Now restore the state of the rest of the controls
2044 // We don't use a SignalBlocker as set_current_state is currently only
2045 // called from set_state before any signals are connected. If at some point
2046 // a more general named state mechanism is implemented and
2047 // set_current_state is called while signals are connected then a
2048 // SignalBlocker will need to be instantiated before setting these.
2050 device_combo.set_active_text (state->device);
2051 input_device_combo.set_active_text (state->input_device);
2052 output_device_combo.set_active_text (state->output_device);
2053 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2054 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2055 input_latency.set_value (state->input_latency);
2056 output_latency.set_value (state->output_latency);
2057 midi_option_combo.set_active_text (state->midi_option);
2062 EngineControl::push_state_to_backend (bool start)
2064 DEBUG_ECONTROL ("push_state_to_backend");
2065 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2071 /* figure out what is going to change */
2073 bool restart_required = false;
2074 bool was_running = ARDOUR::AudioEngine::instance()->running();
2075 bool change_driver = false;
2076 bool change_device = false;
2077 bool change_rate = false;
2078 bool change_bufsize = false;
2079 bool change_latency = false;
2080 bool change_channels = false;
2081 bool change_midi = false;
2083 uint32_t ochan = get_output_channels ();
2084 uint32_t ichan = get_input_channels ();
2086 if (_have_control) {
2088 if (started_at_least_once) {
2090 /* we can control the backend */
2092 if (backend->requires_driver_selection()) {
2093 if (get_driver() != backend->driver_name()) {
2094 change_driver = true;
2098 if (backend->use_separate_input_and_output_devices()) {
2099 if (get_input_device_name() != backend->input_device_name()) {
2100 change_device = true;
2102 if (get_output_device_name() != backend->output_device_name()) {
2103 change_device = true;
2106 if (get_device_name() != backend->device_name()) {
2107 change_device = true;
2111 if (queue_device_changed) {
2112 change_device = true;
2115 if (get_rate() != backend->sample_rate()) {
2119 if (get_buffer_size() != backend->buffer_size()) {
2120 change_bufsize = true;
2123 if (get_midi_option() != backend->midi_option()) {
2127 /* zero-requested channels means "all available" */
2130 ichan = backend->input_channels();
2134 ochan = backend->output_channels();
2137 if (ichan != backend->input_channels()) {
2138 change_channels = true;
2141 if (ochan != backend->output_channels()) {
2142 change_channels = true;
2145 if (get_input_latency() != backend->systemic_input_latency() ||
2146 get_output_latency() != backend->systemic_output_latency()) {
2147 change_latency = true;
2150 /* backend never started, so we have to force a group
2153 change_device = true;
2154 if (backend->requires_driver_selection()) {
2155 change_driver = true;
2158 change_bufsize = true;
2159 change_channels = true;
2160 change_latency = true;
2166 /* we have no control over the backend, meaning that we can
2167 * only possibly change sample rate and buffer size.
2171 if (get_rate() != backend->sample_rate()) {
2172 change_bufsize = true;
2175 if (get_buffer_size() != backend->buffer_size()) {
2176 change_bufsize = true;
2180 queue_device_changed = false;
2182 if (!_have_control) {
2184 /* We do not have control over the backend, so the best we can
2185 * do is try to change the sample rate and/or bufsize and get
2189 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2193 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2198 backend->set_sample_rate (get_rate());
2201 if (change_bufsize) {
2202 backend->set_buffer_size (get_buffer_size());
2206 if (ARDOUR::AudioEngine::instance()->start ()) {
2207 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2217 /* determine if we need to stop the backend before changing parameters */
2219 if (change_driver || change_device || change_channels || change_latency ||
2220 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2222 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2223 restart_required = true;
2225 restart_required = false;
2230 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2231 /* no changes in any parameters that absolutely require a
2232 * restart, so check those that might be changeable without a
2236 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2237 /* can't do this while running ... */
2238 restart_required = true;
2241 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2242 /* can't do this while running ... */
2243 restart_required = true;
2249 if (restart_required) {
2250 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2257 if (change_driver && backend->set_driver (get_driver())) {
2258 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2261 if (backend->use_separate_input_and_output_devices()) {
2262 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2263 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2266 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2267 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2271 if (change_device && backend->set_device_name (get_device_name())) {
2272 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2276 if (change_rate && backend->set_sample_rate (get_rate())) {
2277 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2280 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2281 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2285 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2286 if (backend->set_input_channels (get_input_channels())) {
2287 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2290 if (backend->set_output_channels (get_output_channels())) {
2291 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2295 if (change_latency) {
2296 if (backend->set_systemic_input_latency (get_input_latency())) {
2297 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2300 if (backend->set_systemic_output_latency (get_output_latency())) {
2301 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2307 backend->set_midi_option (get_midi_option());
2311 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2312 if (_measure_midi) {
2313 if (*p == _measure_midi) {
2314 backend->set_midi_device_enabled ((*p)->name, true);
2316 backend->set_midi_device_enabled ((*p)->name, false);
2320 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2321 if (backend->can_set_systemic_midi_latencies()) {
2322 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2323 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2328 if (start || (was_running && restart_required)) {
2329 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2340 EngineControl::post_push ()
2342 /* get a pointer to the current state object, creating one if
2346 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2349 state = save_state ();
2357 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2358 (*i)->active = false;
2361 /* mark this one active (to be used next time the dialog is
2365 state->active = true;
2367 if (_have_control) { // XXX
2368 manage_control_app_sensitivity ();
2371 /* schedule a redisplay of MIDI ports */
2372 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2377 EngineControl::get_rate () const
2379 float r = atof (sample_rate_combo.get_active_text ());
2380 /* the string may have been translated with an abbreviation for
2381 * thousands, so use a crude heuristic to fix this.
2391 EngineControl::get_buffer_size () const
2393 string txt = buffer_size_combo.get_active_text ();
2396 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2397 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2398 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2406 EngineControl::get_midi_option () const
2408 return midi_option_combo.get_active_text();
2412 EngineControl::get_input_channels() const
2414 if (ARDOUR::Profile->get_mixbus()) {
2415 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2416 if (!backend) return 0;
2417 return backend->input_channels();
2419 return (uint32_t) input_channels_adjustment.get_value();
2423 EngineControl::get_output_channels() const
2425 if (ARDOUR::Profile->get_mixbus()) {
2426 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2427 if (!backend) return 0;
2428 return backend->input_channels();
2430 return (uint32_t) output_channels_adjustment.get_value();
2434 EngineControl::get_input_latency() const
2436 return (uint32_t) input_latency_adjustment.get_value();
2440 EngineControl::get_output_latency() const
2442 return (uint32_t) output_latency_adjustment.get_value();
2446 EngineControl::get_backend () const
2448 return backend_combo.get_active_text ();
2452 EngineControl::get_driver () const
2454 if (driver_combo.get_parent()) {
2455 return driver_combo.get_active_text ();
2462 EngineControl::get_device_name () const
2464 return device_combo.get_active_text ();
2468 EngineControl::get_input_device_name () const
2470 return input_device_combo.get_active_text ();
2474 EngineControl::get_output_device_name () const
2476 return output_device_combo.get_active_text ();
2480 EngineControl::control_app_button_clicked ()
2482 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2488 backend->launch_control_app ();
2492 EngineControl::start_stop_button_clicked ()
2494 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2500 if (ARDOUR::AudioEngine::instance()->running()) {
2501 ARDOUR::AudioEngine::instance()->stop ();
2503 push_state_to_backend (true);
2508 EngineControl::update_devices_button_clicked ()
2510 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2516 if (backend->update_devices()) {
2517 device_list_changed ();
2522 EngineControl::manage_control_app_sensitivity ()
2524 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2530 string appname = backend->control_app_name();
2532 if (appname.empty()) {
2533 control_app_button.set_sensitive (false);
2535 control_app_button.set_sensitive (true);
2540 EngineControl::set_desired_sample_rate (uint32_t sr)
2542 _desired_sample_rate = sr;
2547 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2549 if (page_num == 0) {
2550 cancel_button->set_sensitive (true);
2551 _measure_midi.reset();
2552 update_sensitivity ();
2554 cancel_button->set_sensitive (false);
2555 ok_button->set_sensitive (false);
2558 if (page_num == midi_tab) {
2560 refresh_midi_display ();
2563 if (page_num == latency_tab) {
2566 if (ARDOUR::AudioEngine::instance()->running()) {
2567 // TODO - mark as 'stopped for latency
2568 ARDOUR_UI::instance()->disconnect_from_engine ();
2572 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2574 /* save any existing latency values */
2576 uint32_t il = (uint32_t) input_latency.get_value ();
2577 uint32_t ol = (uint32_t) input_latency.get_value ();
2579 /* reset to zero so that our new test instance
2580 will be clean of any existing latency measures.
2582 NB. this should really be done by the backend
2583 when stated for latency measurement.
2586 input_latency.set_value (0);
2587 output_latency.set_value (0);
2589 push_state_to_backend (false);
2593 input_latency.set_value (il);
2594 output_latency.set_value (ol);
2597 // This should be done in push_state_to_backend()
2598 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2599 disable_latency_tab ();
2602 enable_latency_tab ();
2606 end_latency_detection ();
2607 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2612 /* latency measurement */
2615 EngineControl::check_audio_latency_measurement ()
2617 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2619 if (mtdm->resolve () < 0) {
2620 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2624 if (mtdm->err () > 0.3) {
2630 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2632 if (sample_rate == 0) {
2633 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2634 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2638 int frames_total = mtdm->del();
2639 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2641 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2642 _("Detected roundtrip latency: "),
2643 frames_total, frames_total * 1000.0f/sample_rate,
2644 _("Systemic latency: "),
2645 extra, extra * 1000.0f/sample_rate);
2649 if (mtdm->err () > 0.2) {
2651 strcat (buf, _("(signal detection error)"));
2657 strcat (buf, _("(inverted - bad wiring)"));
2661 lm_results.set_markup (string_compose (results_markup, buf));
2664 have_lm_results = true;
2665 end_latency_detection ();
2666 lm_use_button.set_sensitive (true);
2674 EngineControl::check_midi_latency_measurement ()
2676 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2678 if (!mididm->have_signal () || mididm->latency () == 0) {
2679 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2684 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2686 if (sample_rate == 0) {
2687 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2688 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2692 ARDOUR::framecnt_t frames_total = mididm->latency();
2693 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2694 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2695 _("Detected roundtrip latency: "),
2696 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2697 _("Systemic latency: "),
2698 extra, extra * 1000.0f / sample_rate);
2702 if (!mididm->ok ()) {
2704 strcat (buf, _("(averaging)"));
2708 if (mididm->deviation () > 50.0) {
2710 strcat (buf, _("(too large jitter)"));
2712 } else if (mididm->deviation () > 10.0) {
2714 strcat (buf, _("(large jitter)"));
2718 have_lm_results = true;
2719 end_latency_detection ();
2720 lm_use_button.set_sensitive (true);
2721 lm_results.set_markup (string_compose (results_markup, buf));
2723 } else if (mididm->processed () > 400) {
2724 have_lm_results = false;
2725 end_latency_detection ();
2726 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2730 lm_results.set_markup (string_compose (results_markup, buf));
2736 EngineControl::start_latency_detection ()
2738 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2739 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2741 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2742 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2743 if (_measure_midi) {
2744 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2746 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2748 lm_measure_label.set_text (_("Cancel"));
2749 have_lm_results = false;
2750 lm_use_button.set_sensitive (false);
2751 lm_input_channel_combo.set_sensitive (false);
2752 lm_output_channel_combo.set_sensitive (false);
2758 EngineControl::end_latency_detection ()
2760 latency_timeout.disconnect ();
2761 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2762 lm_measure_label.set_text (_("Measure"));
2763 if (!have_lm_results) {
2764 lm_use_button.set_sensitive (false);
2766 lm_input_channel_combo.set_sensitive (true);
2767 lm_output_channel_combo.set_sensitive (true);
2772 EngineControl::latency_button_clicked ()
2775 start_latency_detection ();
2777 end_latency_detection ();
2782 EngineControl::use_latency_button_clicked ()
2784 if (_measure_midi) {
2785 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2789 ARDOUR::framecnt_t frames_total = mididm->latency();
2790 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2791 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2792 _measure_midi->input_latency = one_way;
2793 _measure_midi->output_latency = one_way;
2794 notebook.set_current_page (midi_tab);
2796 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2802 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2803 one_way = std::max (0., one_way);
2805 input_latency_adjustment.set_value (one_way);
2806 output_latency_adjustment.set_value (one_way);
2808 /* back to settings page */
2809 notebook.set_current_page (0);
2815 EngineControl::on_delete_event (GdkEventAny* ev)
2817 if (notebook.get_current_page() == 2) {
2818 /* currently on latency tab - be sure to clean up */
2819 end_latency_detection ();
2821 return ArdourDialog::on_delete_event (ev);
2825 EngineControl::engine_running ()
2827 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2830 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2831 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2833 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2834 connect_disconnect_button.show();
2836 started_at_least_once = true;
2837 if (_have_control) {
2838 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2840 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2842 update_sensitivity();
2846 EngineControl::engine_stopped ()
2848 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2851 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2852 connect_disconnect_button.show();
2854 if (_have_control) {
2855 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2857 engine_status.set_markup(X_(""));
2860 update_sensitivity();
2864 EngineControl::device_list_changed ()
2866 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2868 midi_option_changed();
2872 EngineControl::connect_disconnect_click()
2874 if (ARDOUR::AudioEngine::instance()->running()) {
2875 ARDOUR_UI::instance()->disconnect_from_engine ();
2877 ARDOUR_UI::instance()->reconnect_to_engine ();
2882 EngineControl::calibrate_audio_latency ()
2884 _measure_midi.reset ();
2885 have_lm_results = false;
2886 lm_use_button.set_sensitive (false);
2887 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2888 notebook.set_current_page (latency_tab);
2892 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2895 have_lm_results = false;
2896 lm_use_button.set_sensitive (false);
2897 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2898 notebook.set_current_page (latency_tab);
2902 EngineControl::configure_midi_devices ()
2904 notebook.set_current_page (midi_tab);