2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/scoped_ptr.hpp>
27 #include <gtkmm/messagedialog.h>
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
72 EngineControl::EngineControl ()
73 : ArdourDialog (_("Audio/MIDI Setup"))
76 , input_latency_adjustment (0, 0, 99999, 1)
77 , input_latency (input_latency_adjustment)
78 , output_latency_adjustment (0, 0, 99999, 1)
79 , output_latency (output_latency_adjustment)
80 , input_channels_adjustment (0, 0, 256, 1)
81 , input_channels (input_channels_adjustment)
82 , output_channels_adjustment (0, 0, 256, 1)
83 , output_channels (output_channels_adjustment)
84 , ports_adjustment (128, 8, 1024, 1, 16)
85 , ports_spinner (ports_adjustment)
86 , control_app_button (_("Device Control Panel"))
87 , midi_devices_button (_("Midi Device Setup"))
88 , start_stop_button (_("Stop"))
89 , update_devices_button (_("Refresh Devices"))
90 , lm_measure_label (_("Measure"))
91 , lm_use_button (_("Use results"))
92 , lm_back_button (_("Back to settings ... (ignore results)"))
93 , lm_button_audio (_("Calibrate Audio"))
95 , have_lm_results (false)
97 , midi_back_button (_("Back to settings"))
99 , _desired_sample_rate (0)
100 , started_at_least_once (false)
101 , queue_device_changed (false)
102 , _have_control (true)
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(
190 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
192 lm_use_button.set_sensitive (false);
194 /* Increase the default spacing around the labels of these three
200 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
201 l->set_padding (10, 10);
204 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
205 l->set_padding (10, 10);
208 preamble = manage (new Label);
209 preamble->set_width_chars (60);
210 preamble->set_line_wrap (true);
211 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
212 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
215 preamble = manage (new Label);
216 preamble->set_width_chars (60);
217 preamble->set_line_wrap (true);
218 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
219 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
221 ++row; // skip a row in the table
222 ++row; // skip a row in the table
224 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 ++row; // skip a row in the table
227 ++row; // skip a row in the table
229 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
230 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
235 lm_vbox.set_border_width (12);
236 lm_vbox.pack_start (lm_table, false, false);
238 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
242 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
243 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
244 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
245 notebook.set_border_width (12);
247 notebook.set_show_tabs (false);
248 notebook.show_all ();
250 notebook.set_name ("SettingsNotebook");
252 /* packup the notebook */
254 get_vbox()->set_border_width (12);
255 get_vbox()->pack_start (notebook);
257 /* need a special function to print "all available channels" when the
258 * channel counts hit zero.
261 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
262 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
264 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
265 midi_devices_button.set_sensitive (false);
266 midi_devices_button.set_name ("generic button");
267 midi_devices_button.set_can_focus(true);
269 control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
270 control_app_button.set_name ("generic button");
271 control_app_button.set_can_focus(true);
272 manage_control_app_sensitivity ();
274 start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
275 start_stop_button.set_sensitive (false);
276 start_stop_button.set_name ("generic button");
277 start_stop_button.set_can_focus(true);
279 update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
280 update_devices_button.set_sensitive (false);
281 update_devices_button.set_name ("generic button");
282 update_devices_button.set_can_focus(true);
284 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
285 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
287 /* Pick up any existing audio setup configuration, if appropriate */
289 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
291 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
292 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
293 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
294 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
297 if (!set_state (*audio_setup)) {
298 set_default_state ();
301 set_default_state ();
304 connect_changed_signals ();
306 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
308 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
309 connect_disconnect_button.set_no_show_all();
314 EngineControl::connect_changed_signals ()
316 backend_combo_connection = backend_combo.signal_changed ().connect (
317 sigc::mem_fun (*this, &EngineControl::backend_changed));
318 driver_combo_connection = driver_combo.signal_changed ().connect (
319 sigc::mem_fun (*this, &EngineControl::driver_changed));
320 sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
321 sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
322 buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
323 sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
324 device_combo_connection = device_combo.signal_changed ().connect (
325 sigc::mem_fun (*this, &EngineControl::device_changed));
326 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
327 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
329 input_device_combo_connection = input_device_combo.signal_changed ().connect (
330 sigc::mem_fun (*this, &EngineControl::input_device_changed));
331 output_device_combo_connection = output_device_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::output_device_changed));
334 input_latency_connection = input_latency.signal_changed ().connect (
335 sigc::mem_fun (*this, &EngineControl::parameter_changed));
336 output_latency_connection = output_latency.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::parameter_changed));
338 input_channels_connection = input_channels.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::parameter_changed));
340 output_channels_connection = output_channels.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::parameter_changed));
345 EngineControl::block_changed_signals ()
347 if (block_signals++ == 0) {
348 DEBUG_ECONTROL ("Blocking changed signals");
349 backend_combo_connection.block ();
350 driver_combo_connection.block ();
351 sample_rate_combo_connection.block ();
352 buffer_size_combo_connection.block ();
353 device_combo_connection.block ();
354 input_device_combo_connection.block ();
355 output_device_combo_connection.block ();
356 midi_option_combo_connection.block ();
357 input_latency_connection.block ();
358 output_latency_connection.block ();
359 input_channels_connection.block ();
360 output_channels_connection.block ();
365 EngineControl::unblock_changed_signals ()
367 if (--block_signals == 0) {
368 DEBUG_ECONTROL ("Unblocking changed signals");
369 backend_combo_connection.unblock ();
370 driver_combo_connection.unblock ();
371 sample_rate_combo_connection.unblock ();
372 buffer_size_combo_connection.unblock ();
373 device_combo_connection.unblock ();
374 input_device_combo_connection.unblock ();
375 output_device_combo_connection.unblock ();
376 midi_option_combo_connection.unblock ();
377 input_latency_connection.unblock ();
378 output_latency_connection.unblock ();
379 input_channels_connection.unblock ();
380 output_channels_connection.unblock ();
384 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
385 const std::string& reason)
386 : ec (engine_control)
389 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
390 ec.block_changed_signals ();
393 EngineControl::SignalBlocker::~SignalBlocker ()
395 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
396 ec.unblock_changed_signals ();
400 EngineControl::on_show ()
402 ArdourDialog::on_show ();
403 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
404 // re-check _have_control (jackd running) see #6041
408 ok_button->grab_focus();
412 EngineControl::start_engine ()
414 if (push_state_to_backend(true) != 0) {
415 MessageDialog msg(*this,
416 ARDOUR::AudioEngine::instance()->get_last_backend_error());
424 EngineControl::stop_engine ()
426 if (ARDOUR::AudioEngine::instance()->stop()) {
427 MessageDialog msg(*this,
428 ARDOUR::AudioEngine::instance()->get_last_backend_error());
436 EngineControl::on_response (int response_id)
438 ArdourDialog::on_response (response_id);
440 switch (response_id) {
442 if (!start_engine()) {
447 #ifdef PLATFORM_WINDOWS
449 // But if there's no session open, this can produce
450 // a long gap when nothing appears to be happening.
451 // Let's show the splash image while we're waiting.
452 if (!ARDOUR_COMMAND_LINE::no_splash) {
453 if (ARDOUR_UI::instance()) {
454 if (!ARDOUR_UI::instance()->session_loaded) {
455 ARDOUR_UI::instance()->show_splash();
461 case RESPONSE_DELETE_EVENT: {
463 ev.type = GDK_BUTTON_PRESS;
465 on_delete_event((GdkEventAny*)&ev);
468 case RESPONSE_CANCEL:
469 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
470 ARDOUR_UI::instance()->check_audioengine(*this);
479 EngineControl::build_notebook ()
482 AttachOptions xopt = AttachOptions (FILL|EXPAND);
484 /* clear the table */
486 Gtkmm2ext::container_clear (basic_vbox);
487 Gtkmm2ext::container_clear (basic_packer);
489 if (control_app_button.get_parent()) {
490 control_app_button.get_parent()->remove (control_app_button);
493 label = manage (left_aligned_label (_("Audio System:")));
494 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
495 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
497 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
498 engine_status.show();
500 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
501 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
503 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
504 lm_button_audio.set_name ("generic button");
505 lm_button_audio.set_can_focus(true);
508 build_full_control_notebook ();
510 build_no_control_notebook ();
513 basic_vbox.pack_start (basic_hbox, false, false);
516 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
517 basic_vbox.show_all ();
522 EngineControl::build_full_control_notebook ()
524 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
527 using namespace Notebook_Helpers;
529 vector<string> strings;
530 AttachOptions xopt = AttachOptions (FILL|EXPAND);
531 int row = 1; // row zero == backend combo
533 /* start packing it up */
535 if (backend->requires_driver_selection()) {
536 label = manage (left_aligned_label (_("Driver:")));
537 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
538 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
542 if (backend->use_separate_input_and_output_devices()) {
543 label = manage (left_aligned_label (_("Input Device:")));
544 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
545 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
547 label = manage (left_aligned_label (_("Output Device:")));
548 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
549 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
551 // reset so it isn't used in state comparisons
552 device_combo.set_active_text ("");
554 label = manage (left_aligned_label (_("Device:")));
555 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
556 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
558 // reset these so they don't get used in state comparisons
559 input_device_combo.set_active_text ("");
560 output_device_combo.set_active_text ("");
563 label = manage (left_aligned_label (_("Sample rate:")));
564 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
565 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
569 label = manage (left_aligned_label (_("Buffer size:")));
570 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
571 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
572 buffer_size_duration_label.set_alignment (0.0); /* left-align */
573 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
575 /* button spans 2 rows */
577 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
580 input_channels.set_name ("InputChannels");
581 input_channels.set_flags (Gtk::CAN_FOCUS);
582 input_channels.set_digits (0);
583 input_channels.set_wrap (false);
584 output_channels.set_editable (true);
586 if (!ARDOUR::Profile->get_mixbus()) {
587 label = manage (left_aligned_label (_("Input Channels:")));
588 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
589 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
593 output_channels.set_name ("OutputChannels");
594 output_channels.set_flags (Gtk::CAN_FOCUS);
595 output_channels.set_digits (0);
596 output_channels.set_wrap (false);
597 output_channels.set_editable (true);
599 if (!ARDOUR::Profile->get_mixbus()) {
600 label = manage (left_aligned_label (_("Output Channels:")));
601 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
602 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
606 input_latency.set_name ("InputLatency");
607 input_latency.set_flags (Gtk::CAN_FOCUS);
608 input_latency.set_digits (0);
609 input_latency.set_wrap (false);
610 input_latency.set_editable (true);
612 label = manage (left_aligned_label (_("Hardware input latency:")));
613 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
614 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
615 label = manage (left_aligned_label (_("samples")));
616 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
619 output_latency.set_name ("OutputLatency");
620 output_latency.set_flags (Gtk::CAN_FOCUS);
621 output_latency.set_digits (0);
622 output_latency.set_wrap (false);
623 output_latency.set_editable (true);
625 label = manage (left_aligned_label (_("Hardware output latency:")));
626 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
627 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
628 label = manage (left_aligned_label (_("samples")));
629 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
631 /* button spans 2 rows */
633 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
636 label = manage (left_aligned_label (_("MIDI System:")));
637 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
638 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
639 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
640 /* Currently the only backend with dedicated Midi setup is ALSA.
641 * lot of people complain that this is greyed out
642 * "I can't use MIDI, the setup is greyed out"
644 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
650 EngineControl::build_no_control_notebook ()
652 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
655 using namespace Notebook_Helpers;
657 vector<string> strings;
658 AttachOptions xopt = AttachOptions (FILL|EXPAND);
659 int row = 1; // row zero == backend combo
660 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
662 label = manage (new Label);
663 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
664 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
667 if (backend->can_change_sample_rate_when_running()) {
668 label = manage (left_aligned_label (_("Sample rate:")));
669 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
670 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
674 if (backend->can_change_buffer_size_when_running()) {
675 label = manage (left_aligned_label (_("Buffer size:")));
676 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
677 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
678 buffer_size_duration_label.set_alignment (0.0); /* left-align */
679 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
683 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
687 EngineControl::~EngineControl ()
689 ignore_changes = true;
693 EngineControl::disable_latency_tab ()
695 vector<string> empty;
696 set_popdown_strings (lm_output_channel_combo, empty);
697 set_popdown_strings (lm_input_channel_combo, empty);
698 lm_measure_button.set_sensitive (false);
699 lm_use_button.set_sensitive (false);
703 EngineControl::enable_latency_tab ()
705 vector<string> outputs;
706 vector<string> inputs;
708 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
709 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
710 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
712 if (!ARDOUR::AudioEngine::instance()->running()) {
713 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
714 notebook.set_current_page (0);
718 else if (inputs.empty() || outputs.empty()) {
719 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
720 notebook.set_current_page (0);
725 lm_back_button_signal.disconnect();
727 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
730 lm_back_button_signal = lm_back_button.signal_clicked().connect(
731 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
735 set_popdown_strings (lm_output_channel_combo, outputs);
736 lm_output_channel_combo.set_active_text (outputs.front());
737 lm_output_channel_combo.set_sensitive (true);
739 set_popdown_strings (lm_input_channel_combo, inputs);
740 lm_input_channel_combo.set_active_text (inputs.front());
741 lm_input_channel_combo.set_sensitive (true);
743 lm_measure_button.set_sensitive (true);
747 EngineControl::setup_midi_tab_for_backend ()
749 string backend = backend_combo.get_active_text ();
751 Gtkmm2ext::container_clear (midi_vbox);
753 midi_vbox.set_border_width (12);
754 midi_device_table.set_border_width (12);
756 if (backend == "JACK") {
757 setup_midi_tab_for_jack ();
760 midi_vbox.pack_start (midi_device_table, true, true);
761 midi_vbox.pack_start (midi_back_button, false, false);
762 midi_vbox.show_all ();
766 EngineControl::update_sensitivity ()
768 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
770 ok_button->set_sensitive (false);
771 start_stop_button.set_sensitive (false);
776 size_t devices_available = 0;
778 if (backend->use_separate_input_and_output_devices ()) {
779 devices_available += get_popdown_string_count (input_device_combo);
780 devices_available += get_popdown_string_count (output_device_combo);
782 devices_available += get_popdown_string_count (device_combo);
785 if (devices_available == 0) {
787 input_latency.set_sensitive (false);
788 output_latency.set_sensitive (false);
789 input_channels.set_sensitive (false);
790 output_channels.set_sensitive (false);
792 input_latency.set_sensitive (true);
793 output_latency.set_sensitive (true);
794 input_channels.set_sensitive (true);
795 output_channels.set_sensitive (true);
798 if (get_popdown_string_count (buffer_size_combo) > 0) {
799 if (!ARDOUR::AudioEngine::instance()->running()) {
800 buffer_size_combo.set_sensitive (valid);
801 } else if (backend->can_change_sample_rate_when_running()) {
802 buffer_size_combo.set_sensitive (valid || !_have_control);
806 * Currently there is no way to manually stop the
807 * engine in order to re-configure it.
808 * This needs to remain sensitive for now.
810 * (it's also handy to implicily
811 * re-start the engine)
813 buffer_size_combo.set_sensitive (true);
815 buffer_size_combo.set_sensitive (false);
819 buffer_size_combo.set_sensitive (false);
823 if (get_popdown_string_count (sample_rate_combo) > 0) {
824 if (!ARDOUR::AudioEngine::instance()->running()) {
825 sample_rate_combo.set_sensitive (true);
827 sample_rate_combo.set_sensitive (false);
830 sample_rate_combo.set_sensitive (false);
835 start_stop_button.set_sensitive(true);
836 start_stop_button.show();
837 if (ARDOUR::AudioEngine::instance()->running()) {
838 start_stop_button.set_text("Stop");
839 update_devices_button.set_sensitive(false);
841 if (backend->can_request_update_devices()) {
842 update_devices_button.show();
844 update_devices_button.hide();
846 start_stop_button.set_text("Start");
847 update_devices_button.set_sensitive(true);
850 update_devices_button.set_sensitive(false);
851 update_devices_button.hide();
852 start_stop_button.set_sensitive(false);
853 start_stop_button.hide();
856 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
857 input_device_combo.set_sensitive (false);
858 output_device_combo.set_sensitive (false);
859 device_combo.set_sensitive (false);
860 driver_combo.set_sensitive (false);
862 input_device_combo.set_sensitive (true);
863 output_device_combo.set_sensitive (true);
864 device_combo.set_sensitive (true);
865 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
866 driver_combo.set_sensitive (true);
868 driver_combo.set_sensitive (false);
872 if (valid || !_have_control) {
873 ok_button->set_sensitive (true);
875 ok_button->set_sensitive (false);
880 EngineControl::setup_midi_tab_for_jack ()
885 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
887 device->input_latency = a->get_value();
889 device->output_latency = a->get_value();
894 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
895 b->set_active (!b->get_active());
896 device->enabled = b->get_active();
897 refresh_midi_display(device->name);
901 EngineControl::refresh_midi_display (std::string focus)
903 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
907 AttachOptions xopt = AttachOptions (FILL|EXPAND);
910 Gtkmm2ext::container_clear (midi_device_table);
912 midi_device_table.set_spacings (6);
914 l = manage (new Label);
915 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
916 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
917 l->set_alignment (0.5, 0.5);
921 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
922 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
923 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
924 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
926 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
927 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
928 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
929 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
932 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
937 bool enabled = (*p)->enabled;
939 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
940 m->set_name ("midi device");
941 m->set_can_focus (Gtk::CAN_FOCUS);
942 m->add_events (Gdk::BUTTON_RELEASE_MASK);
943 m->set_active (enabled);
944 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
945 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
946 if ((*p)->name == focus) {
950 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
951 s = manage (new Gtk::SpinButton (*a));
952 a->set_value ((*p)->input_latency);
953 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
954 s->set_sensitive (_can_set_midi_latencies && enabled);
955 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
957 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
958 s = manage (new Gtk::SpinButton (*a));
959 a->set_value ((*p)->output_latency);
960 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
961 s->set_sensitive (_can_set_midi_latencies && enabled);
962 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
964 b = manage (new Button (_("Calibrate")));
965 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
966 b->set_sensitive (_can_set_midi_latencies && enabled);
967 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
974 EngineControl::backend_changed ()
976 SignalBlocker blocker (*this, "backend_changed");
977 string backend_name = backend_combo.get_active_text();
978 boost::shared_ptr<ARDOUR::AudioBackend> backend;
980 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
981 /* eh? setting the backend failed... how ? */
982 /* A: stale config contains a backend that does not exist in current build */
986 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
988 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
991 setup_midi_tab_for_backend ();
992 _midi_devices.clear();
994 if (backend->requires_driver_selection()) {
995 if (set_driver_popdown_strings ()) {
999 /* this will change the device text which will cause a call to
1000 * device changed which will set up parameters
1005 update_midi_options ();
1007 connect_disconnect_button.hide();
1009 midi_option_changed();
1011 started_at_least_once = false;
1013 /* changing the backend implies stopping the engine
1014 * ARDOUR::AudioEngine() may or may not emit this signal
1015 * depending on previous engine state
1017 engine_stopped (); // set "active/inactive"
1019 if (!_have_control) {
1020 // set settings from backend that we do have control over
1021 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1024 if (_have_control && !ignore_changes) {
1025 // set driver & devices
1026 State state = get_matching_state (backend_combo.get_active_text());
1028 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1029 set_current_state (state);
1033 if (!ignore_changes) {
1034 maybe_display_saved_state ();
1039 EngineControl::update_midi_options ()
1041 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1042 vector<string> midi_options = backend->enumerate_midi_options();
1044 if (midi_options.size() == 1) {
1045 /* only contains the "none" option */
1046 midi_option_combo.set_sensitive (false);
1048 if (_have_control) {
1049 set_popdown_strings (midi_option_combo, midi_options);
1050 midi_option_combo.set_active_text (midi_options.front());
1051 midi_option_combo.set_sensitive (true);
1053 midi_option_combo.set_sensitive (false);
1059 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1061 if (ARDOUR::Profile->get_mixbus()) {
1065 uint32_t cnt = (uint32_t) sb->get_value();
1067 sb->set_text (_("all available channels"));
1070 snprintf (buf, sizeof (buf), "%d", cnt);
1076 // @return true if there are drivers available
1078 EngineControl::set_driver_popdown_strings ()
1080 DEBUG_ECONTROL ("set_driver_popdown_strings");
1081 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1082 vector<string> drivers = backend->enumerate_drivers();
1084 if (drivers.empty ()) {
1085 // This is an error...?
1089 string current_driver = backend->driver_name ();
1091 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1093 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1096 current_driver = drivers.front ();
1099 set_popdown_strings (driver_combo, drivers);
1101 string_compose ("driver_combo.set_active_text: %1", current_driver));
1102 driver_combo.set_active_text (current_driver);
1107 EngineControl::get_default_device(const string& current_device_name,
1108 const vector<string>& available_devices)
1110 // If the current device is available, use it as default
1111 if (std::find (available_devices.begin (),
1112 available_devices.end (),
1113 current_device_name) != available_devices.end ()) {
1115 return current_device_name;
1118 using namespace ARDOUR;
1120 string default_device_name =
1121 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1123 vector<string>::const_iterator i;
1125 // If there is a "Default" device available, use it
1126 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1127 if (*i == default_device_name) {
1132 string none_device_name =
1133 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1135 // Use the first device that isn't "None"
1136 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1137 if (*i != none_device_name) {
1142 // Use "None" if there are no other available
1143 return available_devices.front();
1146 // @return true if there are devices available
1148 EngineControl::set_device_popdown_strings ()
1150 DEBUG_ECONTROL ("set_device_popdown_strings");
1151 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1152 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1154 /* NOTE: Ardour currently does not display the "available" field of the
1157 * Doing so would require a different GUI widget than the combo
1158 * box/popdown that we currently use, since it has no way to list
1159 * items that are not selectable. Something more like a popup menu,
1160 * which could have unselectable items, would be appropriate.
1163 vector<string> available_devices;
1165 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1166 available_devices.push_back (i->name);
1169 if (available_devices.empty ()) {
1173 set_popdown_strings (device_combo, available_devices);
1175 std::string default_device =
1176 get_default_device(backend->device_name(), available_devices);
1179 string_compose ("set device_combo active text: %1", default_device));
1181 device_combo.set_active_text(default_device);
1185 // @return true if there are input devices available
1187 EngineControl::set_input_device_popdown_strings ()
1189 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1190 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1191 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1193 vector<string> available_devices;
1195 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1196 available_devices.push_back (i->name);
1199 if (available_devices.empty()) {
1203 set_popdown_strings (input_device_combo, available_devices);
1205 std::string default_device =
1206 get_default_device(backend->input_device_name(), available_devices);
1209 string_compose ("set input_device_combo active text: %1", default_device));
1210 input_device_combo.set_active_text(default_device);
1214 // @return true if there are output devices available
1216 EngineControl::set_output_device_popdown_strings ()
1218 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1219 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1220 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1222 vector<string> available_devices;
1224 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1225 available_devices.push_back (i->name);
1228 if (available_devices.empty()) {
1232 set_popdown_strings (output_device_combo, available_devices);
1234 std::string default_device =
1235 get_default_device(backend->output_device_name(), available_devices);
1238 string_compose ("set output_device_combo active text: %1", default_device));
1239 output_device_combo.set_active_text(default_device);
1244 EngineControl::list_devices ()
1246 DEBUG_ECONTROL ("list_devices");
1247 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1250 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1252 bool devices_available = false;
1254 if (backend->use_separate_input_and_output_devices ()) {
1255 bool input_devices_available = set_input_device_popdown_strings ();
1256 bool output_devices_available = set_output_device_popdown_strings ();
1257 devices_available = input_devices_available || output_devices_available;
1259 devices_available = set_device_popdown_strings ();
1262 if (devices_available) {
1265 device_combo.clear();
1266 input_device_combo.clear();
1267 output_device_combo.clear();
1269 update_sensitivity ();
1273 EngineControl::driver_changed ()
1275 SignalBlocker blocker (*this, "driver_changed");
1276 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1279 backend->set_driver (driver_combo.get_active_text());
1282 // TODO load LRU device(s) for backend + driver combo
1284 if (!ignore_changes) {
1285 maybe_display_saved_state ();
1290 EngineControl::get_sample_rates_for_all_devices ()
1292 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1293 ARDOUR::AudioEngine::instance ()->current_backend ();
1294 vector<float> all_rates;
1296 if (backend->use_separate_input_and_output_devices ()) {
1297 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1299 all_rates = backend->available_sample_rates (get_device_name ());
1305 EngineControl::get_default_sample_rates ()
1307 vector<float> rates;
1308 rates.push_back (8000.0f);
1309 rates.push_back (16000.0f);
1310 rates.push_back (32000.0f);
1311 rates.push_back (44100.0f);
1312 rates.push_back (48000.0f);
1313 rates.push_back (88200.0f);
1314 rates.push_back (96000.0f);
1315 rates.push_back (192000.0f);
1316 rates.push_back (384000.0f);
1321 EngineControl::set_samplerate_popdown_strings ()
1323 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1324 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1329 if (_have_control) {
1330 sr = get_sample_rates_for_all_devices ();
1332 sr = get_default_sample_rates ();
1335 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1336 s.push_back (rate_as_string (*x));
1337 if (*x == _desired_sample_rate) {
1342 set_popdown_strings (sample_rate_combo, s);
1345 if (desired.empty ()) {
1346 float new_active_sr = backend->default_sample_rate ();
1348 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1349 new_active_sr = sr.front ();
1352 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1354 sample_rate_combo.set_active_text (desired);
1358 update_sensitivity ();
1362 EngineControl::get_buffer_sizes_for_all_devices ()
1364 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1365 ARDOUR::AudioEngine::instance ()->current_backend ();
1366 vector<uint32_t> all_sizes;
1368 if (backend->use_separate_input_and_output_devices ()) {
1369 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1371 all_sizes = backend->available_buffer_sizes (get_device_name ());
1377 EngineControl::get_default_buffer_sizes ()
1379 vector<uint32_t> sizes;
1380 sizes.push_back (8);
1381 sizes.push_back (16);
1382 sizes.push_back (32);
1383 sizes.push_back (64);
1384 sizes.push_back (128);
1385 sizes.push_back (256);
1386 sizes.push_back (512);
1387 sizes.push_back (1024);
1388 sizes.push_back (2048);
1389 sizes.push_back (4096);
1390 sizes.push_back (8192);
1395 EngineControl::set_buffersize_popdown_strings ()
1397 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1398 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1399 vector<uint32_t> bs;
1402 if (_have_control) {
1403 bs = get_buffer_sizes_for_all_devices ();
1404 } else if (backend->can_change_buffer_size_when_running()) {
1405 bs = get_default_buffer_sizes ();
1408 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1409 s.push_back (bufsize_as_string (*x));
1412 uint32_t previous_size = 0;
1413 if (!buffer_size_combo.get_active_text().empty()) {
1414 previous_size = get_buffer_size ();
1417 set_popdown_strings (buffer_size_combo, s);
1421 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1422 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1425 buffer_size_combo.set_active_text(s.front());
1427 uint32_t period = backend->buffer_size();
1428 if (0 == period && backend->use_separate_input_and_output_devices()) {
1429 period = backend->default_buffer_size(get_input_device_name());
1431 if (0 == period && backend->use_separate_input_and_output_devices()) {
1432 period = backend->default_buffer_size(get_output_device_name());
1434 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1435 period = backend->default_buffer_size(get_device_name());
1438 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1440 show_buffer_duration ();
1442 update_sensitivity ();
1446 EngineControl::device_changed ()
1448 SignalBlocker blocker (*this, "device_changed");
1449 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1452 string device_name_in;
1453 string device_name_out; // only used if backend support separate I/O devices
1455 if (backend->use_separate_input_and_output_devices()) {
1456 device_name_in = get_input_device_name ();
1457 device_name_out = get_output_device_name ();
1459 device_name_in = get_device_name ();
1462 /* we set the backend-device to query various device related intormation.
1463 * This has the side effect that backend->device_name() will match
1464 * the device_name and 'change_device' will never be true.
1465 * so work around this by setting...
1467 if (backend->use_separate_input_and_output_devices()) {
1468 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1469 queue_device_changed = true;
1472 if (device_name_in != backend->device_name()) {
1473 queue_device_changed = true;
1477 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1478 if (backend->use_separate_input_and_output_devices()) {
1479 backend->set_input_device_name (device_name_in);
1480 backend->set_output_device_name (device_name_out);
1482 backend->set_device_name(device_name_in);
1486 /* don't allow programmatic change to combos to cause a
1487 recursive call to this method.
1489 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1491 set_samplerate_popdown_strings ();
1492 set_buffersize_popdown_strings ();
1494 /* TODO set min + max channel counts here */
1496 manage_control_app_sensitivity ();
1499 /* pick up any saved state for this device */
1501 if (!ignore_changes) {
1502 maybe_display_saved_state ();
1507 EngineControl::input_device_changed ()
1509 DEBUG_ECONTROL ("input_device_changed");
1514 EngineControl::output_device_changed ()
1516 DEBUG_ECONTROL ("output_device_changed");
1521 EngineControl::bufsize_as_string (uint32_t sz)
1523 /* Translators: "samples" is always plural here, so no
1524 need for plural+singular forms.
1527 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1532 EngineControl::sample_rate_changed ()
1534 DEBUG_ECONTROL ("sample_rate_changed");
1535 /* reset the strings for buffer size to show the correct msec value
1536 (reflecting the new sample rate).
1539 show_buffer_duration ();
1544 EngineControl::buffer_size_changed ()
1546 DEBUG_ECONTROL ("buffer_size_changed");
1547 show_buffer_duration ();
1551 EngineControl::show_buffer_duration ()
1553 DEBUG_ECONTROL ("show_buffer_duration");
1554 /* buffer sizes - convert from just samples to samples + msecs for
1555 * the displayed string
1558 string bs_text = buffer_size_combo.get_active_text ();
1559 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1560 uint32_t rate = get_rate();
1562 /* Developers: note the hard-coding of a double buffered model
1563 in the (2 * samples) computation of latency. we always start
1564 the audiobackend in this configuration.
1566 /* note to jack1 developers: ardour also always starts the engine
1567 * in async mode (no jack2 --sync option) which adds an extra cycle
1568 * of latency with jack2 (and *3 would be correct)
1569 * The value can also be wrong if jackd is started externally..
1571 * At the time of writing the ALSA backend always uses double-buffering *2,
1572 * The Dummy backend *1, and who knows what ASIO really does :)
1574 * So just display the period size, that's also what
1575 * ARDOUR_UI::update_sample_rate() does for the status bar.
1576 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1577 * but still, that's the buffer period, not [round-trip] latency)
1580 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1581 buffer_size_duration_label.set_text (buf);
1585 EngineControl::midi_option_changed ()
1587 DEBUG_ECONTROL ("midi_option_changed");
1588 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1591 backend->set_midi_option (get_midi_option());
1593 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1595 //_midi_devices.clear(); // TODO merge with state-saved settings..
1596 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1597 std::vector<MidiDeviceSettings> new_devices;
1599 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1600 MidiDeviceSettings mds = find_midi_device (i->name);
1601 if (i->available && !mds) {
1602 uint32_t input_latency = 0;
1603 uint32_t output_latency = 0;
1604 if (_can_set_midi_latencies) {
1605 input_latency = backend->systemic_midi_input_latency (i->name);
1606 output_latency = backend->systemic_midi_output_latency (i->name);
1608 bool enabled = backend->midi_device_enabled (i->name);
1609 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1610 new_devices.push_back (ptr);
1611 } else if (i->available) {
1612 new_devices.push_back (mds);
1615 _midi_devices = new_devices;
1617 if (_midi_devices.empty()) {
1618 midi_devices_button.set_sensitive (false);
1620 midi_devices_button.set_sensitive (true);
1625 EngineControl::parameter_changed ()
1629 EngineControl::State
1630 EngineControl::get_matching_state (const string& backend)
1632 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1633 if ((*i)->backend == backend) {
1640 EngineControl::State
1641 EngineControl::get_matching_state (
1642 const string& backend,
1643 const string& driver,
1644 const string& device)
1646 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1647 if ((*i)->backend == backend &&
1648 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1656 EngineControl::State
1657 EngineControl::get_matching_state (
1658 const string& backend,
1659 const string& driver,
1660 const string& input_device,
1661 const string& output_device)
1663 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1664 if ((*i)->backend == backend &&
1665 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1673 EngineControl::State
1674 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1676 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1679 if (backend->use_separate_input_and_output_devices ()) {
1680 return get_matching_state (backend_combo.get_active_text(),
1681 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1682 input_device_combo.get_active_text(),
1683 output_device_combo.get_active_text());
1685 return get_matching_state (backend_combo.get_active_text(),
1686 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1687 device_combo.get_active_text());
1691 return get_matching_state (backend_combo.get_active_text(),
1693 device_combo.get_active_text());
1696 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1697 const EngineControl::State& state2)
1699 if (state1->backend == state2->backend &&
1700 state1->driver == state2->driver &&
1701 state1->device == state2->device &&
1702 state1->input_device == state2->input_device &&
1703 state1->output_device == state2->output_device) {
1710 EngineControl::state_sort_cmp (const State &a, const State &b) {
1714 else if (b->active) {
1718 return a->lru < b->lru;
1722 EngineControl::State
1723 EngineControl::save_state ()
1727 if (!_have_control) {
1728 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1730 state->lru = time (NULL) ;
1733 state.reset(new StateStruct);
1734 state->backend = get_backend ();
1736 state.reset(new StateStruct);
1737 store_state (state);
1740 for (StateList::iterator i = states.begin(); i != states.end();) {
1741 if (equivalent_states (*i, state)) {
1742 i = states.erase(i);
1748 states.push_back (state);
1750 states.sort (state_sort_cmp);
1756 EngineControl::store_state (State state)
1758 state->backend = get_backend ();
1759 state->driver = get_driver ();
1760 state->device = get_device_name ();
1761 state->input_device = get_input_device_name ();
1762 state->output_device = get_output_device_name ();
1763 state->sample_rate = get_rate ();
1764 state->buffer_size = get_buffer_size ();
1765 state->input_latency = get_input_latency ();
1766 state->output_latency = get_output_latency ();
1767 state->input_channels = get_input_channels ();
1768 state->output_channels = get_output_channels ();
1769 state->midi_option = get_midi_option ();
1770 state->midi_devices = _midi_devices;
1771 state->lru = time (NULL) ;
1775 EngineControl::maybe_display_saved_state ()
1777 if (!_have_control) {
1781 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1784 DEBUG_ECONTROL ("Restoring saved state");
1785 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1787 if (!_desired_sample_rate) {
1788 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1790 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1791 /* call this explicitly because we're ignoring changes to
1792 the controls at this point.
1794 show_buffer_duration ();
1795 input_latency.set_value (state->input_latency);
1796 output_latency.set_value (state->output_latency);
1798 if (!state->midi_option.empty()) {
1799 midi_option_combo.set_active_text (state->midi_option);
1800 _midi_devices = state->midi_devices;
1803 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1808 EngineControl::get_state ()
1810 LocaleGuard lg (X_("C"));
1812 XMLNode* root = new XMLNode ("AudioMIDISetup");
1815 if (!states.empty()) {
1816 XMLNode* state_nodes = new XMLNode ("EngineStates");
1818 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1820 XMLNode* node = new XMLNode ("State");
1822 node->add_property ("backend", (*i)->backend);
1823 node->add_property ("driver", (*i)->driver);
1824 node->add_property ("device", (*i)->device);
1825 node->add_property ("input-device", (*i)->input_device);
1826 node->add_property ("output-device", (*i)->output_device);
1827 node->add_property ("sample-rate", (*i)->sample_rate);
1828 node->add_property ("buffer-size", (*i)->buffer_size);
1829 node->add_property ("input-latency", (*i)->input_latency);
1830 node->add_property ("output-latency", (*i)->output_latency);
1831 node->add_property ("input-channels", (*i)->input_channels);
1832 node->add_property ("output-channels", (*i)->output_channels);
1833 node->add_property ("active", (*i)->active ? "yes" : "no");
1834 node->add_property ("midi-option", (*i)->midi_option);
1835 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1837 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1838 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1839 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1840 midi_device_stuff->add_property (X_("name"), (*p)->name);
1841 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1842 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1843 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1844 midi_devices->add_child_nocopy (*midi_device_stuff);
1846 node->add_child_nocopy (*midi_devices);
1848 state_nodes->add_child_nocopy (*node);
1851 root->add_child_nocopy (*state_nodes);
1858 EngineControl::set_default_state ()
1860 vector<string> backend_names;
1861 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1863 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1864 backend_names.push_back ((*b)->name);
1866 backend_combo.set_active_text (backend_names.front());
1868 // We could set default backends per platform etc here
1874 EngineControl::set_state (const XMLNode& root)
1876 XMLNodeList clist, cclist;
1877 XMLNodeConstIterator citer, cciter;
1879 XMLNode* grandchild;
1880 XMLProperty* prop = NULL;
1882 fprintf (stderr, "EngineControl::set_state\n");
1884 if (root.name() != "AudioMIDISetup") {
1888 clist = root.children();
1892 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1896 if (child->name() != "EngineStates") {
1900 cclist = child->children();
1902 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1903 State state (new StateStruct);
1905 grandchild = *cciter;
1907 if (grandchild->name() != "State") {
1911 if ((prop = grandchild->property ("backend")) == 0) {
1914 state->backend = prop->value ();
1916 if ((prop = grandchild->property ("driver")) == 0) {
1919 state->driver = prop->value ();
1921 if ((prop = grandchild->property ("device")) == 0) {
1924 state->device = prop->value ();
1926 if ((prop = grandchild->property ("input-device")) == 0) {
1929 state->input_device = prop->value ();
1931 if ((prop = grandchild->property ("output-device")) == 0) {
1934 state->output_device = prop->value ();
1936 if ((prop = grandchild->property ("sample-rate")) == 0) {
1939 state->sample_rate = atof (prop->value ());
1941 if ((prop = grandchild->property ("buffer-size")) == 0) {
1944 state->buffer_size = atoi (prop->value ());
1946 if ((prop = grandchild->property ("input-latency")) == 0) {
1949 state->input_latency = atoi (prop->value ());
1951 if ((prop = grandchild->property ("output-latency")) == 0) {
1954 state->output_latency = atoi (prop->value ());
1956 if ((prop = grandchild->property ("input-channels")) == 0) {
1959 state->input_channels = atoi (prop->value ());
1961 if ((prop = grandchild->property ("output-channels")) == 0) {
1964 state->output_channels = atoi (prop->value ());
1966 if ((prop = grandchild->property ("active")) == 0) {
1969 state->active = string_is_affirmative (prop->value ());
1971 if ((prop = grandchild->property ("midi-option")) == 0) {
1974 state->midi_option = prop->value ();
1976 state->midi_devices.clear();
1978 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1979 const XMLNodeList mnc = midinode->children();
1980 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1981 if ((*n)->property (X_("name")) == 0
1982 || (*n)->property (X_("enabled")) == 0
1983 || (*n)->property (X_("input-latency")) == 0
1984 || (*n)->property (X_("output-latency")) == 0
1989 MidiDeviceSettings ptr (new MidiDeviceSetting(
1990 (*n)->property (X_("name"))->value (),
1991 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1992 atoi ((*n)->property (X_("input-latency"))->value ()),
1993 atoi ((*n)->property (X_("output-latency"))->value ())
1995 state->midi_devices.push_back (ptr);
1999 if ((prop = grandchild->property ("lru"))) {
2000 state->lru = atoi (prop->value ());
2004 /* remove accumulated duplicates (due to bug in ealier version)
2005 * this can be removed again before release
2007 for (StateList::iterator i = states.begin(); i != states.end();) {
2008 if ((*i)->backend == state->backend &&
2009 (*i)->driver == state->driver &&
2010 (*i)->device == state->device) {
2011 i = states.erase(i);
2018 states.push_back (state);
2022 /* now see if there was an active state and switch the setup to it */
2024 // purge states of backend that are not available in this built
2025 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2026 vector<std::string> backend_names;
2028 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2029 backend_names.push_back((*i)->name);
2031 for (StateList::iterator i = states.begin(); i != states.end();) {
2032 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2033 i = states.erase(i);
2039 states.sort (state_sort_cmp);
2041 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2044 return set_current_state (*i);
2051 EngineControl::set_current_state (const State& state)
2053 DEBUG_ECONTROL ("set_current_state");
2055 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2057 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2058 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2059 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2060 // this shouldn't happen as the invalid backend names should have been
2061 // removed from the list of states.
2065 // now reflect the change in the backend in the GUI so backend_changed will
2066 // do the right thing
2067 backend_combo.set_active_text (state->backend);
2069 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2071 // we don't have control don't restore state
2076 if (!state->driver.empty ()) {
2077 if (!backend->requires_driver_selection ()) {
2078 DEBUG_ECONTROL ("Backend should require driver selection");
2079 // A backend has changed from having driver selection to not having
2080 // it or someone has been manually editing a config file and messed
2085 if (backend->set_driver (state->driver) != 0) {
2086 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2087 // Driver names for a backend have changed and the name in the
2088 // config file is now invalid or support for driver is no longer
2089 // included in the backend
2092 // no need to set the driver_combo as backend_changed will use
2093 // backend->driver_name to set the active driver
2096 if (!state->device.empty ()) {
2097 if (backend->set_device_name (state->device) != 0) {
2099 string_compose ("Unable to set device name %1", state->device));
2100 // device is no longer available on the system
2103 // no need to set active device as it will be picked up in
2104 // via backend_changed ()/set_device_popdown_strings
2107 // backend supports separate input/output devices
2108 if (backend->set_input_device_name (state->input_device) != 0) {
2109 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2110 state->input_device));
2111 // input device is no longer available on the system
2115 if (backend->set_output_device_name (state->output_device) != 0) {
2116 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2117 state->input_device));
2118 // output device is no longer available on the system
2121 // no need to set active devices as it will be picked up in via
2122 // backend_changed ()/set_*_device_popdown_strings
2127 // Now restore the state of the rest of the controls
2129 // We don't use a SignalBlocker as set_current_state is currently only
2130 // called from set_state before any signals are connected. If at some point
2131 // a more general named state mechanism is implemented and
2132 // set_current_state is called while signals are connected then a
2133 // SignalBlocker will need to be instantiated before setting these.
2135 device_combo.set_active_text (state->device);
2136 input_device_combo.set_active_text (state->input_device);
2137 output_device_combo.set_active_text (state->output_device);
2138 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2139 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2140 input_latency.set_value (state->input_latency);
2141 output_latency.set_value (state->output_latency);
2142 midi_option_combo.set_active_text (state->midi_option);
2147 EngineControl::push_state_to_backend (bool start)
2149 DEBUG_ECONTROL ("push_state_to_backend");
2150 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2156 /* figure out what is going to change */
2158 bool restart_required = false;
2159 bool was_running = ARDOUR::AudioEngine::instance()->running();
2160 bool change_driver = false;
2161 bool change_device = false;
2162 bool change_rate = false;
2163 bool change_bufsize = false;
2164 bool change_latency = false;
2165 bool change_channels = false;
2166 bool change_midi = false;
2168 uint32_t ochan = get_output_channels ();
2169 uint32_t ichan = get_input_channels ();
2171 if (_have_control) {
2173 if (started_at_least_once) {
2175 /* we can control the backend */
2177 if (backend->requires_driver_selection()) {
2178 if (get_driver() != backend->driver_name()) {
2179 change_driver = true;
2183 if (backend->use_separate_input_and_output_devices()) {
2184 if (get_input_device_name() != backend->input_device_name()) {
2185 change_device = true;
2187 if (get_output_device_name() != backend->output_device_name()) {
2188 change_device = true;
2191 if (get_device_name() != backend->device_name()) {
2192 change_device = true;
2196 if (queue_device_changed) {
2197 change_device = true;
2200 if (get_rate() != backend->sample_rate()) {
2204 if (get_buffer_size() != backend->buffer_size()) {
2205 change_bufsize = true;
2208 if (get_midi_option() != backend->midi_option()) {
2212 /* zero-requested channels means "all available" */
2215 ichan = backend->input_channels();
2219 ochan = backend->output_channels();
2222 if (ichan != backend->input_channels()) {
2223 change_channels = true;
2226 if (ochan != backend->output_channels()) {
2227 change_channels = true;
2230 if (get_input_latency() != backend->systemic_input_latency() ||
2231 get_output_latency() != backend->systemic_output_latency()) {
2232 change_latency = true;
2235 /* backend never started, so we have to force a group
2238 change_device = true;
2239 if (backend->requires_driver_selection()) {
2240 change_driver = true;
2243 change_bufsize = true;
2244 change_channels = true;
2245 change_latency = true;
2251 /* we have no control over the backend, meaning that we can
2252 * only possibly change sample rate and buffer size.
2256 if (get_rate() != backend->sample_rate()) {
2257 change_bufsize = true;
2260 if (get_buffer_size() != backend->buffer_size()) {
2261 change_bufsize = true;
2265 queue_device_changed = false;
2267 if (!_have_control) {
2269 /* We do not have control over the backend, so the best we can
2270 * do is try to change the sample rate and/or bufsize and get
2274 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2278 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2283 backend->set_sample_rate (get_rate());
2286 if (change_bufsize) {
2287 backend->set_buffer_size (get_buffer_size());
2291 if (ARDOUR::AudioEngine::instance()->start ()) {
2292 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2302 /* determine if we need to stop the backend before changing parameters */
2304 if (change_driver || change_device || change_channels || change_latency ||
2305 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2307 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2308 restart_required = true;
2310 restart_required = false;
2315 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
2316 /* no changes in any parameters that absolutely require a
2317 * restart, so check those that might be changeable without a
2321 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2322 /* can't do this while running ... */
2323 restart_required = true;
2326 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2327 /* can't do this while running ... */
2328 restart_required = true;
2334 if (restart_required) {
2335 if (ARDOUR::AudioEngine::instance()->stop()) {
2341 if (change_driver && backend->set_driver (get_driver())) {
2342 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2345 if (backend->use_separate_input_and_output_devices()) {
2346 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2347 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2350 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2351 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2355 if (change_device && backend->set_device_name (get_device_name())) {
2356 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2360 if (change_rate && backend->set_sample_rate (get_rate())) {
2361 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2364 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2365 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2369 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2370 if (backend->set_input_channels (get_input_channels())) {
2371 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2374 if (backend->set_output_channels (get_output_channels())) {
2375 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2379 if (change_latency) {
2380 if (backend->set_systemic_input_latency (get_input_latency())) {
2381 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2384 if (backend->set_systemic_output_latency (get_output_latency())) {
2385 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2391 backend->set_midi_option (get_midi_option());
2395 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2396 if (_measure_midi) {
2397 if (*p == _measure_midi) {
2398 backend->set_midi_device_enabled ((*p)->name, true);
2400 backend->set_midi_device_enabled ((*p)->name, false);
2404 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2405 if (backend->can_set_systemic_midi_latencies()) {
2406 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2407 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2412 if (start || (was_running && restart_required)) {
2413 if (ARDOUR::AudioEngine::instance()->start()) {
2424 EngineControl::post_push ()
2426 /* get a pointer to the current state object, creating one if
2430 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2433 state = save_state ();
2439 states.sort (state_sort_cmp);
2443 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2444 (*i)->active = false;
2447 /* mark this one active (to be used next time the dialog is
2451 state->active = true;
2453 if (_have_control) { // XXX
2454 manage_control_app_sensitivity ();
2457 /* schedule a redisplay of MIDI ports */
2458 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2463 EngineControl::get_rate () const
2465 float r = atof (sample_rate_combo.get_active_text ());
2466 /* the string may have been translated with an abbreviation for
2467 * thousands, so use a crude heuristic to fix this.
2477 EngineControl::get_buffer_size () const
2479 string txt = buffer_size_combo.get_active_text ();
2482 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2483 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2484 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2492 EngineControl::get_midi_option () const
2494 return midi_option_combo.get_active_text();
2498 EngineControl::get_input_channels() const
2500 if (ARDOUR::Profile->get_mixbus()) {
2501 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2502 if (!backend) return 0;
2503 return backend->input_channels();
2505 return (uint32_t) input_channels_adjustment.get_value();
2509 EngineControl::get_output_channels() const
2511 if (ARDOUR::Profile->get_mixbus()) {
2512 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2513 if (!backend) return 0;
2514 return backend->input_channels();
2516 return (uint32_t) output_channels_adjustment.get_value();
2520 EngineControl::get_input_latency() const
2522 return (uint32_t) input_latency_adjustment.get_value();
2526 EngineControl::get_output_latency() const
2528 return (uint32_t) output_latency_adjustment.get_value();
2532 EngineControl::get_backend () const
2534 return backend_combo.get_active_text ();
2538 EngineControl::get_driver () const
2540 if (driver_combo.get_parent()) {
2541 return driver_combo.get_active_text ();
2548 EngineControl::get_device_name () const
2550 return device_combo.get_active_text ();
2554 EngineControl::get_input_device_name () const
2556 return input_device_combo.get_active_text ();
2560 EngineControl::get_output_device_name () const
2562 return output_device_combo.get_active_text ();
2566 EngineControl::control_app_button_clicked ()
2568 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2574 backend->launch_control_app ();
2578 EngineControl::start_stop_button_clicked ()
2580 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2586 if (ARDOUR::AudioEngine::instance()->running()) {
2587 ARDOUR::AudioEngine::instance()->stop ();
2594 EngineControl::update_devices_button_clicked ()
2596 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2602 if (backend->update_devices()) {
2603 device_list_changed ();
2608 EngineControl::manage_control_app_sensitivity ()
2610 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2616 string appname = backend->control_app_name();
2618 if (appname.empty()) {
2619 control_app_button.set_sensitive (false);
2621 control_app_button.set_sensitive (true);
2626 EngineControl::set_desired_sample_rate (uint32_t sr)
2628 _desired_sample_rate = sr;
2633 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2635 if (page_num == 0) {
2636 cancel_button->set_sensitive (true);
2637 _measure_midi.reset();
2638 update_sensitivity ();
2640 cancel_button->set_sensitive (false);
2641 ok_button->set_sensitive (false);
2644 if (page_num == midi_tab) {
2646 refresh_midi_display ();
2649 if (page_num == latency_tab) {
2652 if (ARDOUR::AudioEngine::instance()->running()) {
2653 // TODO - mark as 'stopped for latency
2658 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2660 /* save any existing latency values */
2662 uint32_t il = (uint32_t) input_latency.get_value ();
2663 uint32_t ol = (uint32_t) input_latency.get_value ();
2665 /* reset to zero so that our new test instance
2666 will be clean of any existing latency measures.
2668 NB. this should really be done by the backend
2669 when stated for latency measurement.
2672 input_latency.set_value (0);
2673 output_latency.set_value (0);
2675 push_state_to_backend (false);
2679 input_latency.set_value (il);
2680 output_latency.set_value (ol);
2683 // This should be done in push_state_to_backend()
2684 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2685 disable_latency_tab ();
2688 enable_latency_tab ();
2692 end_latency_detection ();
2693 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2698 /* latency measurement */
2701 EngineControl::check_audio_latency_measurement ()
2703 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2705 if (mtdm->resolve () < 0) {
2706 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2710 if (mtdm->err () > 0.3) {
2716 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2718 if (sample_rate == 0) {
2719 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2720 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2724 int frames_total = mtdm->del();
2725 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2727 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2728 _("Detected roundtrip latency: "),
2729 frames_total, frames_total * 1000.0f/sample_rate,
2730 _("Systemic latency: "),
2731 extra, extra * 1000.0f/sample_rate);
2735 if (mtdm->err () > 0.2) {
2737 strcat (buf, _("(signal detection error)"));
2743 strcat (buf, _("(inverted - bad wiring)"));
2747 lm_results.set_markup (string_compose (results_markup, buf));
2750 have_lm_results = true;
2751 end_latency_detection ();
2752 lm_use_button.set_sensitive (true);
2760 EngineControl::check_midi_latency_measurement ()
2762 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2764 if (!mididm->have_signal () || mididm->latency () == 0) {
2765 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2770 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2772 if (sample_rate == 0) {
2773 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2774 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2778 ARDOUR::framecnt_t frames_total = mididm->latency();
2779 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2780 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2781 _("Detected roundtrip latency: "),
2782 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2783 _("Systemic latency: "),
2784 extra, extra * 1000.0f / sample_rate);
2788 if (!mididm->ok ()) {
2790 strcat (buf, _("(averaging)"));
2794 if (mididm->deviation () > 50.0) {
2796 strcat (buf, _("(too large jitter)"));
2798 } else if (mididm->deviation () > 10.0) {
2800 strcat (buf, _("(large jitter)"));
2804 have_lm_results = true;
2805 end_latency_detection ();
2806 lm_use_button.set_sensitive (true);
2807 lm_results.set_markup (string_compose (results_markup, buf));
2809 } else if (mididm->processed () > 400) {
2810 have_lm_results = false;
2811 end_latency_detection ();
2812 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2816 lm_results.set_markup (string_compose (results_markup, buf));
2822 EngineControl::start_latency_detection ()
2824 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2825 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2827 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2828 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2829 if (_measure_midi) {
2830 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2832 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2834 lm_measure_label.set_text (_("Cancel"));
2835 have_lm_results = false;
2836 lm_use_button.set_sensitive (false);
2837 lm_input_channel_combo.set_sensitive (false);
2838 lm_output_channel_combo.set_sensitive (false);
2844 EngineControl::end_latency_detection ()
2846 latency_timeout.disconnect ();
2847 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2848 lm_measure_label.set_text (_("Measure"));
2849 if (!have_lm_results) {
2850 lm_use_button.set_sensitive (false);
2852 lm_input_channel_combo.set_sensitive (true);
2853 lm_output_channel_combo.set_sensitive (true);
2858 EngineControl::latency_button_clicked ()
2861 start_latency_detection ();
2863 end_latency_detection ();
2868 EngineControl::latency_back_button_clicked ()
2870 ARDOUR::AudioEngine::instance()->stop(true);
2871 notebook.set_current_page(0);
2875 EngineControl::use_latency_button_clicked ()
2877 if (_measure_midi) {
2878 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2882 ARDOUR::framecnt_t frames_total = mididm->latency();
2883 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2884 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2885 _measure_midi->input_latency = one_way;
2886 _measure_midi->output_latency = one_way;
2887 notebook.set_current_page (midi_tab);
2889 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2895 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2896 one_way = std::max (0., one_way);
2898 input_latency_adjustment.set_value (one_way);
2899 output_latency_adjustment.set_value (one_way);
2901 /* back to settings page */
2902 notebook.set_current_page (0);
2907 EngineControl::on_delete_event (GdkEventAny* ev)
2909 if (notebook.get_current_page() == 2) {
2910 /* currently on latency tab - be sure to clean up */
2911 end_latency_detection ();
2913 return ArdourDialog::on_delete_event (ev);
2917 EngineControl::engine_running ()
2919 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2922 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2923 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2925 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2926 connect_disconnect_button.show();
2928 started_at_least_once = true;
2929 if (_have_control) {
2930 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
2932 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
2934 update_sensitivity();
2938 EngineControl::engine_stopped ()
2940 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2943 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2944 connect_disconnect_button.show();
2946 if (_have_control) {
2947 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
2949 engine_status.set_markup(X_(""));
2952 update_sensitivity();
2956 EngineControl::device_list_changed ()
2958 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2960 midi_option_changed();
2964 EngineControl::connect_disconnect_click()
2966 if (ARDOUR::AudioEngine::instance()->running()) {
2974 EngineControl::calibrate_audio_latency ()
2976 _measure_midi.reset ();
2977 have_lm_results = false;
2978 lm_use_button.set_sensitive (false);
2979 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2980 notebook.set_current_page (latency_tab);
2984 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2987 have_lm_results = false;
2988 lm_use_button.set_sensitive (false);
2989 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2990 notebook.set_current_page (latency_tab);
2994 EngineControl::configure_midi_devices ()
2996 notebook.set_current_page (midi_tab);