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 set_popdown_strings (buffer_size_combo, s);
1358 buffer_size_combo.set_active_text (s.front());
1360 uint32_t period = backend->buffer_size();
1361 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1362 period = backend->default_buffer_size (get_input_device_name ());
1364 if (0 == period && backend->use_separate_input_and_output_devices ()) {
1365 period = backend->default_buffer_size (get_output_device_name ());
1367 if (0 == period && !backend->use_separate_input_and_output_devices ()) {
1368 period = backend->default_buffer_size (get_device_name ());
1371 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1372 show_buffer_duration ();
1374 update_sensitivity ();
1378 EngineControl::device_changed ()
1380 SignalBlocker blocker (*this, "device_changed");
1381 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1384 string device_name_in;
1385 string device_name_out; // only used if backend support separate I/O devices
1387 if (backend->use_separate_input_and_output_devices()) {
1388 device_name_in = get_input_device_name ();
1389 device_name_out = get_output_device_name ();
1391 device_name_in = get_device_name ();
1394 /* we set the backend-device to query various device related intormation.
1395 * This has the side effect that backend->device_name() will match
1396 * the device_name and 'change_device' will never be true.
1397 * so work around this by setting...
1399 if (backend->use_separate_input_and_output_devices()) {
1400 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1401 queue_device_changed = true;
1404 if (device_name_in != backend->device_name()) {
1405 queue_device_changed = true;
1409 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1410 if (backend->use_separate_input_and_output_devices()) {
1411 backend->set_input_device_name (device_name_in);
1412 backend->set_output_device_name (device_name_out);
1414 backend->set_device_name(device_name_in);
1418 /* don't allow programmatic change to combos to cause a
1419 recursive call to this method.
1421 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1423 set_samplerate_popdown_strings ();
1424 set_buffersize_popdown_strings ();
1426 /* TODO set min + max channel counts here */
1428 manage_control_app_sensitivity ();
1431 /* pick up any saved state for this device */
1433 if (!ignore_changes) {
1434 maybe_display_saved_state ();
1439 EngineControl::input_device_changed ()
1441 DEBUG_ECONTROL ("input_device_changed");
1446 EngineControl::output_device_changed ()
1448 DEBUG_ECONTROL ("output_device_changed");
1453 EngineControl::bufsize_as_string (uint32_t sz)
1455 /* Translators: "samples" is always plural here, so no
1456 need for plural+singular forms.
1459 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1464 EngineControl::sample_rate_changed ()
1466 DEBUG_ECONTROL ("sample_rate_changed");
1467 /* reset the strings for buffer size to show the correct msec value
1468 (reflecting the new sample rate).
1471 show_buffer_duration ();
1476 EngineControl::buffer_size_changed ()
1478 DEBUG_ECONTROL ("buffer_size_changed");
1479 show_buffer_duration ();
1483 EngineControl::show_buffer_duration ()
1485 DEBUG_ECONTROL ("show_buffer_duration");
1486 /* buffer sizes - convert from just samples to samples + msecs for
1487 * the displayed string
1490 string bs_text = buffer_size_combo.get_active_text ();
1491 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1492 uint32_t rate = get_rate();
1494 /* Developers: note the hard-coding of a double buffered model
1495 in the (2 * samples) computation of latency. we always start
1496 the audiobackend in this configuration.
1498 /* note to jack1 developers: ardour also always starts the engine
1499 * in async mode (no jack2 --sync option) which adds an extra cycle
1500 * of latency with jack2 (and *3 would be correct)
1501 * The value can also be wrong if jackd is started externally..
1503 * At the time of writing the ALSA backend always uses double-buffering *2,
1504 * The Dummy backend *1, and who knows what ASIO really does :)
1506 * So just display the period size, that's also what
1507 * ARDOUR_UI::update_sample_rate() does for the status bar.
1508 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1509 * but still, that's the buffer period, not [round-trip] latency)
1512 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1513 buffer_size_duration_label.set_text (buf);
1517 EngineControl::midi_option_changed ()
1519 DEBUG_ECONTROL ("midi_option_changed");
1520 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1523 backend->set_midi_option (get_midi_option());
1525 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1527 //_midi_devices.clear(); // TODO merge with state-saved settings..
1528 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1529 std::vector<MidiDeviceSettings> new_devices;
1531 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1532 MidiDeviceSettings mds = find_midi_device (i->name);
1533 if (i->available && !mds) {
1534 uint32_t input_latency = 0;
1535 uint32_t output_latency = 0;
1536 if (_can_set_midi_latencies) {
1537 input_latency = backend->systemic_midi_input_latency (i->name);
1538 output_latency = backend->systemic_midi_output_latency (i->name);
1540 bool enabled = backend->midi_device_enabled (i->name);
1541 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1542 new_devices.push_back (ptr);
1543 } else if (i->available) {
1544 new_devices.push_back (mds);
1547 _midi_devices = new_devices;
1549 if (_midi_devices.empty()) {
1550 midi_devices_button.set_sensitive (false);
1552 midi_devices_button.set_sensitive (true);
1557 EngineControl::parameter_changed ()
1561 EngineControl::State
1562 EngineControl::get_matching_state (
1563 const string& backend,
1564 const string& driver,
1565 const string& device)
1567 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1568 if ((*i)->backend == backend &&
1569 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1577 EngineControl::State
1578 EngineControl::get_matching_state (
1579 const string& backend,
1580 const string& driver,
1581 const string& input_device,
1582 const string& output_device)
1584 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1585 if ((*i)->backend == backend &&
1586 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1594 EngineControl::State
1595 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1597 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1600 if (backend->use_separate_input_and_output_devices ()) {
1601 return get_matching_state (backend_combo.get_active_text(),
1602 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1603 input_device_combo.get_active_text(),
1604 output_device_combo.get_active_text());
1606 return get_matching_state (backend_combo.get_active_text(),
1607 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1608 device_combo.get_active_text());
1612 return get_matching_state (backend_combo.get_active_text(),
1614 device_combo.get_active_text());
1617 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1618 const EngineControl::State& state2)
1620 if (state1->backend == state2->backend &&
1621 state1->driver == state2->driver &&
1622 state1->device == state2->device &&
1623 state1->input_device == state2->input_device &&
1624 state1->output_device == state2->output_device) {
1630 EngineControl::State
1631 EngineControl::save_state ()
1635 if (!_have_control) {
1636 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1640 state.reset(new StateStruct);
1641 state->backend = get_backend ();
1643 state.reset(new StateStruct);
1644 store_state (state);
1647 for (StateList::iterator i = states.begin(); i != states.end();) {
1648 if (equivalent_states (*i, state)) {
1649 i = states.erase(i);
1655 states.push_back (state);
1661 EngineControl::store_state (State state)
1663 state->backend = get_backend ();
1664 state->driver = get_driver ();
1665 state->device = get_device_name ();
1666 state->input_device = get_input_device_name ();
1667 state->output_device = get_output_device_name ();
1668 state->sample_rate = get_rate ();
1669 state->buffer_size = get_buffer_size ();
1670 state->input_latency = get_input_latency ();
1671 state->output_latency = get_output_latency ();
1672 state->input_channels = get_input_channels ();
1673 state->output_channels = get_output_channels ();
1674 state->midi_option = get_midi_option ();
1675 state->midi_devices = _midi_devices;
1679 EngineControl::maybe_display_saved_state ()
1681 if (!_have_control) {
1685 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1688 DEBUG_ECONTROL ("Restoring saved state");
1689 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1691 if (!_desired_sample_rate) {
1692 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1694 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1695 /* call this explicitly because we're ignoring changes to
1696 the controls at this point.
1698 show_buffer_duration ();
1699 input_latency.set_value (state->input_latency);
1700 output_latency.set_value (state->output_latency);
1702 if (!state->midi_option.empty()) {
1703 midi_option_combo.set_active_text (state->midi_option);
1704 _midi_devices = state->midi_devices;
1707 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1712 EngineControl::get_state ()
1714 LocaleGuard lg (X_("C"));
1716 XMLNode* root = new XMLNode ("AudioMIDISetup");
1719 if (!states.empty()) {
1720 XMLNode* state_nodes = new XMLNode ("EngineStates");
1722 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1724 XMLNode* node = new XMLNode ("State");
1726 node->add_property ("backend", (*i)->backend);
1727 node->add_property ("driver", (*i)->driver);
1728 node->add_property ("device", (*i)->device);
1729 node->add_property ("input-device", (*i)->input_device);
1730 node->add_property ("output-device", (*i)->output_device);
1731 node->add_property ("sample-rate", (*i)->sample_rate);
1732 node->add_property ("buffer-size", (*i)->buffer_size);
1733 node->add_property ("input-latency", (*i)->input_latency);
1734 node->add_property ("output-latency", (*i)->output_latency);
1735 node->add_property ("input-channels", (*i)->input_channels);
1736 node->add_property ("output-channels", (*i)->output_channels);
1737 node->add_property ("active", (*i)->active ? "yes" : "no");
1738 node->add_property ("midi-option", (*i)->midi_option);
1740 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1741 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1742 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1743 midi_device_stuff->add_property (X_("name"), (*p)->name);
1744 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1745 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1746 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1747 midi_devices->add_child_nocopy (*midi_device_stuff);
1749 node->add_child_nocopy (*midi_devices);
1751 state_nodes->add_child_nocopy (*node);
1754 root->add_child_nocopy (*state_nodes);
1761 EngineControl::set_default_state ()
1763 vector<string> backend_names;
1764 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1766 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1767 backend_names.push_back ((*b)->name);
1769 backend_combo.set_active_text (backend_names.front());
1771 // We could set default backends per platform etc here
1777 EngineControl::set_state (const XMLNode& root)
1779 XMLNodeList clist, cclist;
1780 XMLNodeConstIterator citer, cciter;
1782 XMLNode* grandchild;
1783 XMLProperty* prop = NULL;
1785 fprintf (stderr, "EngineControl::set_state\n");
1787 if (root.name() != "AudioMIDISetup") {
1791 clist = root.children();
1795 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1799 if (child->name() != "EngineStates") {
1803 cclist = child->children();
1805 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1806 State state (new StateStruct);
1808 grandchild = *cciter;
1810 if (grandchild->name() != "State") {
1814 if ((prop = grandchild->property ("backend")) == 0) {
1817 state->backend = prop->value ();
1819 if ((prop = grandchild->property ("driver")) == 0) {
1822 state->driver = prop->value ();
1824 if ((prop = grandchild->property ("device")) == 0) {
1827 state->device = prop->value ();
1829 if ((prop = grandchild->property ("input-device")) == 0) {
1832 state->input_device = prop->value ();
1834 if ((prop = grandchild->property ("output-device")) == 0) {
1837 state->output_device = prop->value ();
1839 if ((prop = grandchild->property ("sample-rate")) == 0) {
1842 state->sample_rate = atof (prop->value ());
1844 if ((prop = grandchild->property ("buffer-size")) == 0) {
1847 state->buffer_size = atoi (prop->value ());
1849 if ((prop = grandchild->property ("input-latency")) == 0) {
1852 state->input_latency = atoi (prop->value ());
1854 if ((prop = grandchild->property ("output-latency")) == 0) {
1857 state->output_latency = atoi (prop->value ());
1859 if ((prop = grandchild->property ("input-channels")) == 0) {
1862 state->input_channels = atoi (prop->value ());
1864 if ((prop = grandchild->property ("output-channels")) == 0) {
1867 state->output_channels = atoi (prop->value ());
1869 if ((prop = grandchild->property ("active")) == 0) {
1872 state->active = string_is_affirmative (prop->value ());
1874 if ((prop = grandchild->property ("midi-option")) == 0) {
1877 state->midi_option = prop->value ();
1879 state->midi_devices.clear();
1881 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1882 const XMLNodeList mnc = midinode->children();
1883 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1884 if ((*n)->property (X_("name")) == 0
1885 || (*n)->property (X_("enabled")) == 0
1886 || (*n)->property (X_("input-latency")) == 0
1887 || (*n)->property (X_("output-latency")) == 0
1892 MidiDeviceSettings ptr (new MidiDeviceSetting(
1893 (*n)->property (X_("name"))->value (),
1894 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1895 atoi ((*n)->property (X_("input-latency"))->value ()),
1896 atoi ((*n)->property (X_("output-latency"))->value ())
1898 state->midi_devices.push_back (ptr);
1903 /* remove accumulated duplicates (due to bug in ealier version)
1904 * this can be removed again before release
1906 for (StateList::iterator i = states.begin(); i != states.end();) {
1907 if ((*i)->backend == state->backend &&
1908 (*i)->driver == state->driver &&
1909 (*i)->device == state->device) {
1910 i = states.erase(i);
1917 states.push_back (state);
1921 /* now see if there was an active state and switch the setup to it */
1923 // purge states of backend that are not available in this built
1924 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1925 vector<std::string> backend_names;
1927 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1928 backend_names.push_back((*i)->name);
1930 for (StateList::iterator i = states.begin(); i != states.end();) {
1931 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1932 i = states.erase(i);
1938 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1941 return set_current_state (*i);
1948 EngineControl::set_current_state (const State& state)
1950 DEBUG_ECONTROL ("set_current_state");
1952 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1954 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
1955 state->backend, downcase (PROGRAM_NAME), ""))) {
1956 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
1957 // this shouldn't happen as the invalid backend names should have been
1958 // removed from the list of states.
1962 // now reflect the change in the backend in the GUI so backend_changed will
1963 // do the right thing
1964 backend_combo.set_active_text (state->backend);
1966 if (!state->driver.empty ()) {
1967 if (!backend->requires_driver_selection ()) {
1968 DEBUG_ECONTROL ("Backend should require driver selection");
1969 // A backend has changed from having driver selection to not having
1970 // it or someone has been manually editing a config file and messed
1975 if (backend->set_driver (state->driver) != 0) {
1976 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
1977 // Driver names for a backend have changed and the name in the
1978 // config file is now invalid or support for driver is no longer
1979 // included in the backend
1982 // no need to set the driver_combo as backend_changed will use
1983 // backend->driver_name to set the active driver
1986 if (!state->device.empty ()) {
1987 if (backend->set_device_name (state->device) != 0) {
1989 string_compose ("Unable to set device name %1", state->device));
1990 // device is no longer available on the system
1993 // no need to set active device as it will be picked up in
1994 // via backend_changed ()/set_device_popdown_strings
1997 // backend supports separate input/output devices
1998 if (backend->set_input_device_name (state->input_device) != 0) {
1999 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2000 state->input_device));
2001 // input device is no longer available on the system
2005 if (backend->set_output_device_name (state->output_device) != 0) {
2006 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2007 state->input_device));
2008 // output device is no longer available on the system
2011 // no need to set active devices as it will be picked up in via
2012 // backend_changed ()/set_*_device_popdown_strings
2017 // Now restore the state of the rest of the controls
2019 // We don't use a SignalBlocker as set_current_state is currently only
2020 // called from set_state before any signals are connected. If at some point
2021 // a more general named state mechanism is implemented and
2022 // set_current_state is called while signals are connected then a
2023 // SignalBlocker will need to be instantiated before setting these.
2025 device_combo.set_active_text (state->device);
2026 input_device_combo.set_active_text (state->input_device);
2027 output_device_combo.set_active_text (state->output_device);
2028 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2029 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2030 input_latency.set_value (state->input_latency);
2031 output_latency.set_value (state->output_latency);
2032 midi_option_combo.set_active_text (state->midi_option);
2037 EngineControl::push_state_to_backend (bool start)
2039 DEBUG_ECONTROL ("push_state_to_backend");
2040 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2046 /* figure out what is going to change */
2048 bool restart_required = false;
2049 bool was_running = ARDOUR::AudioEngine::instance()->running();
2050 bool change_driver = false;
2051 bool change_device = false;
2052 bool change_rate = false;
2053 bool change_bufsize = false;
2054 bool change_latency = false;
2055 bool change_channels = false;
2056 bool change_midi = false;
2058 uint32_t ochan = get_output_channels ();
2059 uint32_t ichan = get_input_channels ();
2061 if (_have_control) {
2063 if (started_at_least_once) {
2065 /* we can control the backend */
2067 if (backend->requires_driver_selection()) {
2068 if (get_driver() != backend->driver_name()) {
2069 change_driver = true;
2073 if (backend->use_separate_input_and_output_devices()) {
2074 if (get_input_device_name() != backend->input_device_name()) {
2075 change_device = true;
2077 if (get_output_device_name() != backend->output_device_name()) {
2078 change_device = true;
2081 if (get_device_name() != backend->device_name()) {
2082 change_device = true;
2086 if (queue_device_changed) {
2087 change_device = true;
2090 if (get_rate() != backend->sample_rate()) {
2094 if (get_buffer_size() != backend->buffer_size()) {
2095 change_bufsize = true;
2098 if (get_midi_option() != backend->midi_option()) {
2102 /* zero-requested channels means "all available" */
2105 ichan = backend->input_channels();
2109 ochan = backend->output_channels();
2112 if (ichan != backend->input_channels()) {
2113 change_channels = true;
2116 if (ochan != backend->output_channels()) {
2117 change_channels = true;
2120 if (get_input_latency() != backend->systemic_input_latency() ||
2121 get_output_latency() != backend->systemic_output_latency()) {
2122 change_latency = true;
2125 /* backend never started, so we have to force a group
2128 change_device = true;
2129 if (backend->requires_driver_selection()) {
2130 change_driver = true;
2133 change_bufsize = true;
2134 change_channels = true;
2135 change_latency = true;
2141 /* we have no control over the backend, meaning that we can
2142 * only possibly change sample rate and buffer size.
2146 if (get_rate() != backend->sample_rate()) {
2147 change_bufsize = true;
2150 if (get_buffer_size() != backend->buffer_size()) {
2151 change_bufsize = true;
2155 queue_device_changed = false;
2157 if (!_have_control) {
2159 /* We do not have control over the backend, so the best we can
2160 * do is try to change the sample rate and/or bufsize and get
2164 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2168 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2173 backend->set_sample_rate (get_rate());
2176 if (change_bufsize) {
2177 backend->set_buffer_size (get_buffer_size());
2181 if (ARDOUR::AudioEngine::instance()->start ()) {
2182 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2192 /* determine if we need to stop the backend before changing parameters */
2194 if (change_driver || change_device || change_channels || change_latency ||
2195 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2197 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2198 restart_required = true;
2200 restart_required = false;
2205 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2206 /* no changes in any parameters that absolutely require a
2207 * restart, so check those that might be changeable without a
2211 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2212 /* can't do this while running ... */
2213 restart_required = true;
2216 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2217 /* can't do this while running ... */
2218 restart_required = true;
2224 if (restart_required) {
2225 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
2232 if (change_driver && backend->set_driver (get_driver())) {
2233 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2236 if (backend->use_separate_input_and_output_devices()) {
2237 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2238 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2241 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2242 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2246 if (change_device && backend->set_device_name (get_device_name())) {
2247 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2251 if (change_rate && backend->set_sample_rate (get_rate())) {
2252 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2255 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2256 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2260 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2261 if (backend->set_input_channels (get_input_channels())) {
2262 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2265 if (backend->set_output_channels (get_output_channels())) {
2266 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2270 if (change_latency) {
2271 if (backend->set_systemic_input_latency (get_input_latency())) {
2272 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2275 if (backend->set_systemic_output_latency (get_output_latency())) {
2276 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2282 backend->set_midi_option (get_midi_option());
2286 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2287 if (_measure_midi) {
2288 if (*p == _measure_midi) {
2289 backend->set_midi_device_enabled ((*p)->name, true);
2291 backend->set_midi_device_enabled ((*p)->name, false);
2295 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2296 if (backend->can_set_systemic_midi_latencies()) {
2297 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2298 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2303 if (start || (was_running && restart_required)) {
2304 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2315 EngineControl::post_push ()
2317 /* get a pointer to the current state object, creating one if
2321 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2324 state = save_state ();
2332 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2333 (*i)->active = false;
2336 /* mark this one active (to be used next time the dialog is
2340 state->active = true;
2342 if (_have_control) { // XXX
2343 manage_control_app_sensitivity ();
2346 /* schedule a redisplay of MIDI ports */
2347 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2352 EngineControl::get_rate () const
2354 float r = atof (sample_rate_combo.get_active_text ());
2355 /* the string may have been translated with an abbreviation for
2356 * thousands, so use a crude heuristic to fix this.
2366 EngineControl::get_buffer_size () const
2368 string txt = buffer_size_combo.get_active_text ();
2371 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2372 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2373 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2381 EngineControl::get_midi_option () const
2383 return midi_option_combo.get_active_text();
2387 EngineControl::get_input_channels() const
2389 if (ARDOUR::Profile->get_mixbus()) {
2390 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2391 if (!backend) return 0;
2392 return backend->input_channels();
2394 return (uint32_t) input_channels_adjustment.get_value();
2398 EngineControl::get_output_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) output_channels_adjustment.get_value();
2409 EngineControl::get_input_latency() const
2411 return (uint32_t) input_latency_adjustment.get_value();
2415 EngineControl::get_output_latency() const
2417 return (uint32_t) output_latency_adjustment.get_value();
2421 EngineControl::get_backend () const
2423 return backend_combo.get_active_text ();
2427 EngineControl::get_driver () const
2429 if (driver_combo.get_parent()) {
2430 return driver_combo.get_active_text ();
2437 EngineControl::get_device_name () const
2439 return device_combo.get_active_text ();
2443 EngineControl::get_input_device_name () const
2445 return input_device_combo.get_active_text ();
2449 EngineControl::get_output_device_name () const
2451 return output_device_combo.get_active_text ();
2455 EngineControl::control_app_button_clicked ()
2457 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2463 backend->launch_control_app ();
2467 EngineControl::start_stop_button_clicked ()
2469 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2475 if (ARDOUR::AudioEngine::instance()->running()) {
2476 ARDOUR::AudioEngine::instance()->stop ();
2478 push_state_to_backend (true);
2483 EngineControl::update_devices_button_clicked ()
2485 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2491 if (backend->update_devices()) {
2492 device_list_changed ();
2497 EngineControl::manage_control_app_sensitivity ()
2499 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2505 string appname = backend->control_app_name();
2507 if (appname.empty()) {
2508 control_app_button.set_sensitive (false);
2510 control_app_button.set_sensitive (true);
2515 EngineControl::set_desired_sample_rate (uint32_t sr)
2517 _desired_sample_rate = sr;
2522 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2524 if (page_num == 0) {
2525 cancel_button->set_sensitive (true);
2526 _measure_midi.reset();
2527 update_sensitivity ();
2529 cancel_button->set_sensitive (false);
2530 ok_button->set_sensitive (false);
2533 if (page_num == midi_tab) {
2535 refresh_midi_display ();
2538 if (page_num == latency_tab) {
2541 if (ARDOUR::AudioEngine::instance()->running()) {
2542 // TODO - mark as 'stopped for latency
2543 ARDOUR_UI::instance()->disconnect_from_engine ();
2547 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2549 /* save any existing latency values */
2551 uint32_t il = (uint32_t) input_latency.get_value ();
2552 uint32_t ol = (uint32_t) input_latency.get_value ();
2554 /* reset to zero so that our new test instance
2555 will be clean of any existing latency measures.
2557 NB. this should really be done by the backend
2558 when stated for latency measurement.
2561 input_latency.set_value (0);
2562 output_latency.set_value (0);
2564 push_state_to_backend (false);
2568 input_latency.set_value (il);
2569 output_latency.set_value (ol);
2572 // This should be done in push_state_to_backend()
2573 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2574 disable_latency_tab ();
2577 enable_latency_tab ();
2581 end_latency_detection ();
2582 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2587 /* latency measurement */
2590 EngineControl::check_audio_latency_measurement ()
2592 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2594 if (mtdm->resolve () < 0) {
2595 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2599 if (mtdm->err () > 0.3) {
2605 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2607 if (sample_rate == 0) {
2608 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2609 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2613 int frames_total = mtdm->del();
2614 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2616 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2617 _("Detected roundtrip latency: "),
2618 frames_total, frames_total * 1000.0f/sample_rate,
2619 _("Systemic latency: "),
2620 extra, extra * 1000.0f/sample_rate);
2624 if (mtdm->err () > 0.2) {
2626 strcat (buf, _("(signal detection error)"));
2632 strcat (buf, _("(inverted - bad wiring)"));
2636 lm_results.set_markup (string_compose (results_markup, buf));
2639 have_lm_results = true;
2640 end_latency_detection ();
2641 lm_use_button.set_sensitive (true);
2649 EngineControl::check_midi_latency_measurement ()
2651 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2653 if (!mididm->have_signal () || mididm->latency () == 0) {
2654 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2659 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2661 if (sample_rate == 0) {
2662 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2663 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2667 ARDOUR::framecnt_t frames_total = mididm->latency();
2668 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2669 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2670 _("Detected roundtrip latency: "),
2671 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2672 _("Systemic latency: "),
2673 extra, extra * 1000.0f / sample_rate);
2677 if (!mididm->ok ()) {
2679 strcat (buf, _("(averaging)"));
2683 if (mididm->deviation () > 50.0) {
2685 strcat (buf, _("(too large jitter)"));
2687 } else if (mididm->deviation () > 10.0) {
2689 strcat (buf, _("(large jitter)"));
2693 have_lm_results = true;
2694 end_latency_detection ();
2695 lm_use_button.set_sensitive (true);
2696 lm_results.set_markup (string_compose (results_markup, buf));
2698 } else if (mididm->processed () > 400) {
2699 have_lm_results = false;
2700 end_latency_detection ();
2701 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2705 lm_results.set_markup (string_compose (results_markup, buf));
2711 EngineControl::start_latency_detection ()
2713 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2714 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2716 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2717 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2718 if (_measure_midi) {
2719 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2721 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2723 lm_measure_label.set_text (_("Cancel"));
2724 have_lm_results = false;
2725 lm_use_button.set_sensitive (false);
2726 lm_input_channel_combo.set_sensitive (false);
2727 lm_output_channel_combo.set_sensitive (false);
2733 EngineControl::end_latency_detection ()
2735 latency_timeout.disconnect ();
2736 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2737 lm_measure_label.set_text (_("Measure"));
2738 if (!have_lm_results) {
2739 lm_use_button.set_sensitive (false);
2741 lm_input_channel_combo.set_sensitive (true);
2742 lm_output_channel_combo.set_sensitive (true);
2747 EngineControl::latency_button_clicked ()
2750 start_latency_detection ();
2752 end_latency_detection ();
2757 EngineControl::use_latency_button_clicked ()
2759 if (_measure_midi) {
2760 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2764 ARDOUR::framecnt_t frames_total = mididm->latency();
2765 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2766 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2767 _measure_midi->input_latency = one_way;
2768 _measure_midi->output_latency = one_way;
2769 notebook.set_current_page (midi_tab);
2771 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2777 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2778 one_way = std::max (0., one_way);
2780 input_latency_adjustment.set_value (one_way);
2781 output_latency_adjustment.set_value (one_way);
2783 /* back to settings page */
2784 notebook.set_current_page (0);
2790 EngineControl::on_delete_event (GdkEventAny* ev)
2792 if (notebook.get_current_page() == 2) {
2793 /* currently on latency tab - be sure to clean up */
2794 end_latency_detection ();
2796 return ArdourDialog::on_delete_event (ev);
2800 EngineControl::engine_running ()
2802 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2805 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2806 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2808 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2809 connect_disconnect_button.show();
2811 started_at_least_once = true;
2812 if (_have_control) {
2813 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2815 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2817 update_sensitivity();
2821 EngineControl::engine_stopped ()
2823 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2826 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2827 connect_disconnect_button.show();
2829 if (_have_control) {
2830 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2832 engine_status.set_markup(X_(""));
2835 update_sensitivity();
2839 EngineControl::device_list_changed ()
2841 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2843 midi_option_changed();
2847 EngineControl::connect_disconnect_click()
2849 if (ARDOUR::AudioEngine::instance()->running()) {
2850 ARDOUR_UI::instance()->disconnect_from_engine ();
2852 ARDOUR_UI::instance()->reconnect_to_engine ();
2857 EngineControl::calibrate_audio_latency ()
2859 _measure_midi.reset ();
2860 have_lm_results = false;
2861 lm_use_button.set_sensitive (false);
2862 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2863 notebook.set_current_page (latency_tab);
2867 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2870 have_lm_results = false;
2871 lm_use_button.set_sensitive (false);
2872 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2873 notebook.set_current_page (latency_tab);
2877 EngineControl::configure_midi_devices ()
2879 notebook.set_current_page (midi_tab);