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);
1065 // @return true if there are devices available
1067 EngineControl::set_device_popdown_strings ()
1069 DEBUG_ECONTROL ("set_device_popdown_strings");
1070 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1071 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1073 /* NOTE: Ardour currently does not display the "available" field of the
1076 * Doing so would require a different GUI widget than the combo
1077 * box/popdown that we currently use, since it has no way to list
1078 * items that are not selectable. Something more like a popup menu,
1079 * which could have unselectable items, would be appropriate.
1082 vector<string> available_devices;
1084 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1085 available_devices.push_back (i->name);
1088 if (available_devices.empty ()) {
1092 string current_device = backend->device_name ();
1094 // Make sure that backend->device_name () is a valid
1095 // device, the backend may not return a valid device if it hasn't
1097 if (std::find (available_devices.begin (),
1098 available_devices.end (),
1099 current_device) == available_devices.end ()) {
1101 current_device = available_devices.front ();
1104 set_popdown_strings (device_combo, available_devices);
1106 string_compose ("set device_combo active text: %1", current_device));
1108 device_combo.set_active_text (current_device);
1112 // @return true if there are input devices available
1114 EngineControl::set_input_device_popdown_strings ()
1116 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1117 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1118 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1120 vector<string> available_devices;
1122 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1123 available_devices.push_back (i->name);
1126 if (available_devices.empty()) {
1130 string current_device = backend->input_device_name ();
1132 // Make sure that backend->input_device_name () is a valid
1133 // device, the backend may not return a valid device if it hasn't
1135 if (std::find (available_devices.begin (),
1136 available_devices.end (),
1137 current_device) == available_devices.end ()) {
1139 current_device = available_devices.front ();
1142 set_popdown_strings (input_device_combo, available_devices);
1145 string_compose ("set input_device_combo active text: %1", current_device));
1146 input_device_combo.set_active_text (current_device);
1150 // @return true if there are output devices available
1152 EngineControl::set_output_device_popdown_strings ()
1154 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1155 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1156 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1158 vector<string> available_devices;
1160 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1161 available_devices.push_back (i->name);
1164 if (available_devices.empty()) {
1168 string current_device = backend->output_device_name ();
1170 // Make sure that backend->output_device_name () is a valid
1171 // device, the backend may not return a valid device if it hasn't
1173 if (std::find (available_devices.begin (),
1174 available_devices.end (),
1175 current_device) == available_devices.end ()) {
1177 current_device = available_devices.front ();
1180 set_popdown_strings (output_device_combo, available_devices);
1183 string_compose ("set output_device_combo active text: %1", current_device));
1184 output_device_combo.set_active_text (current_device);
1189 EngineControl::list_devices ()
1191 DEBUG_ECONTROL ("list_devices");
1192 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1195 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1197 bool devices_available = false;
1199 if (backend->use_separate_input_and_output_devices ()) {
1200 bool input_devices_available = set_input_device_popdown_strings ();
1201 bool output_devices_available = set_output_device_popdown_strings ();
1202 devices_available = input_devices_available || output_devices_available;
1204 devices_available = set_device_popdown_strings ();
1207 if (devices_available) {
1210 device_combo.clear();
1211 input_device_combo.clear();
1212 output_device_combo.clear();
1214 update_sensitivity ();
1218 EngineControl::driver_changed ()
1220 SignalBlocker blocker (*this, "driver_changed");
1221 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1224 backend->set_driver (driver_combo.get_active_text());
1227 if (!ignore_changes) {
1228 maybe_display_saved_state ();
1233 EngineControl::get_sample_rates_for_all_devices ()
1235 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1236 ARDOUR::AudioEngine::instance ()->current_backend ();
1237 vector<float> all_rates;
1239 if (backend->use_separate_input_and_output_devices ()) {
1240 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1242 all_rates = backend->available_sample_rates (get_device_name ());
1248 EngineControl::get_default_sample_rates ()
1250 vector<float> rates;
1251 rates.push_back (8000.0f);
1252 rates.push_back (16000.0f);
1253 rates.push_back (32000.0f);
1254 rates.push_back (44100.0f);
1255 rates.push_back (48000.0f);
1256 rates.push_back (88200.0f);
1257 rates.push_back (96000.0f);
1258 rates.push_back (192000.0f);
1259 rates.push_back (384000.0f);
1264 EngineControl::set_samplerate_popdown_strings ()
1266 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1267 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1272 if (_have_control) {
1273 sr = get_sample_rates_for_all_devices ();
1275 sr = get_default_sample_rates ();
1278 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1279 s.push_back (rate_as_string (*x));
1280 if (*x == _desired_sample_rate) {
1285 set_popdown_strings (sample_rate_combo, s);
1288 if (desired.empty ()) {
1289 float new_active_sr = backend->default_sample_rate ();
1291 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1292 new_active_sr = sr.front ();
1295 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1297 sample_rate_combo.set_active_text (desired);
1301 update_sensitivity ();
1305 EngineControl::get_buffer_sizes_for_all_devices ()
1307 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1308 ARDOUR::AudioEngine::instance ()->current_backend ();
1309 vector<uint32_t> all_sizes;
1311 if (backend->use_separate_input_and_output_devices ()) {
1312 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1314 all_sizes = backend->available_buffer_sizes (get_device_name ());
1320 EngineControl::get_default_buffer_sizes ()
1322 vector<uint32_t> sizes;
1323 sizes.push_back (8);
1324 sizes.push_back (16);
1325 sizes.push_back (32);
1326 sizes.push_back (64);
1327 sizes.push_back (128);
1328 sizes.push_back (256);
1329 sizes.push_back (512);
1330 sizes.push_back (1024);
1331 sizes.push_back (2048);
1332 sizes.push_back (4096);
1333 sizes.push_back (8192);
1338 EngineControl::set_buffersize_popdown_strings ()
1340 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1341 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1342 vector<uint32_t> bs;
1345 if (_have_control) {
1346 bs = get_buffer_sizes_for_all_devices ();
1347 } else if (backend->can_change_buffer_size_when_running()) {
1348 bs = get_default_buffer_sizes ();
1351 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1352 s.push_back (bufsize_as_string (*x));
1355 uint32_t previous_size = 0;
1356 if (!buffer_size_combo.get_active_text().empty()) {
1357 previous_size = get_buffer_size ();
1360 set_popdown_strings (buffer_size_combo, s);
1364 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1365 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1368 buffer_size_combo.set_active_text(s.front());
1370 uint32_t period = backend->buffer_size();
1371 if (0 == period && backend->use_separate_input_and_output_devices()) {
1372 period = backend->default_buffer_size(get_input_device_name());
1374 if (0 == period && backend->use_separate_input_and_output_devices()) {
1375 period = backend->default_buffer_size(get_output_device_name());
1377 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1378 period = backend->default_buffer_size(get_device_name());
1381 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1383 show_buffer_duration ();
1385 update_sensitivity ();
1389 EngineControl::device_changed ()
1391 SignalBlocker blocker (*this, "device_changed");
1392 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1395 string device_name_in;
1396 string device_name_out; // only used if backend support separate I/O devices
1398 if (backend->use_separate_input_and_output_devices()) {
1399 device_name_in = get_input_device_name ();
1400 device_name_out = get_output_device_name ();
1402 device_name_in = get_device_name ();
1405 /* we set the backend-device to query various device related intormation.
1406 * This has the side effect that backend->device_name() will match
1407 * the device_name and 'change_device' will never be true.
1408 * so work around this by setting...
1410 if (backend->use_separate_input_and_output_devices()) {
1411 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1412 queue_device_changed = true;
1415 if (device_name_in != backend->device_name()) {
1416 queue_device_changed = true;
1420 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1421 if (backend->use_separate_input_and_output_devices()) {
1422 backend->set_input_device_name (device_name_in);
1423 backend->set_output_device_name (device_name_out);
1425 backend->set_device_name(device_name_in);
1429 /* don't allow programmatic change to combos to cause a
1430 recursive call to this method.
1432 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1434 set_samplerate_popdown_strings ();
1435 set_buffersize_popdown_strings ();
1437 /* TODO set min + max channel counts here */
1439 manage_control_app_sensitivity ();
1442 /* pick up any saved state for this device */
1444 if (!ignore_changes) {
1445 maybe_display_saved_state ();
1450 EngineControl::input_device_changed ()
1452 DEBUG_ECONTROL ("input_device_changed");
1457 EngineControl::output_device_changed ()
1459 DEBUG_ECONTROL ("output_device_changed");
1464 EngineControl::bufsize_as_string (uint32_t sz)
1466 /* Translators: "samples" is always plural here, so no
1467 need for plural+singular forms.
1470 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1475 EngineControl::sample_rate_changed ()
1477 DEBUG_ECONTROL ("sample_rate_changed");
1478 /* reset the strings for buffer size to show the correct msec value
1479 (reflecting the new sample rate).
1482 show_buffer_duration ();
1487 EngineControl::buffer_size_changed ()
1489 DEBUG_ECONTROL ("buffer_size_changed");
1490 show_buffer_duration ();
1494 EngineControl::show_buffer_duration ()
1496 DEBUG_ECONTROL ("show_buffer_duration");
1497 /* buffer sizes - convert from just samples to samples + msecs for
1498 * the displayed string
1501 string bs_text = buffer_size_combo.get_active_text ();
1502 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1503 uint32_t rate = get_rate();
1505 /* Developers: note the hard-coding of a double buffered model
1506 in the (2 * samples) computation of latency. we always start
1507 the audiobackend in this configuration.
1509 /* note to jack1 developers: ardour also always starts the engine
1510 * in async mode (no jack2 --sync option) which adds an extra cycle
1511 * of latency with jack2 (and *3 would be correct)
1512 * The value can also be wrong if jackd is started externally..
1514 * At the time of writing the ALSA backend always uses double-buffering *2,
1515 * The Dummy backend *1, and who knows what ASIO really does :)
1517 * So just display the period size, that's also what
1518 * ARDOUR_UI::update_sample_rate() does for the status bar.
1519 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1520 * but still, that's the buffer period, not [round-trip] latency)
1523 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1524 buffer_size_duration_label.set_text (buf);
1528 EngineControl::midi_option_changed ()
1530 DEBUG_ECONTROL ("midi_option_changed");
1531 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1534 backend->set_midi_option (get_midi_option());
1536 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1538 //_midi_devices.clear(); // TODO merge with state-saved settings..
1539 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1540 std::vector<MidiDeviceSettings> new_devices;
1542 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1543 MidiDeviceSettings mds = find_midi_device (i->name);
1544 if (i->available && !mds) {
1545 uint32_t input_latency = 0;
1546 uint32_t output_latency = 0;
1547 if (_can_set_midi_latencies) {
1548 input_latency = backend->systemic_midi_input_latency (i->name);
1549 output_latency = backend->systemic_midi_output_latency (i->name);
1551 bool enabled = backend->midi_device_enabled (i->name);
1552 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1553 new_devices.push_back (ptr);
1554 } else if (i->available) {
1555 new_devices.push_back (mds);
1558 _midi_devices = new_devices;
1560 if (_midi_devices.empty()) {
1561 midi_devices_button.set_sensitive (false);
1563 midi_devices_button.set_sensitive (true);
1568 EngineControl::parameter_changed ()
1572 EngineControl::State
1573 EngineControl::get_matching_state (
1574 const string& backend,
1575 const string& driver,
1576 const string& device)
1578 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1579 if ((*i)->backend == backend &&
1580 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1588 EngineControl::State
1589 EngineControl::get_matching_state (
1590 const string& backend,
1591 const string& driver,
1592 const string& input_device,
1593 const string& output_device)
1595 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1596 if ((*i)->backend == backend &&
1597 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1605 EngineControl::State
1606 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1608 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1611 if (backend->use_separate_input_and_output_devices ()) {
1612 return get_matching_state (backend_combo.get_active_text(),
1613 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1614 input_device_combo.get_active_text(),
1615 output_device_combo.get_active_text());
1617 return get_matching_state (backend_combo.get_active_text(),
1618 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1619 device_combo.get_active_text());
1623 return get_matching_state (backend_combo.get_active_text(),
1625 device_combo.get_active_text());
1628 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1629 const EngineControl::State& state2)
1631 if (state1->backend == state2->backend &&
1632 state1->driver == state2->driver &&
1633 state1->device == state2->device &&
1634 state1->input_device == state2->input_device &&
1635 state1->output_device == state2->output_device) {
1641 EngineControl::State
1642 EngineControl::save_state ()
1646 if (!_have_control) {
1647 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1651 state.reset(new StateStruct);
1652 state->backend = get_backend ();
1654 state.reset(new StateStruct);
1655 store_state (state);
1658 for (StateList::iterator i = states.begin(); i != states.end();) {
1659 if (equivalent_states (*i, state)) {
1660 i = states.erase(i);
1666 states.push_back (state);
1672 EngineControl::store_state (State state)
1674 state->backend = get_backend ();
1675 state->driver = get_driver ();
1676 state->device = get_device_name ();
1677 state->input_device = get_input_device_name ();
1678 state->output_device = get_output_device_name ();
1679 state->sample_rate = get_rate ();
1680 state->buffer_size = get_buffer_size ();
1681 state->input_latency = get_input_latency ();
1682 state->output_latency = get_output_latency ();
1683 state->input_channels = get_input_channels ();
1684 state->output_channels = get_output_channels ();
1685 state->midi_option = get_midi_option ();
1686 state->midi_devices = _midi_devices;
1690 EngineControl::maybe_display_saved_state ()
1692 if (!_have_control) {
1696 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1699 DEBUG_ECONTROL ("Restoring saved state");
1700 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1702 if (!_desired_sample_rate) {
1703 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1705 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1706 /* call this explicitly because we're ignoring changes to
1707 the controls at this point.
1709 show_buffer_duration ();
1710 input_latency.set_value (state->input_latency);
1711 output_latency.set_value (state->output_latency);
1713 if (!state->midi_option.empty()) {
1714 midi_option_combo.set_active_text (state->midi_option);
1715 _midi_devices = state->midi_devices;
1718 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1723 EngineControl::get_state ()
1725 LocaleGuard lg (X_("C"));
1727 XMLNode* root = new XMLNode ("AudioMIDISetup");
1730 if (!states.empty()) {
1731 XMLNode* state_nodes = new XMLNode ("EngineStates");
1733 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1735 XMLNode* node = new XMLNode ("State");
1737 node->add_property ("backend", (*i)->backend);
1738 node->add_property ("driver", (*i)->driver);
1739 node->add_property ("device", (*i)->device);
1740 node->add_property ("input-device", (*i)->input_device);
1741 node->add_property ("output-device", (*i)->output_device);
1742 node->add_property ("sample-rate", (*i)->sample_rate);
1743 node->add_property ("buffer-size", (*i)->buffer_size);
1744 node->add_property ("input-latency", (*i)->input_latency);
1745 node->add_property ("output-latency", (*i)->output_latency);
1746 node->add_property ("input-channels", (*i)->input_channels);
1747 node->add_property ("output-channels", (*i)->output_channels);
1748 node->add_property ("active", (*i)->active ? "yes" : "no");
1749 node->add_property ("midi-option", (*i)->midi_option);
1751 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1752 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1753 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1754 midi_device_stuff->add_property (X_("name"), (*p)->name);
1755 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1756 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1757 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1758 midi_devices->add_child_nocopy (*midi_device_stuff);
1760 node->add_child_nocopy (*midi_devices);
1762 state_nodes->add_child_nocopy (*node);
1765 root->add_child_nocopy (*state_nodes);
1772 EngineControl::set_default_state ()
1774 vector<string> backend_names;
1775 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1777 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1778 backend_names.push_back ((*b)->name);
1780 backend_combo.set_active_text (backend_names.front());
1782 // We could set default backends per platform etc here
1788 EngineControl::set_state (const XMLNode& root)
1790 XMLNodeList clist, cclist;
1791 XMLNodeConstIterator citer, cciter;
1793 XMLNode* grandchild;
1794 XMLProperty* prop = NULL;
1796 fprintf (stderr, "EngineControl::set_state\n");
1798 if (root.name() != "AudioMIDISetup") {
1802 clist = root.children();
1806 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1810 if (child->name() != "EngineStates") {
1814 cclist = child->children();
1816 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1817 State state (new StateStruct);
1819 grandchild = *cciter;
1821 if (grandchild->name() != "State") {
1825 if ((prop = grandchild->property ("backend")) == 0) {
1828 state->backend = prop->value ();
1830 if ((prop = grandchild->property ("driver")) == 0) {
1833 state->driver = prop->value ();
1835 if ((prop = grandchild->property ("device")) == 0) {
1838 state->device = prop->value ();
1840 if ((prop = grandchild->property ("input-device")) == 0) {
1843 state->input_device = prop->value ();
1845 if ((prop = grandchild->property ("output-device")) == 0) {
1848 state->output_device = prop->value ();
1850 if ((prop = grandchild->property ("sample-rate")) == 0) {
1853 state->sample_rate = atof (prop->value ());
1855 if ((prop = grandchild->property ("buffer-size")) == 0) {
1858 state->buffer_size = atoi (prop->value ());
1860 if ((prop = grandchild->property ("input-latency")) == 0) {
1863 state->input_latency = atoi (prop->value ());
1865 if ((prop = grandchild->property ("output-latency")) == 0) {
1868 state->output_latency = atoi (prop->value ());
1870 if ((prop = grandchild->property ("input-channels")) == 0) {
1873 state->input_channels = atoi (prop->value ());
1875 if ((prop = grandchild->property ("output-channels")) == 0) {
1878 state->output_channels = atoi (prop->value ());
1880 if ((prop = grandchild->property ("active")) == 0) {
1883 state->active = string_is_affirmative (prop->value ());
1885 if ((prop = grandchild->property ("midi-option")) == 0) {
1888 state->midi_option = prop->value ();
1890 state->midi_devices.clear();
1892 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1893 const XMLNodeList mnc = midinode->children();
1894 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1895 if ((*n)->property (X_("name")) == 0
1896 || (*n)->property (X_("enabled")) == 0
1897 || (*n)->property (X_("input-latency")) == 0
1898 || (*n)->property (X_("output-latency")) == 0
1903 MidiDeviceSettings ptr (new MidiDeviceSetting(
1904 (*n)->property (X_("name"))->value (),
1905 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1906 atoi ((*n)->property (X_("input-latency"))->value ()),
1907 atoi ((*n)->property (X_("output-latency"))->value ())
1909 state->midi_devices.push_back (ptr);
1914 /* remove accumulated duplicates (due to bug in ealier version)
1915 * this can be removed again before release
1917 for (StateList::iterator i = states.begin(); i != states.end();) {
1918 if ((*i)->backend == state->backend &&
1919 (*i)->driver == state->driver &&
1920 (*i)->device == state->device) {
1921 i = states.erase(i);
1928 states.push_back (state);
1932 /* now see if there was an active state and switch the setup to it */
1934 // purge states of backend that are not available in this built
1935 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1936 vector<std::string> backend_names;
1938 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1939 backend_names.push_back((*i)->name);
1941 for (StateList::iterator i = states.begin(); i != states.end();) {
1942 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1943 i = states.erase(i);
1949 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1952 return set_current_state (*i);
1959 EngineControl::set_current_state (const State& state)
1961 DEBUG_ECONTROL ("set_current_state");
1963 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1965 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1966 state->backend, downcase (PROGRAM_NAME), ""))) {
1967 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1968 // this shouldn't happen as the invalid backend names should have been
1969 // removed from the list of states.
1973 // now reflect the change in the backend in the GUI so backend_changed will
1974 // do the right thing
1975 backend_combo.set_active_text (state->backend);
1977 if (!state->driver.empty ()) {
1978 if (!backend->requires_driver_selection ()) {
1979 DEBUG_ECONTROL ("Backend should require driver selection");
1980 // A backend has changed from having driver selection to not having
1981 // it or someone has been manually editing a config file and messed
1986 if (backend->set_driver (state->driver) != 0) {
1987 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1988 // Driver names for a backend have changed and the name in the
1989 // config file is now invalid or support for driver is no longer
1990 // included in the backend
1993 // no need to set the driver_combo as backend_changed will use
1994 // backend->driver_name to set the active driver
1997 if (!state->device.empty ()) {
1998 if (backend->set_device_name (state->device) != 0) {
2000 string_compose ("Unable to set device name %1", state->device));
2001 // device is no longer available on the system
2004 // no need to set active device as it will be picked up in
2005 // via backend_changed ()/set_device_popdown_strings
2008 // backend supports separate input/output devices
2009 if (backend->set_input_device_name (state->input_device) != 0) {
2010 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2011 state->input_device));
2012 // input device is no longer available on the system
2016 if (backend->set_output_device_name (state->output_device) != 0) {
2017 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2018 state->input_device));
2019 // output device is no longer available on the system
2022 // no need to set active devices as it will be picked up in via
2023 // backend_changed ()/set_*_device_popdown_strings
2028 // Now restore the state of the rest of the controls
2030 // We don't use a SignalBlocker as set_current_state is currently only
2031 // called from set_state before any signals are connected. If at some point
2032 // a more general named state mechanism is implemented and
2033 // set_current_state is called while signals are connected then a
2034 // SignalBlocker will need to be instantiated before setting these.
2036 device_combo.set_active_text (state->device);
2037 input_device_combo.set_active_text (state->input_device);
2038 output_device_combo.set_active_text (state->output_device);
2039 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2040 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2041 input_latency.set_value (state->input_latency);
2042 output_latency.set_value (state->output_latency);
2043 midi_option_combo.set_active_text (state->midi_option);
2048 EngineControl::push_state_to_backend (bool start)
2050 DEBUG_ECONTROL ("push_state_to_backend");
2051 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2057 /* figure out what is going to change */
2059 bool restart_required = false;
2060 bool was_running = ARDOUR::AudioEngine::instance()->running();
2061 bool change_driver = false;
2062 bool change_device = false;
2063 bool change_rate = false;
2064 bool change_bufsize = false;
2065 bool change_latency = false;
2066 bool change_channels = false;
2067 bool change_midi = false;
2069 uint32_t ochan = get_output_channels ();
2070 uint32_t ichan = get_input_channels ();
2072 if (_have_control) {
2074 if (started_at_least_once) {
2076 /* we can control the backend */
2078 if (backend->requires_driver_selection()) {
2079 if (get_driver() != backend->driver_name()) {
2080 change_driver = true;
2084 if (backend->use_separate_input_and_output_devices()) {
2085 if (get_input_device_name() != backend->input_device_name()) {
2086 change_device = true;
2088 if (get_output_device_name() != backend->output_device_name()) {
2089 change_device = true;
2092 if (get_device_name() != backend->device_name()) {
2093 change_device = true;
2097 if (queue_device_changed) {
2098 change_device = true;
2101 if (get_rate() != backend->sample_rate()) {
2105 if (get_buffer_size() != backend->buffer_size()) {
2106 change_bufsize = true;
2109 if (get_midi_option() != backend->midi_option()) {
2113 /* zero-requested channels means "all available" */
2116 ichan = backend->input_channels();
2120 ochan = backend->output_channels();
2123 if (ichan != backend->input_channels()) {
2124 change_channels = true;
2127 if (ochan != backend->output_channels()) {
2128 change_channels = true;
2131 if (get_input_latency() != backend->systemic_input_latency() ||
2132 get_output_latency() != backend->systemic_output_latency()) {
2133 change_latency = true;
2136 /* backend never started, so we have to force a group
2139 change_device = true;
2140 if (backend->requires_driver_selection()) {
2141 change_driver = true;
2144 change_bufsize = true;
2145 change_channels = true;
2146 change_latency = true;
2152 /* we have no control over the backend, meaning that we can
2153 * only possibly change sample rate and buffer size.
2157 if (get_rate() != backend->sample_rate()) {
2158 change_bufsize = true;
2161 if (get_buffer_size() != backend->buffer_size()) {
2162 change_bufsize = true;
2166 queue_device_changed = false;
2168 if (!_have_control) {
2170 /* We do not have control over the backend, so the best we can
2171 * do is try to change the sample rate and/or bufsize and get
2175 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2179 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2184 backend->set_sample_rate (get_rate());
2187 if (change_bufsize) {
2188 backend->set_buffer_size (get_buffer_size());
2192 if (ARDOUR::AudioEngine::instance()->start ()) {
2193 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2203 /* determine if we need to stop the backend before changing parameters */
2205 if (change_driver || change_device || change_channels || change_latency ||
2206 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2208 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2209 restart_required = true;
2211 restart_required = false;
2216 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2217 /* no changes in any parameters that absolutely require a
2218 * restart, so check those that might be changeable without a
2222 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2223 /* can't do this while running ... */
2224 restart_required = true;
2227 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2228 /* can't do this while running ... */
2229 restart_required = true;
2235 if (restart_required) {
2236 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2243 if (change_driver && backend->set_driver (get_driver())) {
2244 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2247 if (backend->use_separate_input_and_output_devices()) {
2248 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2249 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2252 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2253 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2257 if (change_device && backend->set_device_name (get_device_name())) {
2258 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2262 if (change_rate && backend->set_sample_rate (get_rate())) {
2263 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2266 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2267 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2271 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2272 if (backend->set_input_channels (get_input_channels())) {
2273 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2276 if (backend->set_output_channels (get_output_channels())) {
2277 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2281 if (change_latency) {
2282 if (backend->set_systemic_input_latency (get_input_latency())) {
2283 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2286 if (backend->set_systemic_output_latency (get_output_latency())) {
2287 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2293 backend->set_midi_option (get_midi_option());
2297 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2298 if (_measure_midi) {
2299 if (*p == _measure_midi) {
2300 backend->set_midi_device_enabled ((*p)->name, true);
2302 backend->set_midi_device_enabled ((*p)->name, false);
2306 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2307 if (backend->can_set_systemic_midi_latencies()) {
2308 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2309 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2314 if (start || (was_running && restart_required)) {
2315 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2326 EngineControl::post_push ()
2328 /* get a pointer to the current state object, creating one if
2332 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2335 state = save_state ();
2343 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2344 (*i)->active = false;
2347 /* mark this one active (to be used next time the dialog is
2351 state->active = true;
2353 if (_have_control) { // XXX
2354 manage_control_app_sensitivity ();
2357 /* schedule a redisplay of MIDI ports */
2358 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2363 EngineControl::get_rate () const
2365 float r = atof (sample_rate_combo.get_active_text ());
2366 /* the string may have been translated with an abbreviation for
2367 * thousands, so use a crude heuristic to fix this.
2377 EngineControl::get_buffer_size () const
2379 string txt = buffer_size_combo.get_active_text ();
2382 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2383 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2384 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2392 EngineControl::get_midi_option () const
2394 return midi_option_combo.get_active_text();
2398 EngineControl::get_input_channels() const
2400 if (ARDOUR::Profile->get_mixbus()) {
2401 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2402 if (!backend) return 0;
2403 return backend->input_channels();
2405 return (uint32_t) input_channels_adjustment.get_value();
2409 EngineControl::get_output_channels() const
2411 if (ARDOUR::Profile->get_mixbus()) {
2412 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2413 if (!backend) return 0;
2414 return backend->input_channels();
2416 return (uint32_t) output_channels_adjustment.get_value();
2420 EngineControl::get_input_latency() const
2422 return (uint32_t) input_latency_adjustment.get_value();
2426 EngineControl::get_output_latency() const
2428 return (uint32_t) output_latency_adjustment.get_value();
2432 EngineControl::get_backend () const
2434 return backend_combo.get_active_text ();
2438 EngineControl::get_driver () const
2440 if (driver_combo.get_parent()) {
2441 return driver_combo.get_active_text ();
2448 EngineControl::get_device_name () const
2450 return device_combo.get_active_text ();
2454 EngineControl::get_input_device_name () const
2456 return input_device_combo.get_active_text ();
2460 EngineControl::get_output_device_name () const
2462 return output_device_combo.get_active_text ();
2466 EngineControl::control_app_button_clicked ()
2468 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2474 backend->launch_control_app ();
2478 EngineControl::start_stop_button_clicked ()
2480 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2486 if (ARDOUR::AudioEngine::instance()->running()) {
2487 ARDOUR::AudioEngine::instance()->stop ();
2489 push_state_to_backend (true);
2494 EngineControl::update_devices_button_clicked ()
2496 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2502 if (backend->update_devices()) {
2503 device_list_changed ();
2508 EngineControl::manage_control_app_sensitivity ()
2510 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2516 string appname = backend->control_app_name();
2518 if (appname.empty()) {
2519 control_app_button.set_sensitive (false);
2521 control_app_button.set_sensitive (true);
2526 EngineControl::set_desired_sample_rate (uint32_t sr)
2528 _desired_sample_rate = sr;
2533 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2535 if (page_num == 0) {
2536 cancel_button->set_sensitive (true);
2537 _measure_midi.reset();
2538 update_sensitivity ();
2540 cancel_button->set_sensitive (false);
2541 ok_button->set_sensitive (false);
2544 if (page_num == midi_tab) {
2546 refresh_midi_display ();
2549 if (page_num == latency_tab) {
2552 if (ARDOUR::AudioEngine::instance()->running()) {
2553 // TODO - mark as 'stopped for latency
2554 ARDOUR_UI::instance()->disconnect_from_engine ();
2558 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2560 /* save any existing latency values */
2562 uint32_t il = (uint32_t) input_latency.get_value ();
2563 uint32_t ol = (uint32_t) input_latency.get_value ();
2565 /* reset to zero so that our new test instance
2566 will be clean of any existing latency measures.
2568 NB. this should really be done by the backend
2569 when stated for latency measurement.
2572 input_latency.set_value (0);
2573 output_latency.set_value (0);
2575 push_state_to_backend (false);
2579 input_latency.set_value (il);
2580 output_latency.set_value (ol);
2583 // This should be done in push_state_to_backend()
2584 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2585 disable_latency_tab ();
2588 enable_latency_tab ();
2592 end_latency_detection ();
2593 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2598 /* latency measurement */
2601 EngineControl::check_audio_latency_measurement ()
2603 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2605 if (mtdm->resolve () < 0) {
2606 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2610 if (mtdm->err () > 0.3) {
2616 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2618 if (sample_rate == 0) {
2619 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2620 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2624 int frames_total = mtdm->del();
2625 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2627 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2628 _("Detected roundtrip latency: "),
2629 frames_total, frames_total * 1000.0f/sample_rate,
2630 _("Systemic latency: "),
2631 extra, extra * 1000.0f/sample_rate);
2635 if (mtdm->err () > 0.2) {
2637 strcat (buf, _("(signal detection error)"));
2643 strcat (buf, _("(inverted - bad wiring)"));
2647 lm_results.set_markup (string_compose (results_markup, buf));
2650 have_lm_results = true;
2651 end_latency_detection ();
2652 lm_use_button.set_sensitive (true);
2660 EngineControl::check_midi_latency_measurement ()
2662 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2664 if (!mididm->have_signal () || mididm->latency () == 0) {
2665 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2670 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2672 if (sample_rate == 0) {
2673 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2674 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2678 ARDOUR::framecnt_t frames_total = mididm->latency();
2679 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2680 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2681 _("Detected roundtrip latency: "),
2682 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2683 _("Systemic latency: "),
2684 extra, extra * 1000.0f / sample_rate);
2688 if (!mididm->ok ()) {
2690 strcat (buf, _("(averaging)"));
2694 if (mididm->deviation () > 50.0) {
2696 strcat (buf, _("(too large jitter)"));
2698 } else if (mididm->deviation () > 10.0) {
2700 strcat (buf, _("(large jitter)"));
2704 have_lm_results = true;
2705 end_latency_detection ();
2706 lm_use_button.set_sensitive (true);
2707 lm_results.set_markup (string_compose (results_markup, buf));
2709 } else if (mididm->processed () > 400) {
2710 have_lm_results = false;
2711 end_latency_detection ();
2712 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2716 lm_results.set_markup (string_compose (results_markup, buf));
2722 EngineControl::start_latency_detection ()
2724 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2725 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2727 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2728 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2729 if (_measure_midi) {
2730 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2732 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2734 lm_measure_label.set_text (_("Cancel"));
2735 have_lm_results = false;
2736 lm_use_button.set_sensitive (false);
2737 lm_input_channel_combo.set_sensitive (false);
2738 lm_output_channel_combo.set_sensitive (false);
2744 EngineControl::end_latency_detection ()
2746 latency_timeout.disconnect ();
2747 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2748 lm_measure_label.set_text (_("Measure"));
2749 if (!have_lm_results) {
2750 lm_use_button.set_sensitive (false);
2752 lm_input_channel_combo.set_sensitive (true);
2753 lm_output_channel_combo.set_sensitive (true);
2758 EngineControl::latency_button_clicked ()
2761 start_latency_detection ();
2763 end_latency_detection ();
2768 EngineControl::use_latency_button_clicked ()
2770 if (_measure_midi) {
2771 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2775 ARDOUR::framecnt_t frames_total = mididm->latency();
2776 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2777 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2778 _measure_midi->input_latency = one_way;
2779 _measure_midi->output_latency = one_way;
2780 notebook.set_current_page (midi_tab);
2782 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2788 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2789 one_way = std::max (0., one_way);
2791 input_latency_adjustment.set_value (one_way);
2792 output_latency_adjustment.set_value (one_way);
2794 /* back to settings page */
2795 notebook.set_current_page (0);
2801 EngineControl::on_delete_event (GdkEventAny* ev)
2803 if (notebook.get_current_page() == 2) {
2804 /* currently on latency tab - be sure to clean up */
2805 end_latency_detection ();
2807 return ArdourDialog::on_delete_event (ev);
2811 EngineControl::engine_running ()
2813 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2816 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2817 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2819 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2820 connect_disconnect_button.show();
2822 started_at_least_once = true;
2823 if (_have_control) {
2824 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2826 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2828 update_sensitivity();
2832 EngineControl::engine_stopped ()
2834 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2837 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2838 connect_disconnect_button.show();
2840 if (_have_control) {
2841 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2843 engine_status.set_markup(X_(""));
2846 update_sensitivity();
2850 EngineControl::device_list_changed ()
2852 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2854 midi_option_changed();
2858 EngineControl::connect_disconnect_click()
2860 if (ARDOUR::AudioEngine::instance()->running()) {
2861 ARDOUR_UI::instance()->disconnect_from_engine ();
2863 ARDOUR_UI::instance()->reconnect_to_engine ();
2868 EngineControl::calibrate_audio_latency ()
2870 _measure_midi.reset ();
2871 have_lm_results = false;
2872 lm_use_button.set_sensitive (false);
2873 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2874 notebook.set_current_page (latency_tab);
2878 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2881 have_lm_results = false;
2882 lm_use_button.set_sensitive (false);
2883 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2884 notebook.set_current_page (latency_tab);
2888 EngineControl::configure_midi_devices ()
2890 notebook.set_current_page (midi_tab);