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 , ignore_device_changes (0)
100 , _desired_sample_rate (0)
101 , started_at_least_once (false)
102 , queue_device_changed (false)
103 , _have_control (true)
106 using namespace Notebook_Helpers;
107 vector<string> backend_names;
109 AttachOptions xopt = AttachOptions (FILL|EXPAND);
112 set_name (X_("AudioMIDISetup"));
114 /* the backend combo is the one thing that is ALWAYS visible */
116 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
118 if (backends.empty()) {
119 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));
121 throw failed_constructor ();
124 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
125 backend_names.push_back ((*b)->name);
128 set_popdown_strings (backend_combo, backend_names);
130 /* setup basic packing characteristics for the table used on the main
131 * tab of the notebook
134 basic_packer.set_spacings (6);
135 basic_packer.set_border_width (12);
136 basic_packer.set_homogeneous (false);
140 basic_hbox.pack_start (basic_packer, false, false);
142 /* latency measurement tab */
144 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
147 lm_table.set_row_spacings (12);
148 lm_table.set_col_spacings (6);
149 lm_table.set_homogeneous (false);
151 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
154 lm_preamble.set_width_chars (60);
155 lm_preamble.set_line_wrap (true);
156 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
158 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
161 Gtk::Label* preamble;
162 preamble = manage (new Label);
163 preamble->set_width_chars (60);
164 preamble->set_line_wrap (true);
165 preamble->set_markup (_("Select two channels below and connect them using a cable."));
167 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
170 label = manage (new Label (_("Output channel")));
171 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
173 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
174 misc_align->add (lm_output_channel_combo);
175 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
178 label = manage (new Label (_("Input channel")));
179 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
181 misc_align = manage (new Alignment (0.0, 0.5));
182 misc_align->add (lm_input_channel_combo);
183 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
186 lm_measure_label.set_padding (10, 10);
187 lm_measure_button.add (lm_measure_label);
188 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
189 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
190 lm_back_button_signal = lm_back_button.signal_clicked().connect(
191 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
193 lm_use_button.set_sensitive (false);
195 /* Increase the default spacing around the labels of these three
201 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
202 l->set_padding (10, 10);
205 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
206 l->set_padding (10, 10);
209 preamble = manage (new Label);
210 preamble->set_width_chars (60);
211 preamble->set_line_wrap (true);
212 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
213 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
216 preamble = manage (new Label);
217 preamble->set_width_chars (60);
218 preamble->set_line_wrap (true);
219 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
220 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222 ++row; // skip a row in the table
223 ++row; // skip a row in the table
225 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 ++row; // skip a row in the table
228 ++row; // skip a row in the table
230 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
231 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
234 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
236 lm_vbox.set_border_width (12);
237 lm_vbox.pack_start (lm_table, false, false);
239 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
243 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
244 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
245 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
246 notebook.set_border_width (12);
248 notebook.set_show_tabs (false);
249 notebook.show_all ();
251 notebook.set_name ("SettingsNotebook");
253 /* packup the notebook */
255 get_vbox()->set_border_width (12);
256 get_vbox()->pack_start (notebook);
258 /* need a special function to print "all available channels" when the
259 * channel counts hit zero.
262 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
263 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
265 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
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 nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
325 sigc::mem_fun (*this, &EngineControl::nperiods_changed));
326 device_combo_connection = device_combo.signal_changed ().connect (
327 sigc::mem_fun (*this, &EngineControl::device_changed));
328 midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
329 sigc::mem_fun (*this, &EngineControl::midi_option_changed));
331 input_device_combo_connection = input_device_combo.signal_changed ().connect (
332 sigc::mem_fun (*this, &EngineControl::input_device_changed));
333 output_device_combo_connection = output_device_combo.signal_changed ().connect (
334 sigc::mem_fun (*this, &EngineControl::output_device_changed));
336 input_latency_connection = input_latency.signal_changed ().connect (
337 sigc::mem_fun (*this, &EngineControl::parameter_changed));
338 output_latency_connection = output_latency.signal_changed ().connect (
339 sigc::mem_fun (*this, &EngineControl::parameter_changed));
340 input_channels_connection = input_channels.signal_changed ().connect (
341 sigc::mem_fun (*this, &EngineControl::parameter_changed));
342 output_channels_connection = output_channels.signal_changed ().connect (
343 sigc::mem_fun (*this, &EngineControl::parameter_changed));
347 EngineControl::block_changed_signals ()
349 if (block_signals++ == 0) {
350 DEBUG_ECONTROL ("Blocking changed signals");
351 backend_combo_connection.block ();
352 driver_combo_connection.block ();
353 sample_rate_combo_connection.block ();
354 buffer_size_combo_connection.block ();
355 nperiods_combo_connection.block ();
356 device_combo_connection.block ();
357 input_device_combo_connection.block ();
358 output_device_combo_connection.block ();
359 midi_option_combo_connection.block ();
360 input_latency_connection.block ();
361 output_latency_connection.block ();
362 input_channels_connection.block ();
363 output_channels_connection.block ();
368 EngineControl::unblock_changed_signals ()
370 if (--block_signals == 0) {
371 DEBUG_ECONTROL ("Unblocking changed signals");
372 backend_combo_connection.unblock ();
373 driver_combo_connection.unblock ();
374 sample_rate_combo_connection.unblock ();
375 buffer_size_combo_connection.unblock ();
376 nperiods_combo_connection.unblock ();
377 device_combo_connection.unblock ();
378 input_device_combo_connection.unblock ();
379 output_device_combo_connection.unblock ();
380 midi_option_combo_connection.unblock ();
381 input_latency_connection.unblock ();
382 output_latency_connection.unblock ();
383 input_channels_connection.unblock ();
384 output_channels_connection.unblock ();
388 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
389 const std::string& reason)
390 : ec (engine_control)
393 DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
394 ec.block_changed_signals ();
397 EngineControl::SignalBlocker::~SignalBlocker ()
399 DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
400 ec.unblock_changed_signals ();
404 EngineControl::on_show ()
406 ArdourDialog::on_show ();
407 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
408 // re-check _have_control (jackd running) see #6041
412 ok_button->grab_focus();
416 EngineControl::start_engine ()
418 if (push_state_to_backend(true) != 0) {
419 MessageDialog msg(*this,
420 ARDOUR::AudioEngine::instance()->get_last_backend_error());
428 EngineControl::stop_engine (bool for_latency)
430 if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
431 MessageDialog msg(*this,
432 ARDOUR::AudioEngine::instance()->get_last_backend_error());
440 EngineControl::on_response (int response_id)
442 ArdourDialog::on_response (response_id);
444 switch (response_id) {
446 if (!start_engine()) {
451 #ifdef PLATFORM_WINDOWS
453 // But if there's no session open, this can produce
454 // a long gap when nothing appears to be happening.
455 // Let's show the splash image while we're waiting.
456 if (!ARDOUR_COMMAND_LINE::no_splash) {
457 if (ARDOUR_UI::instance()) {
458 if (!ARDOUR_UI::instance()->session_loaded) {
459 ARDOUR_UI::instance()->show_splash();
465 case RESPONSE_DELETE_EVENT: {
467 ev.type = GDK_BUTTON_PRESS;
469 on_delete_event((GdkEventAny*)&ev);
472 case RESPONSE_CANCEL:
473 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
474 ARDOUR_UI::instance()->check_audioengine(*this);
483 EngineControl::build_notebook ()
486 AttachOptions xopt = AttachOptions (FILL|EXPAND);
488 /* clear the table */
490 Gtkmm2ext::container_clear (basic_vbox);
491 Gtkmm2ext::container_clear (basic_packer);
493 if (control_app_button.get_parent()) {
494 control_app_button.get_parent()->remove (control_app_button);
497 label = manage (left_aligned_label (_("Audio System:")));
498 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
499 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
501 basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
502 engine_status.show();
504 basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
505 basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
507 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
508 lm_button_audio.set_name ("generic button");
509 lm_button_audio.set_can_focus(true);
512 build_full_control_notebook ();
514 build_no_control_notebook ();
517 basic_vbox.pack_start (basic_hbox, false, false);
520 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
521 basic_vbox.show_all ();
526 EngineControl::build_full_control_notebook ()
528 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
531 using namespace Notebook_Helpers;
533 vector<string> strings;
534 AttachOptions xopt = AttachOptions (FILL|EXPAND);
535 int row = 1; // row zero == backend combo
537 /* start packing it up */
539 if (backend->requires_driver_selection()) {
540 label = manage (left_aligned_label (_("Driver:")));
541 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
542 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
546 if (backend->use_separate_input_and_output_devices()) {
547 label = manage (left_aligned_label (_("Input Device:")));
548 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
549 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
551 label = manage (left_aligned_label (_("Output Device:")));
552 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
553 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
555 // reset so it isn't used in state comparisons
556 device_combo.set_active_text ("");
558 label = manage (left_aligned_label (_("Device:")));
559 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
560 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
562 // reset these so they don't get used in state comparisons
563 input_device_combo.set_active_text ("");
564 output_device_combo.set_active_text ("");
567 label = manage (left_aligned_label (_("Sample rate:")));
568 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
569 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
573 label = manage (left_aligned_label (_("Buffer size:")));
574 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
575 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
576 buffer_size_duration_label.set_alignment (0.0); /* left-align */
577 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
579 int ctrl_btn_span = 1;
580 if (backend->can_set_period_size ()) {
582 label = manage (left_aligned_label (_("Periods:")));
583 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
584 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
588 /* button spans 2 or 3 rows */
590 basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
593 input_channels.set_name ("InputChannels");
594 input_channels.set_flags (Gtk::CAN_FOCUS);
595 input_channels.set_digits (0);
596 input_channels.set_wrap (false);
597 output_channels.set_editable (true);
599 if (!ARDOUR::Profile->get_mixbus()) {
600 label = manage (left_aligned_label (_("Input Channels:")));
601 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
602 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
606 output_channels.set_name ("OutputChannels");
607 output_channels.set_flags (Gtk::CAN_FOCUS);
608 output_channels.set_digits (0);
609 output_channels.set_wrap (false);
610 output_channels.set_editable (true);
612 if (!ARDOUR::Profile->get_mixbus()) {
613 label = manage (left_aligned_label (_("Output Channels:")));
614 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
615 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
619 input_latency.set_name ("InputLatency");
620 input_latency.set_flags (Gtk::CAN_FOCUS);
621 input_latency.set_digits (0);
622 input_latency.set_wrap (false);
623 input_latency.set_editable (true);
625 label = manage (left_aligned_label (_("Hardware input latency:")));
626 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
627 basic_packer.attach (input_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);
632 output_latency.set_name ("OutputLatency");
633 output_latency.set_flags (Gtk::CAN_FOCUS);
634 output_latency.set_digits (0);
635 output_latency.set_wrap (false);
636 output_latency.set_editable (true);
638 label = manage (left_aligned_label (_("Hardware output latency:")));
639 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
640 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
641 label = manage (left_aligned_label (_("samples")));
642 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
644 /* button spans 2 rows */
646 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
649 label = manage (left_aligned_label (_("MIDI System:")));
650 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
651 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
652 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
657 EngineControl::build_no_control_notebook ()
659 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
662 using namespace Notebook_Helpers;
664 vector<string> strings;
665 AttachOptions xopt = AttachOptions (FILL|EXPAND);
666 int row = 1; // row zero == backend combo
667 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
669 label = manage (new Label);
670 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
671 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
674 if (backend->can_change_sample_rate_when_running()) {
675 label = manage (left_aligned_label (_("Sample rate:")));
676 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
677 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
681 if (backend->can_change_buffer_size_when_running()) {
682 label = manage (left_aligned_label (_("Buffer size:")));
683 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
684 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
685 buffer_size_duration_label.set_alignment (0.0); /* left-align */
686 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
690 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
694 EngineControl::~EngineControl ()
696 ignore_changes = true;
700 EngineControl::disable_latency_tab ()
702 vector<string> empty;
703 set_popdown_strings (lm_output_channel_combo, empty);
704 set_popdown_strings (lm_input_channel_combo, empty);
705 lm_measure_button.set_sensitive (false);
706 lm_use_button.set_sensitive (false);
710 EngineControl::enable_latency_tab ()
712 vector<string> outputs;
713 vector<string> inputs;
715 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
716 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
717 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
719 if (!ARDOUR::AudioEngine::instance()->running()) {
720 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
721 notebook.set_current_page (0);
725 else if (inputs.empty() || outputs.empty()) {
726 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
727 notebook.set_current_page (0);
732 lm_back_button_signal.disconnect();
734 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
737 lm_back_button_signal = lm_back_button.signal_clicked().connect(
738 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
742 set_popdown_strings (lm_output_channel_combo, outputs);
743 lm_output_channel_combo.set_active_text (outputs.front());
744 lm_output_channel_combo.set_sensitive (true);
746 set_popdown_strings (lm_input_channel_combo, inputs);
747 lm_input_channel_combo.set_active_text (inputs.front());
748 lm_input_channel_combo.set_sensitive (true);
750 lm_measure_button.set_sensitive (true);
754 EngineControl::setup_midi_tab_for_backend ()
756 string backend = backend_combo.get_active_text ();
758 Gtkmm2ext::container_clear (midi_vbox);
760 midi_vbox.set_border_width (12);
761 midi_device_table.set_border_width (12);
763 if (backend == "JACK") {
764 setup_midi_tab_for_jack ();
767 midi_vbox.pack_start (midi_device_table, true, true);
768 midi_vbox.pack_start (midi_back_button, false, false);
769 midi_vbox.show_all ();
773 EngineControl::update_sensitivity ()
775 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
777 ok_button->set_sensitive (false);
778 start_stop_button.set_sensitive (false);
783 size_t devices_available = 0;
785 if (backend->use_separate_input_and_output_devices ()) {
786 devices_available += get_popdown_string_count (input_device_combo);
787 devices_available += get_popdown_string_count (output_device_combo);
789 devices_available += get_popdown_string_count (device_combo);
792 if (devices_available == 0) {
794 input_latency.set_sensitive (false);
795 output_latency.set_sensitive (false);
796 input_channels.set_sensitive (false);
797 output_channels.set_sensitive (false);
799 input_latency.set_sensitive (true);
800 output_latency.set_sensitive (true);
801 input_channels.set_sensitive (true);
802 output_channels.set_sensitive (true);
805 if (get_popdown_string_count (buffer_size_combo) > 0) {
806 if (!ARDOUR::AudioEngine::instance()->running()) {
807 buffer_size_combo.set_sensitive (valid);
808 } else if (backend->can_change_sample_rate_when_running()) {
809 buffer_size_combo.set_sensitive (valid || !_have_control);
813 * Currently there is no way to manually stop the
814 * engine in order to re-configure it.
815 * This needs to remain sensitive for now.
817 * (it's also handy to implicily
818 * re-start the engine)
820 buffer_size_combo.set_sensitive (true);
822 buffer_size_combo.set_sensitive (false);
826 buffer_size_combo.set_sensitive (false);
830 if (get_popdown_string_count (sample_rate_combo) > 0) {
831 if (!ARDOUR::AudioEngine::instance()->running()) {
832 sample_rate_combo.set_sensitive (true);
834 sample_rate_combo.set_sensitive (false);
837 sample_rate_combo.set_sensitive (false);
841 if (get_popdown_string_count (nperiods_combo) > 0) {
842 if (!ARDOUR::AudioEngine::instance()->running()) {
843 nperiods_combo.set_sensitive (true);
845 nperiods_combo.set_sensitive (false);
848 nperiods_combo.set_sensitive (false);
852 start_stop_button.set_sensitive(true);
853 start_stop_button.show();
854 if (ARDOUR::AudioEngine::instance()->running()) {
855 start_stop_button.set_text("Stop");
856 update_devices_button.set_sensitive(false);
858 if (backend->can_request_update_devices()) {
859 update_devices_button.show();
861 update_devices_button.hide();
863 start_stop_button.set_text("Start");
864 update_devices_button.set_sensitive(true);
867 update_devices_button.set_sensitive(false);
868 update_devices_button.hide();
869 start_stop_button.set_sensitive(false);
870 start_stop_button.hide();
873 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
874 input_device_combo.set_sensitive (false);
875 output_device_combo.set_sensitive (false);
876 device_combo.set_sensitive (false);
877 driver_combo.set_sensitive (false);
879 input_device_combo.set_sensitive (true);
880 output_device_combo.set_sensitive (true);
881 device_combo.set_sensitive (true);
882 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
883 driver_combo.set_sensitive (true);
885 driver_combo.set_sensitive (false);
889 if (valid || !_have_control) {
890 ok_button->set_sensitive (true);
892 ok_button->set_sensitive (false);
897 EngineControl::setup_midi_tab_for_jack ()
902 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
904 device->input_latency = a->get_value();
906 device->output_latency = a->get_value();
911 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
912 b->set_active (!b->get_active());
913 device->enabled = b->get_active();
914 refresh_midi_display(device->name);
918 EngineControl::refresh_midi_display (std::string focus)
920 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
924 AttachOptions xopt = AttachOptions (FILL|EXPAND);
927 Gtkmm2ext::container_clear (midi_device_table);
929 midi_device_table.set_spacings (6);
931 l = manage (new Label);
932 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
933 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
934 l->set_alignment (0.5, 0.5);
938 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
939 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
940 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
941 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
943 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
944 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
945 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
946 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
949 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
954 bool enabled = (*p)->enabled;
956 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
957 m->set_name ("midi device");
958 m->set_can_focus (Gtk::CAN_FOCUS);
959 m->add_events (Gdk::BUTTON_RELEASE_MASK);
960 m->set_active (enabled);
961 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
962 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
963 if ((*p)->name == focus) {
967 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
968 s = manage (new Gtk::SpinButton (*a));
969 a->set_value ((*p)->input_latency);
970 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
971 s->set_sensitive (_can_set_midi_latencies && enabled);
972 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
974 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
975 s = manage (new Gtk::SpinButton (*a));
976 a->set_value ((*p)->output_latency);
977 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
978 s->set_sensitive (_can_set_midi_latencies && enabled);
979 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
981 b = manage (new Button (_("Calibrate")));
982 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
983 b->set_sensitive (_can_set_midi_latencies && enabled);
984 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
991 EngineControl::backend_changed ()
993 SignalBlocker blocker (*this, "backend_changed");
994 string backend_name = backend_combo.get_active_text();
995 boost::shared_ptr<ARDOUR::AudioBackend> backend;
997 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
998 /* eh? setting the backend failed... how ? */
999 /* A: stale config contains a backend that does not exist in current build */
1003 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1005 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1008 setup_midi_tab_for_backend ();
1009 _midi_devices.clear();
1011 if (backend->requires_driver_selection()) {
1012 if (set_driver_popdown_strings ()) {
1016 /* this will change the device text which will cause a call to
1017 * device changed which will set up parameters
1022 update_midi_options ();
1024 connect_disconnect_button.hide();
1026 midi_option_changed();
1028 started_at_least_once = false;
1030 /* changing the backend implies stopping the engine
1031 * ARDOUR::AudioEngine() may or may not emit this signal
1032 * depending on previous engine state
1034 engine_stopped (); // set "active/inactive"
1036 if (!_have_control) {
1037 // set settings from backend that we do have control over
1038 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1041 if (_have_control && !ignore_changes) {
1042 // set driver & devices
1043 State state = get_matching_state (backend_combo.get_active_text());
1045 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1046 set_current_state (state);
1050 if (!ignore_changes) {
1051 maybe_display_saved_state ();
1056 EngineControl::update_midi_options ()
1058 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1059 vector<string> midi_options = backend->enumerate_midi_options();
1061 if (midi_options.size() == 1) {
1062 /* only contains the "none" option */
1063 midi_option_combo.set_sensitive (false);
1065 if (_have_control) {
1066 set_popdown_strings (midi_option_combo, midi_options);
1067 midi_option_combo.set_active_text (midi_options.front());
1068 midi_option_combo.set_sensitive (true);
1070 midi_option_combo.set_sensitive (false);
1076 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1078 if (ARDOUR::Profile->get_mixbus()) {
1082 uint32_t cnt = (uint32_t) sb->get_value();
1084 sb->set_text (_("all available channels"));
1087 snprintf (buf, sizeof (buf), "%d", cnt);
1093 // @return true if there are drivers available
1095 EngineControl::set_driver_popdown_strings ()
1097 DEBUG_ECONTROL ("set_driver_popdown_strings");
1098 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1099 vector<string> drivers = backend->enumerate_drivers();
1101 if (drivers.empty ()) {
1102 // This is an error...?
1106 string current_driver = backend->driver_name ();
1108 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1110 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1113 current_driver = drivers.front ();
1116 set_popdown_strings (driver_combo, drivers);
1118 string_compose ("driver_combo.set_active_text: %1", current_driver));
1119 driver_combo.set_active_text (current_driver);
1124 EngineControl::get_default_device(const string& current_device_name,
1125 const vector<string>& available_devices)
1127 // If the current device is available, use it as default
1128 if (std::find (available_devices.begin (),
1129 available_devices.end (),
1130 current_device_name) != available_devices.end ()) {
1132 return current_device_name;
1135 using namespace ARDOUR;
1137 string default_device_name =
1138 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1140 vector<string>::const_iterator i;
1142 // If there is a "Default" device available, use it
1143 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1144 if (*i == default_device_name) {
1149 string none_device_name =
1150 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1152 // Use the first device that isn't "None"
1153 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1154 if (*i != none_device_name) {
1159 // Use "None" if there are no other available
1160 return available_devices.front();
1163 // @return true if there are devices available
1165 EngineControl::set_device_popdown_strings ()
1167 DEBUG_ECONTROL ("set_device_popdown_strings");
1168 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1169 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1171 /* NOTE: Ardour currently does not display the "available" field of the
1174 * Doing so would require a different GUI widget than the combo
1175 * box/popdown that we currently use, since it has no way to list
1176 * items that are not selectable. Something more like a popup menu,
1177 * which could have unselectable items, would be appropriate.
1180 vector<string> available_devices;
1182 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1183 available_devices.push_back (i->name);
1186 if (available_devices.empty ()) {
1190 set_popdown_strings (device_combo, available_devices);
1192 std::string default_device =
1193 get_default_device(backend->device_name(), available_devices);
1196 string_compose ("set device_combo active text: %1", default_device));
1198 device_combo.set_active_text(default_device);
1202 // @return true if there are input devices available
1204 EngineControl::set_input_device_popdown_strings ()
1206 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1207 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1208 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1210 vector<string> available_devices;
1212 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1213 available_devices.push_back (i->name);
1216 if (available_devices.empty()) {
1220 set_popdown_strings (input_device_combo, available_devices);
1222 std::string default_device =
1223 get_default_device(backend->input_device_name(), available_devices);
1226 string_compose ("set input_device_combo active text: %1", default_device));
1227 input_device_combo.set_active_text(default_device);
1231 // @return true if there are output devices available
1233 EngineControl::set_output_device_popdown_strings ()
1235 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1236 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1237 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1239 vector<string> available_devices;
1241 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1242 available_devices.push_back (i->name);
1245 if (available_devices.empty()) {
1249 set_popdown_strings (output_device_combo, available_devices);
1251 std::string default_device =
1252 get_default_device(backend->output_device_name(), available_devices);
1255 string_compose ("set output_device_combo active text: %1", default_device));
1256 output_device_combo.set_active_text(default_device);
1261 EngineControl::list_devices ()
1263 DEBUG_ECONTROL ("list_devices");
1264 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1267 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1269 bool devices_available = false;
1271 if (backend->use_separate_input_and_output_devices ()) {
1272 bool input_devices_available = set_input_device_popdown_strings ();
1273 bool output_devices_available = set_output_device_popdown_strings ();
1274 devices_available = input_devices_available || output_devices_available;
1276 devices_available = set_device_popdown_strings ();
1279 if (devices_available) {
1282 device_combo.clear();
1283 input_device_combo.clear();
1284 output_device_combo.clear();
1286 update_sensitivity ();
1290 EngineControl::driver_changed ()
1292 SignalBlocker blocker (*this, "driver_changed");
1293 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1296 backend->set_driver (driver_combo.get_active_text());
1299 // TODO load LRU device(s) for backend + driver combo
1301 if (!ignore_changes) {
1302 maybe_display_saved_state ();
1307 EngineControl::get_sample_rates_for_all_devices ()
1309 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1310 ARDOUR::AudioEngine::instance ()->current_backend ();
1311 vector<float> all_rates;
1313 if (backend->use_separate_input_and_output_devices ()) {
1314 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1316 all_rates = backend->available_sample_rates (get_device_name ());
1322 EngineControl::get_default_sample_rates ()
1324 vector<float> rates;
1325 rates.push_back (8000.0f);
1326 rates.push_back (16000.0f);
1327 rates.push_back (32000.0f);
1328 rates.push_back (44100.0f);
1329 rates.push_back (48000.0f);
1330 rates.push_back (88200.0f);
1331 rates.push_back (96000.0f);
1332 rates.push_back (192000.0f);
1333 rates.push_back (384000.0f);
1338 EngineControl::set_samplerate_popdown_strings ()
1340 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1341 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1346 if (_have_control) {
1347 sr = get_sample_rates_for_all_devices ();
1349 sr = get_default_sample_rates ();
1352 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1353 s.push_back (rate_as_string (*x));
1354 if (*x == _desired_sample_rate) {
1359 set_popdown_strings (sample_rate_combo, s);
1362 if (desired.empty ()) {
1363 float new_active_sr = backend->default_sample_rate ();
1365 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1366 new_active_sr = sr.front ();
1369 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1371 sample_rate_combo.set_active_text (desired);
1375 update_sensitivity ();
1379 EngineControl::get_buffer_sizes_for_all_devices ()
1381 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1382 ARDOUR::AudioEngine::instance ()->current_backend ();
1383 vector<uint32_t> all_sizes;
1385 if (backend->use_separate_input_and_output_devices ()) {
1386 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1388 all_sizes = backend->available_buffer_sizes (get_device_name ());
1394 EngineControl::get_default_buffer_sizes ()
1396 vector<uint32_t> sizes;
1397 sizes.push_back (8);
1398 sizes.push_back (16);
1399 sizes.push_back (32);
1400 sizes.push_back (64);
1401 sizes.push_back (128);
1402 sizes.push_back (256);
1403 sizes.push_back (512);
1404 sizes.push_back (1024);
1405 sizes.push_back (2048);
1406 sizes.push_back (4096);
1407 sizes.push_back (8192);
1412 EngineControl::set_buffersize_popdown_strings ()
1414 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1415 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1416 vector<uint32_t> bs;
1419 if (_have_control) {
1420 bs = get_buffer_sizes_for_all_devices ();
1421 } else if (backend->can_change_buffer_size_when_running()) {
1422 bs = get_default_buffer_sizes ();
1425 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1426 s.push_back (bufsize_as_string (*x));
1429 uint32_t previous_size = 0;
1430 if (!buffer_size_combo.get_active_text().empty()) {
1431 previous_size = get_buffer_size ();
1434 set_popdown_strings (buffer_size_combo, s);
1438 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1439 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1442 buffer_size_combo.set_active_text(s.front());
1444 uint32_t period = backend->buffer_size();
1445 if (0 == period && backend->use_separate_input_and_output_devices()) {
1446 period = backend->default_buffer_size(get_input_device_name());
1448 if (0 == period && backend->use_separate_input_and_output_devices()) {
1449 period = backend->default_buffer_size(get_output_device_name());
1451 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1452 period = backend->default_buffer_size(get_device_name());
1455 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1457 show_buffer_duration ();
1459 update_sensitivity ();
1463 EngineControl::set_nperiods_popdown_strings ()
1465 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1466 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1467 vector<uint32_t> np;
1470 if (backend->can_set_period_size()) {
1471 np = backend->available_period_sizes (get_driver());
1474 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1475 s.push_back (nperiods_as_string (*x));
1478 set_popdown_strings (nperiods_combo, s);
1481 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1484 update_sensitivity ();
1488 EngineControl::device_changed ()
1490 SignalBlocker blocker (*this, "device_changed");
1491 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1494 string device_name_in;
1495 string device_name_out; // only used if backend support separate I/O devices
1497 if (backend->use_separate_input_and_output_devices()) {
1498 device_name_in = get_input_device_name ();
1499 device_name_out = get_output_device_name ();
1501 device_name_in = get_device_name ();
1504 /* we set the backend-device to query various device related intormation.
1505 * This has the side effect that backend->device_name() will match
1506 * the device_name and 'change_device' will never be true.
1507 * so work around this by setting...
1509 if (backend->use_separate_input_and_output_devices()) {
1510 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1511 queue_device_changed = true;
1514 if (device_name_in != backend->device_name()) {
1515 queue_device_changed = true;
1519 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1520 if (backend->use_separate_input_and_output_devices()) {
1521 backend->set_input_device_name (device_name_in);
1522 backend->set_output_device_name (device_name_out);
1524 backend->set_device_name(device_name_in);
1528 /* don't allow programmatic change to combos to cause a
1529 recursive call to this method.
1531 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1533 set_samplerate_popdown_strings ();
1534 set_buffersize_popdown_strings ();
1535 set_nperiods_popdown_strings ();
1537 /* TODO set min + max channel counts here */
1539 manage_control_app_sensitivity ();
1542 /* pick up any saved state for this device */
1544 if (!ignore_changes) {
1545 maybe_display_saved_state ();
1550 EngineControl::input_device_changed ()
1552 DEBUG_ECONTROL ("input_device_changed");
1557 EngineControl::output_device_changed ()
1559 DEBUG_ECONTROL ("output_device_changed");
1564 EngineControl::bufsize_as_string (uint32_t sz)
1566 /* Translators: "samples" is always plural here, so no
1567 need for plural+singular forms.
1570 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1575 EngineControl::nperiods_as_string (uint32_t np)
1578 snprintf (buf, sizeof (buf), "%u", np);
1584 EngineControl::sample_rate_changed ()
1586 DEBUG_ECONTROL ("sample_rate_changed");
1587 /* reset the strings for buffer size to show the correct msec value
1588 (reflecting the new sample rate).
1591 show_buffer_duration ();
1596 EngineControl::buffer_size_changed ()
1598 DEBUG_ECONTROL ("buffer_size_changed");
1599 show_buffer_duration ();
1603 EngineControl::nperiods_changed ()
1605 DEBUG_ECONTROL ("nperiods_changed");
1606 show_buffer_duration ();
1610 EngineControl::show_buffer_duration ()
1612 DEBUG_ECONTROL ("show_buffer_duration");
1613 /* buffer sizes - convert from just samples to samples + msecs for
1614 * the displayed string
1617 string bs_text = buffer_size_combo.get_active_text ();
1618 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1619 uint32_t rate = get_rate();
1621 /* Except for ALSA and Dummy backends, we don't know the number of periods
1622 * per cycle and settings.
1624 * jack1 vs jack2 have different default latencies since jack2 start
1625 * in async-mode unless --sync is given which adds an extra cycle
1626 * of latency. The value is not known if jackd is started externally..
1628 * So just display the period size, that's also what
1629 * ARDOUR_UI::update_sample_rate() does for the status bar.
1630 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1631 * but still, that's the buffer period, not [round-trip] latency)
1634 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1635 buffer_size_duration_label.set_text (buf);
1639 EngineControl::midi_option_changed ()
1641 DEBUG_ECONTROL ("midi_option_changed");
1642 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1645 backend->set_midi_option (get_midi_option());
1647 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1649 //_midi_devices.clear(); // TODO merge with state-saved settings..
1650 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1651 std::vector<MidiDeviceSettings> new_devices;
1653 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1654 MidiDeviceSettings mds = find_midi_device (i->name);
1655 if (i->available && !mds) {
1656 uint32_t input_latency = 0;
1657 uint32_t output_latency = 0;
1658 if (_can_set_midi_latencies) {
1659 input_latency = backend->systemic_midi_input_latency (i->name);
1660 output_latency = backend->systemic_midi_output_latency (i->name);
1662 bool enabled = backend->midi_device_enabled (i->name);
1663 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1664 new_devices.push_back (ptr);
1665 } else if (i->available) {
1666 new_devices.push_back (mds);
1669 _midi_devices = new_devices;
1671 if (_midi_devices.empty()) {
1672 midi_devices_button.hide ();
1674 midi_devices_button.show ();
1679 EngineControl::parameter_changed ()
1683 EngineControl::State
1684 EngineControl::get_matching_state (const string& backend)
1686 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1687 if ((*i)->backend == backend) {
1694 EngineControl::State
1695 EngineControl::get_matching_state (
1696 const string& backend,
1697 const string& driver,
1698 const string& device)
1700 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1701 if ((*i)->backend == backend &&
1702 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1710 EngineControl::State
1711 EngineControl::get_matching_state (
1712 const string& backend,
1713 const string& driver,
1714 const string& input_device,
1715 const string& output_device)
1717 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1718 if ((*i)->backend == backend &&
1719 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1727 EngineControl::State
1728 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1730 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1733 if (backend->use_separate_input_and_output_devices ()) {
1734 return get_matching_state (backend_combo.get_active_text(),
1735 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1736 input_device_combo.get_active_text(),
1737 output_device_combo.get_active_text());
1739 return get_matching_state (backend_combo.get_active_text(),
1740 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1741 device_combo.get_active_text());
1745 return get_matching_state (backend_combo.get_active_text(),
1747 device_combo.get_active_text());
1750 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1751 const EngineControl::State& state2)
1753 if (state1->backend == state2->backend &&
1754 state1->driver == state2->driver &&
1755 state1->device == state2->device &&
1756 state1->input_device == state2->input_device &&
1757 state1->output_device == state2->output_device) {
1764 EngineControl::state_sort_cmp (const State &a, const State &b) {
1768 else if (b->active) {
1772 return a->lru < b->lru;
1776 EngineControl::State
1777 EngineControl::save_state ()
1781 if (!_have_control) {
1782 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1784 state->lru = time (NULL) ;
1787 state.reset(new StateStruct);
1788 state->backend = get_backend ();
1790 state.reset(new StateStruct);
1791 store_state (state);
1794 for (StateList::iterator i = states.begin(); i != states.end();) {
1795 if (equivalent_states (*i, state)) {
1796 i = states.erase(i);
1802 states.push_back (state);
1804 states.sort (state_sort_cmp);
1810 EngineControl::store_state (State state)
1812 state->backend = get_backend ();
1813 state->driver = get_driver ();
1814 state->device = get_device_name ();
1815 state->input_device = get_input_device_name ();
1816 state->output_device = get_output_device_name ();
1817 state->sample_rate = get_rate ();
1818 state->buffer_size = get_buffer_size ();
1819 state->n_periods = get_nperiods ();
1820 state->input_latency = get_input_latency ();
1821 state->output_latency = get_output_latency ();
1822 state->input_channels = get_input_channels ();
1823 state->output_channels = get_output_channels ();
1824 state->midi_option = get_midi_option ();
1825 state->midi_devices = _midi_devices;
1826 state->lru = time (NULL) ;
1830 EngineControl::maybe_display_saved_state ()
1832 if (!_have_control) {
1836 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1839 DEBUG_ECONTROL ("Restoring saved state");
1840 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1842 if (!_desired_sample_rate) {
1843 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1845 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1847 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1848 /* call this explicitly because we're ignoring changes to
1849 the controls at this point.
1851 show_buffer_duration ();
1852 input_latency.set_value (state->input_latency);
1853 output_latency.set_value (state->output_latency);
1855 if (!state->midi_option.empty()) {
1856 midi_option_combo.set_active_text (state->midi_option);
1857 _midi_devices = state->midi_devices;
1860 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1865 EngineControl::get_state ()
1867 LocaleGuard lg (X_("C"));
1869 XMLNode* root = new XMLNode ("AudioMIDISetup");
1872 if (!states.empty()) {
1873 XMLNode* state_nodes = new XMLNode ("EngineStates");
1875 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1877 XMLNode* node = new XMLNode ("State");
1879 node->add_property ("backend", (*i)->backend);
1880 node->add_property ("driver", (*i)->driver);
1881 node->add_property ("device", (*i)->device);
1882 node->add_property ("input-device", (*i)->input_device);
1883 node->add_property ("output-device", (*i)->output_device);
1884 node->add_property ("sample-rate", (*i)->sample_rate);
1885 node->add_property ("buffer-size", (*i)->buffer_size);
1886 node->add_property ("n-periods", (*i)->n_periods);
1887 node->add_property ("input-latency", (*i)->input_latency);
1888 node->add_property ("output-latency", (*i)->output_latency);
1889 node->add_property ("input-channels", (*i)->input_channels);
1890 node->add_property ("output-channels", (*i)->output_channels);
1891 node->add_property ("active", (*i)->active ? "yes" : "no");
1892 node->add_property ("midi-option", (*i)->midi_option);
1893 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1895 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1896 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1897 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1898 midi_device_stuff->add_property (X_("name"), (*p)->name);
1899 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1900 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1901 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1902 midi_devices->add_child_nocopy (*midi_device_stuff);
1904 node->add_child_nocopy (*midi_devices);
1906 state_nodes->add_child_nocopy (*node);
1909 root->add_child_nocopy (*state_nodes);
1916 EngineControl::set_default_state ()
1918 vector<string> backend_names;
1919 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1921 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1922 backend_names.push_back ((*b)->name);
1924 backend_combo.set_active_text (backend_names.front());
1926 // We could set default backends per platform etc here
1932 EngineControl::set_state (const XMLNode& root)
1934 XMLNodeList clist, cclist;
1935 XMLNodeConstIterator citer, cciter;
1937 XMLNode* grandchild;
1938 XMLProperty* prop = NULL;
1940 fprintf (stderr, "EngineControl::set_state\n");
1942 if (root.name() != "AudioMIDISetup") {
1946 clist = root.children();
1950 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1954 if (child->name() != "EngineStates") {
1958 cclist = child->children();
1960 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1961 State state (new StateStruct);
1963 grandchild = *cciter;
1965 if (grandchild->name() != "State") {
1969 if ((prop = grandchild->property ("backend")) == 0) {
1972 state->backend = prop->value ();
1974 if ((prop = grandchild->property ("driver")) == 0) {
1977 state->driver = prop->value ();
1979 if ((prop = grandchild->property ("device")) == 0) {
1982 state->device = prop->value ();
1984 if ((prop = grandchild->property ("input-device")) == 0) {
1987 state->input_device = prop->value ();
1989 if ((prop = grandchild->property ("output-device")) == 0) {
1992 state->output_device = prop->value ();
1994 if ((prop = grandchild->property ("sample-rate")) == 0) {
1997 state->sample_rate = atof (prop->value ());
1999 if ((prop = grandchild->property ("buffer-size")) == 0) {
2002 state->buffer_size = atoi (prop->value ());
2004 if ((prop = grandchild->property ("n-periods")) == 0) {
2005 // optional (new value in 4.5)
2006 state->n_periods = 0;
2008 state->n_periods = atoi (prop->value ());
2011 if ((prop = grandchild->property ("input-latency")) == 0) {
2014 state->input_latency = atoi (prop->value ());
2016 if ((prop = grandchild->property ("output-latency")) == 0) {
2019 state->output_latency = atoi (prop->value ());
2021 if ((prop = grandchild->property ("input-channels")) == 0) {
2024 state->input_channels = atoi (prop->value ());
2026 if ((prop = grandchild->property ("output-channels")) == 0) {
2029 state->output_channels = atoi (prop->value ());
2031 if ((prop = grandchild->property ("active")) == 0) {
2034 state->active = string_is_affirmative (prop->value ());
2036 if ((prop = grandchild->property ("midi-option")) == 0) {
2039 state->midi_option = prop->value ();
2041 state->midi_devices.clear();
2043 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2044 const XMLNodeList mnc = midinode->children();
2045 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2046 if ((*n)->property (X_("name")) == 0
2047 || (*n)->property (X_("enabled")) == 0
2048 || (*n)->property (X_("input-latency")) == 0
2049 || (*n)->property (X_("output-latency")) == 0
2054 MidiDeviceSettings ptr (new MidiDeviceSetting(
2055 (*n)->property (X_("name"))->value (),
2056 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2057 atoi ((*n)->property (X_("input-latency"))->value ()),
2058 atoi ((*n)->property (X_("output-latency"))->value ())
2060 state->midi_devices.push_back (ptr);
2064 if ((prop = grandchild->property ("lru"))) {
2065 state->lru = atoi (prop->value ());
2069 /* remove accumulated duplicates (due to bug in ealier version)
2070 * this can be removed again before release
2072 for (StateList::iterator i = states.begin(); i != states.end();) {
2073 if ((*i)->backend == state->backend &&
2074 (*i)->driver == state->driver &&
2075 (*i)->device == state->device) {
2076 i = states.erase(i);
2083 states.push_back (state);
2087 /* now see if there was an active state and switch the setup to it */
2089 // purge states of backend that are not available in this built
2090 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2091 vector<std::string> backend_names;
2093 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2094 backend_names.push_back((*i)->name);
2096 for (StateList::iterator i = states.begin(); i != states.end();) {
2097 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2098 i = states.erase(i);
2104 states.sort (state_sort_cmp);
2106 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2109 return set_current_state (*i);
2116 EngineControl::set_current_state (const State& state)
2118 DEBUG_ECONTROL ("set_current_state");
2120 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2122 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2123 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2124 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2125 // this shouldn't happen as the invalid backend names should have been
2126 // removed from the list of states.
2130 // now reflect the change in the backend in the GUI so backend_changed will
2131 // do the right thing
2132 backend_combo.set_active_text (state->backend);
2134 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2136 // we don't have control don't restore state
2141 if (!state->driver.empty ()) {
2142 if (!backend->requires_driver_selection ()) {
2143 DEBUG_ECONTROL ("Backend should require driver selection");
2144 // A backend has changed from having driver selection to not having
2145 // it or someone has been manually editing a config file and messed
2150 if (backend->set_driver (state->driver) != 0) {
2151 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2152 // Driver names for a backend have changed and the name in the
2153 // config file is now invalid or support for driver is no longer
2154 // included in the backend
2157 // no need to set the driver_combo as backend_changed will use
2158 // backend->driver_name to set the active driver
2161 if (!state->device.empty ()) {
2162 if (backend->set_device_name (state->device) != 0) {
2164 string_compose ("Unable to set device name %1", state->device));
2165 // device is no longer available on the system
2168 // no need to set active device as it will be picked up in
2169 // via backend_changed ()/set_device_popdown_strings
2172 // backend supports separate input/output devices
2173 if (backend->set_input_device_name (state->input_device) != 0) {
2174 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2175 state->input_device));
2176 // input device is no longer available on the system
2180 if (backend->set_output_device_name (state->output_device) != 0) {
2181 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2182 state->input_device));
2183 // output device is no longer available on the system
2186 // no need to set active devices as it will be picked up in via
2187 // backend_changed ()/set_*_device_popdown_strings
2192 // Now restore the state of the rest of the controls
2194 // We don't use a SignalBlocker as set_current_state is currently only
2195 // called from set_state before any signals are connected. If at some point
2196 // a more general named state mechanism is implemented and
2197 // set_current_state is called while signals are connected then a
2198 // SignalBlocker will need to be instantiated before setting these.
2200 device_combo.set_active_text (state->device);
2201 input_device_combo.set_active_text (state->input_device);
2202 output_device_combo.set_active_text (state->output_device);
2203 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2204 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2205 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2206 input_latency.set_value (state->input_latency);
2207 output_latency.set_value (state->output_latency);
2208 midi_option_combo.set_active_text (state->midi_option);
2213 EngineControl::push_state_to_backend (bool start)
2215 DEBUG_ECONTROL ("push_state_to_backend");
2216 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2217 PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2223 /* figure out what is going to change */
2225 bool restart_required = false;
2226 bool was_running = ARDOUR::AudioEngine::instance()->running();
2227 bool change_driver = false;
2228 bool change_device = false;
2229 bool change_rate = false;
2230 bool change_bufsize = false;
2231 bool change_nperiods = false;
2232 bool change_latency = false;
2233 bool change_channels = false;
2234 bool change_midi = false;
2236 uint32_t ochan = get_output_channels ();
2237 uint32_t ichan = get_input_channels ();
2239 if (_have_control) {
2241 if (started_at_least_once) {
2243 /* we can control the backend */
2245 if (backend->requires_driver_selection()) {
2246 if (get_driver() != backend->driver_name()) {
2247 change_driver = true;
2251 if (backend->use_separate_input_and_output_devices()) {
2252 if (get_input_device_name() != backend->input_device_name()) {
2253 change_device = true;
2255 if (get_output_device_name() != backend->output_device_name()) {
2256 change_device = true;
2259 if (get_device_name() != backend->device_name()) {
2260 change_device = true;
2264 if (queue_device_changed) {
2265 change_device = true;
2268 if (get_rate() != backend->sample_rate()) {
2272 if (get_buffer_size() != backend->buffer_size()) {
2273 change_bufsize = true;
2276 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2277 && get_nperiods() != backend->period_size()) {
2278 change_nperiods = true;
2281 if (get_midi_option() != backend->midi_option()) {
2285 /* zero-requested channels means "all available" */
2288 ichan = backend->input_channels();
2292 ochan = backend->output_channels();
2295 if (ichan != backend->input_channels()) {
2296 change_channels = true;
2299 if (ochan != backend->output_channels()) {
2300 change_channels = true;
2303 if (get_input_latency() != backend->systemic_input_latency() ||
2304 get_output_latency() != backend->systemic_output_latency()) {
2305 change_latency = true;
2308 /* backend never started, so we have to force a group
2311 change_device = true;
2312 if (backend->requires_driver_selection()) {
2313 change_driver = true;
2316 change_bufsize = true;
2317 change_channels = true;
2318 change_latency = true;
2320 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2325 /* we have no control over the backend, meaning that we can
2326 * only possibly change sample rate and buffer size.
2330 if (get_rate() != backend->sample_rate()) {
2331 change_bufsize = true;
2334 if (get_buffer_size() != backend->buffer_size()) {
2335 change_bufsize = true;
2339 queue_device_changed = false;
2341 if (!_have_control) {
2343 /* We do not have control over the backend, so the best we can
2344 * do is try to change the sample rate and/or bufsize and get
2348 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2352 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2357 backend->set_sample_rate (get_rate());
2360 if (change_bufsize) {
2361 backend->set_buffer_size (get_buffer_size());
2365 if (ARDOUR::AudioEngine::instance()->start ()) {
2366 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2376 /* determine if we need to stop the backend before changing parameters */
2378 if (change_driver || change_device || change_channels || change_nperiods ||
2379 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2380 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2382 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2383 restart_required = true;
2385 restart_required = false;
2390 if (restart_required) {
2391 if (ARDOUR::AudioEngine::instance()->stop()) {
2397 if (change_driver && backend->set_driver (get_driver())) {
2398 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2401 if (backend->use_separate_input_and_output_devices()) {
2402 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2403 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2406 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2407 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2411 if (change_device && backend->set_device_name (get_device_name())) {
2412 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2416 if (change_rate && backend->set_sample_rate (get_rate())) {
2417 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2420 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2421 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2424 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2425 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2429 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2430 if (backend->set_input_channels (get_input_channels())) {
2431 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2434 if (backend->set_output_channels (get_output_channels())) {
2435 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2439 if (change_latency) {
2440 if (backend->set_systemic_input_latency (get_input_latency())) {
2441 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2444 if (backend->set_systemic_output_latency (get_output_latency())) {
2445 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2451 backend->set_midi_option (get_midi_option());
2455 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2456 if (_measure_midi) {
2457 if (*p == _measure_midi) {
2458 backend->set_midi_device_enabled ((*p)->name, true);
2460 backend->set_midi_device_enabled ((*p)->name, false);
2462 if (backend->can_change_systemic_latency_when_running ()) {
2463 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2464 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2468 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2469 if (backend->can_set_systemic_midi_latencies()) {
2470 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2471 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2476 if (start || (was_running && restart_required)) {
2477 if (ARDOUR::AudioEngine::instance()->start()) {
2488 EngineControl::post_push ()
2490 /* get a pointer to the current state object, creating one if
2494 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2497 state = save_state ();
2503 states.sort (state_sort_cmp);
2507 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2508 (*i)->active = false;
2511 /* mark this one active (to be used next time the dialog is
2515 state->active = true;
2517 if (_have_control) { // XXX
2518 manage_control_app_sensitivity ();
2521 /* schedule a redisplay of MIDI ports */
2522 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2527 EngineControl::get_rate () const
2529 float r = atof (sample_rate_combo.get_active_text ());
2530 /* the string may have been translated with an abbreviation for
2531 * thousands, so use a crude heuristic to fix this.
2541 EngineControl::get_buffer_size () const
2543 string txt = buffer_size_combo.get_active_text ();
2546 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2547 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2548 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2556 EngineControl::get_nperiods () const
2558 string txt = nperiods_combo.get_active_text ();
2559 return atoi (txt.c_str());
2563 EngineControl::get_midi_option () const
2565 return midi_option_combo.get_active_text();
2569 EngineControl::get_input_channels() const
2571 if (ARDOUR::Profile->get_mixbus()) {
2572 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2573 if (!backend) return 0;
2574 return backend->input_channels();
2576 return (uint32_t) input_channels_adjustment.get_value();
2580 EngineControl::get_output_channels() const
2582 if (ARDOUR::Profile->get_mixbus()) {
2583 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2584 if (!backend) return 0;
2585 return backend->input_channels();
2587 return (uint32_t) output_channels_adjustment.get_value();
2591 EngineControl::get_input_latency() const
2593 return (uint32_t) input_latency_adjustment.get_value();
2597 EngineControl::get_output_latency() const
2599 return (uint32_t) output_latency_adjustment.get_value();
2603 EngineControl::get_backend () const
2605 return backend_combo.get_active_text ();
2609 EngineControl::get_driver () const
2611 if (driver_combo.get_parent()) {
2612 return driver_combo.get_active_text ();
2619 EngineControl::get_device_name () const
2621 return device_combo.get_active_text ();
2625 EngineControl::get_input_device_name () const
2627 return input_device_combo.get_active_text ();
2631 EngineControl::get_output_device_name () const
2633 return output_device_combo.get_active_text ();
2637 EngineControl::control_app_button_clicked ()
2639 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2645 backend->launch_control_app ();
2649 EngineControl::start_stop_button_clicked ()
2651 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2657 if (ARDOUR::AudioEngine::instance()->running()) {
2658 ARDOUR::AudioEngine::instance()->stop ();
2665 EngineControl::update_devices_button_clicked ()
2667 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2673 if (backend->update_devices()) {
2674 device_list_changed ();
2679 EngineControl::manage_control_app_sensitivity ()
2681 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2687 string appname = backend->control_app_name();
2689 if (appname.empty()) {
2690 control_app_button.set_sensitive (false);
2692 control_app_button.set_sensitive (true);
2697 EngineControl::set_desired_sample_rate (uint32_t sr)
2699 _desired_sample_rate = sr;
2704 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2706 if (page_num == 0) {
2707 cancel_button->set_sensitive (true);
2708 _measure_midi.reset();
2709 update_sensitivity ();
2711 cancel_button->set_sensitive (false);
2712 ok_button->set_sensitive (false);
2715 if (page_num == midi_tab) {
2717 refresh_midi_display ();
2720 if (page_num == latency_tab) {
2723 if (ARDOUR::AudioEngine::instance()->running()) {
2728 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2730 /* save any existing latency values */
2732 uint32_t il = (uint32_t) input_latency.get_value ();
2733 uint32_t ol = (uint32_t) input_latency.get_value ();
2735 /* reset to zero so that our new test instance
2736 will be clean of any existing latency measures.
2738 NB. this should really be done by the backend
2739 when stated for latency measurement.
2742 input_latency.set_value (0);
2743 output_latency.set_value (0);
2745 push_state_to_backend (false);
2749 input_latency.set_value (il);
2750 output_latency.set_value (ol);
2753 // This should be done in push_state_to_backend()
2754 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2755 disable_latency_tab ();
2758 enable_latency_tab ();
2762 end_latency_detection ();
2763 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2768 /* latency measurement */
2771 EngineControl::check_audio_latency_measurement ()
2773 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2775 if (mtdm->resolve () < 0) {
2776 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2780 if (mtdm->get_peak () > 0.707f) {
2781 // get_peak() resets the peak-hold in the detector.
2782 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2783 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2787 if (mtdm->err () > 0.3) {
2793 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2795 if (sample_rate == 0) {
2796 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2797 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2801 int frames_total = mtdm->del();
2802 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2804 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2805 _("Detected roundtrip latency: "),
2806 frames_total, frames_total * 1000.0f/sample_rate,
2807 _("Systemic latency: "),
2808 extra, extra * 1000.0f/sample_rate);
2812 if (mtdm->err () > 0.2) {
2814 strcat (buf, _("(signal detection error)"));
2820 strcat (buf, _("(inverted - bad wiring)"));
2824 lm_results.set_markup (string_compose (results_markup, buf));
2827 have_lm_results = true;
2828 end_latency_detection ();
2829 lm_use_button.set_sensitive (true);
2837 EngineControl::check_midi_latency_measurement ()
2839 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2841 if (!mididm->have_signal () || mididm->latency () == 0) {
2842 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2847 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2849 if (sample_rate == 0) {
2850 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2851 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2855 ARDOUR::framecnt_t frames_total = mididm->latency();
2856 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2857 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2858 _("Detected roundtrip latency: "),
2859 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2860 _("Systemic latency: "),
2861 extra, extra * 1000.0f / sample_rate);
2865 if (!mididm->ok ()) {
2867 strcat (buf, _("(averaging)"));
2871 if (mididm->deviation () > 50.0) {
2873 strcat (buf, _("(too large jitter)"));
2875 } else if (mididm->deviation () > 10.0) {
2877 strcat (buf, _("(large jitter)"));
2881 have_lm_results = true;
2882 end_latency_detection ();
2883 lm_use_button.set_sensitive (true);
2884 lm_results.set_markup (string_compose (results_markup, buf));
2886 } else if (mididm->processed () > 400) {
2887 have_lm_results = false;
2888 end_latency_detection ();
2889 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2893 lm_results.set_markup (string_compose (results_markup, buf));
2899 EngineControl::start_latency_detection ()
2901 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2902 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2904 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2905 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2906 if (_measure_midi) {
2907 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2909 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2911 lm_measure_label.set_text (_("Cancel"));
2912 have_lm_results = false;
2913 lm_use_button.set_sensitive (false);
2914 lm_input_channel_combo.set_sensitive (false);
2915 lm_output_channel_combo.set_sensitive (false);
2921 EngineControl::end_latency_detection ()
2923 latency_timeout.disconnect ();
2924 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2925 lm_measure_label.set_text (_("Measure"));
2926 if (!have_lm_results) {
2927 lm_use_button.set_sensitive (false);
2929 lm_input_channel_combo.set_sensitive (true);
2930 lm_output_channel_combo.set_sensitive (true);
2935 EngineControl::latency_button_clicked ()
2938 start_latency_detection ();
2940 end_latency_detection ();
2945 EngineControl::latency_back_button_clicked ()
2947 ARDOUR::AudioEngine::instance()->stop(true);
2948 notebook.set_current_page(0);
2952 EngineControl::use_latency_button_clicked ()
2954 if (_measure_midi) {
2955 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2959 ARDOUR::framecnt_t frames_total = mididm->latency();
2960 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2961 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2962 _measure_midi->input_latency = one_way;
2963 _measure_midi->output_latency = one_way;
2964 notebook.set_current_page (midi_tab);
2966 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2972 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2973 one_way = std::max (0., one_way);
2975 input_latency_adjustment.set_value (one_way);
2976 output_latency_adjustment.set_value (one_way);
2978 /* back to settings page */
2979 notebook.set_current_page (0);
2984 EngineControl::on_delete_event (GdkEventAny* ev)
2986 if (notebook.get_current_page() == 2) {
2987 /* currently on latency tab - be sure to clean up */
2988 end_latency_detection ();
2990 return ArdourDialog::on_delete_event (ev);
2994 EngineControl::engine_running ()
2996 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2999 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3000 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3002 if (backend->can_set_period_size ()) {
3003 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3006 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3007 connect_disconnect_button.show();
3009 started_at_least_once = true;
3010 if (_have_control) {
3011 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3013 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3015 update_sensitivity();
3019 EngineControl::engine_stopped ()
3021 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3024 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3025 connect_disconnect_button.show();
3027 if (_have_control) {
3028 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3030 engine_status.set_markup(X_(""));
3033 update_sensitivity();
3037 EngineControl::device_list_changed ()
3039 if (ignore_device_changes) {
3042 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3044 midi_option_changed();
3048 EngineControl::connect_disconnect_click()
3050 if (ARDOUR::AudioEngine::instance()->running()) {
3058 EngineControl::calibrate_audio_latency ()
3060 _measure_midi.reset ();
3061 have_lm_results = false;
3062 lm_use_button.set_sensitive (false);
3063 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3064 notebook.set_current_page (latency_tab);
3068 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3071 have_lm_results = false;
3072 lm_use_button.set_sensitive (false);
3073 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3074 notebook.set_current_page (latency_tab);
3078 EngineControl::configure_midi_devices ()
3080 notebook.set_current_page (midi_tab);