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 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 #if ! defined __APPLE__ && ! defined PLATFORM_WINDOWS // => linux, YAY
653 /* Currently the only backend with dedicated Midi setup is ALSA.
654 * lot of people complain that this is greyed out
655 * "I can't use MIDI, the setup is greyed out"
657 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
663 EngineControl::build_no_control_notebook ()
665 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
668 using namespace Notebook_Helpers;
670 vector<string> strings;
671 AttachOptions xopt = AttachOptions (FILL|EXPAND);
672 int row = 1; // row zero == backend combo
673 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
675 label = manage (new Label);
676 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
677 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
680 if (backend->can_change_sample_rate_when_running()) {
681 label = manage (left_aligned_label (_("Sample rate:")));
682 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
683 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
687 if (backend->can_change_buffer_size_when_running()) {
688 label = manage (left_aligned_label (_("Buffer size:")));
689 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
690 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
691 buffer_size_duration_label.set_alignment (0.0); /* left-align */
692 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
696 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
700 EngineControl::~EngineControl ()
702 ignore_changes = true;
706 EngineControl::disable_latency_tab ()
708 vector<string> empty;
709 set_popdown_strings (lm_output_channel_combo, empty);
710 set_popdown_strings (lm_input_channel_combo, empty);
711 lm_measure_button.set_sensitive (false);
712 lm_use_button.set_sensitive (false);
716 EngineControl::enable_latency_tab ()
718 vector<string> outputs;
719 vector<string> inputs;
721 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
722 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
723 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
725 if (!ARDOUR::AudioEngine::instance()->running()) {
726 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
727 notebook.set_current_page (0);
731 else if (inputs.empty() || outputs.empty()) {
732 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
733 notebook.set_current_page (0);
738 lm_back_button_signal.disconnect();
740 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
743 lm_back_button_signal = lm_back_button.signal_clicked().connect(
744 sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
748 set_popdown_strings (lm_output_channel_combo, outputs);
749 lm_output_channel_combo.set_active_text (outputs.front());
750 lm_output_channel_combo.set_sensitive (true);
752 set_popdown_strings (lm_input_channel_combo, inputs);
753 lm_input_channel_combo.set_active_text (inputs.front());
754 lm_input_channel_combo.set_sensitive (true);
756 lm_measure_button.set_sensitive (true);
760 EngineControl::setup_midi_tab_for_backend ()
762 string backend = backend_combo.get_active_text ();
764 Gtkmm2ext::container_clear (midi_vbox);
766 midi_vbox.set_border_width (12);
767 midi_device_table.set_border_width (12);
769 if (backend == "JACK") {
770 setup_midi_tab_for_jack ();
773 midi_vbox.pack_start (midi_device_table, true, true);
774 midi_vbox.pack_start (midi_back_button, false, false);
775 midi_vbox.show_all ();
779 EngineControl::update_sensitivity ()
781 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
783 ok_button->set_sensitive (false);
784 start_stop_button.set_sensitive (false);
789 size_t devices_available = 0;
791 if (backend->use_separate_input_and_output_devices ()) {
792 devices_available += get_popdown_string_count (input_device_combo);
793 devices_available += get_popdown_string_count (output_device_combo);
795 devices_available += get_popdown_string_count (device_combo);
798 if (devices_available == 0) {
800 input_latency.set_sensitive (false);
801 output_latency.set_sensitive (false);
802 input_channels.set_sensitive (false);
803 output_channels.set_sensitive (false);
805 input_latency.set_sensitive (true);
806 output_latency.set_sensitive (true);
807 input_channels.set_sensitive (true);
808 output_channels.set_sensitive (true);
811 if (get_popdown_string_count (buffer_size_combo) > 0) {
812 if (!ARDOUR::AudioEngine::instance()->running()) {
813 buffer_size_combo.set_sensitive (valid);
814 } else if (backend->can_change_sample_rate_when_running()) {
815 buffer_size_combo.set_sensitive (valid || !_have_control);
819 * Currently there is no way to manually stop the
820 * engine in order to re-configure it.
821 * This needs to remain sensitive for now.
823 * (it's also handy to implicily
824 * re-start the engine)
826 buffer_size_combo.set_sensitive (true);
828 buffer_size_combo.set_sensitive (false);
832 buffer_size_combo.set_sensitive (false);
836 if (get_popdown_string_count (sample_rate_combo) > 0) {
837 if (!ARDOUR::AudioEngine::instance()->running()) {
838 sample_rate_combo.set_sensitive (true);
840 sample_rate_combo.set_sensitive (false);
843 sample_rate_combo.set_sensitive (false);
847 if (get_popdown_string_count (nperiods_combo) > 0) {
848 if (!ARDOUR::AudioEngine::instance()->running()) {
849 nperiods_combo.set_sensitive (true);
851 nperiods_combo.set_sensitive (false);
854 nperiods_combo.set_sensitive (false);
858 start_stop_button.set_sensitive(true);
859 start_stop_button.show();
860 if (ARDOUR::AudioEngine::instance()->running()) {
861 start_stop_button.set_text("Stop");
862 update_devices_button.set_sensitive(false);
864 if (backend->can_request_update_devices()) {
865 update_devices_button.show();
867 update_devices_button.hide();
869 start_stop_button.set_text("Start");
870 update_devices_button.set_sensitive(true);
873 update_devices_button.set_sensitive(false);
874 update_devices_button.hide();
875 start_stop_button.set_sensitive(false);
876 start_stop_button.hide();
879 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
880 input_device_combo.set_sensitive (false);
881 output_device_combo.set_sensitive (false);
882 device_combo.set_sensitive (false);
883 driver_combo.set_sensitive (false);
885 input_device_combo.set_sensitive (true);
886 output_device_combo.set_sensitive (true);
887 device_combo.set_sensitive (true);
888 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
889 driver_combo.set_sensitive (true);
891 driver_combo.set_sensitive (false);
895 if (valid || !_have_control) {
896 ok_button->set_sensitive (true);
898 ok_button->set_sensitive (false);
903 EngineControl::setup_midi_tab_for_jack ()
908 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
910 device->input_latency = a->get_value();
912 device->output_latency = a->get_value();
917 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
918 b->set_active (!b->get_active());
919 device->enabled = b->get_active();
920 refresh_midi_display(device->name);
924 EngineControl::refresh_midi_display (std::string focus)
926 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
930 AttachOptions xopt = AttachOptions (FILL|EXPAND);
933 Gtkmm2ext::container_clear (midi_device_table);
935 midi_device_table.set_spacings (6);
937 l = manage (new Label);
938 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
939 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
940 l->set_alignment (0.5, 0.5);
944 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
945 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
946 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
947 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
949 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
950 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
951 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
952 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
955 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
960 bool enabled = (*p)->enabled;
962 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
963 m->set_name ("midi device");
964 m->set_can_focus (Gtk::CAN_FOCUS);
965 m->add_events (Gdk::BUTTON_RELEASE_MASK);
966 m->set_active (enabled);
967 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
968 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
969 if ((*p)->name == focus) {
973 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
974 s = manage (new Gtk::SpinButton (*a));
975 a->set_value ((*p)->input_latency);
976 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
977 s->set_sensitive (_can_set_midi_latencies && enabled);
978 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
980 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
981 s = manage (new Gtk::SpinButton (*a));
982 a->set_value ((*p)->output_latency);
983 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
984 s->set_sensitive (_can_set_midi_latencies && enabled);
985 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
987 b = manage (new Button (_("Calibrate")));
988 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
989 b->set_sensitive (_can_set_midi_latencies && enabled);
990 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
997 EngineControl::backend_changed ()
999 SignalBlocker blocker (*this, "backend_changed");
1000 string backend_name = backend_combo.get_active_text();
1001 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1003 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1004 /* eh? setting the backend failed... how ? */
1005 /* A: stale config contains a backend that does not exist in current build */
1009 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1011 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1014 setup_midi_tab_for_backend ();
1015 _midi_devices.clear();
1017 if (backend->requires_driver_selection()) {
1018 if (set_driver_popdown_strings ()) {
1022 /* this will change the device text which will cause a call to
1023 * device changed which will set up parameters
1028 update_midi_options ();
1030 connect_disconnect_button.hide();
1032 midi_option_changed();
1034 started_at_least_once = false;
1036 /* changing the backend implies stopping the engine
1037 * ARDOUR::AudioEngine() may or may not emit this signal
1038 * depending on previous engine state
1040 engine_stopped (); // set "active/inactive"
1042 if (!_have_control) {
1043 // set settings from backend that we do have control over
1044 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1047 if (_have_control && !ignore_changes) {
1048 // set driver & devices
1049 State state = get_matching_state (backend_combo.get_active_text());
1051 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1052 set_current_state (state);
1056 if (!ignore_changes) {
1057 maybe_display_saved_state ();
1062 EngineControl::update_midi_options ()
1064 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1065 vector<string> midi_options = backend->enumerate_midi_options();
1067 if (midi_options.size() == 1) {
1068 /* only contains the "none" option */
1069 midi_option_combo.set_sensitive (false);
1071 if (_have_control) {
1072 set_popdown_strings (midi_option_combo, midi_options);
1073 midi_option_combo.set_active_text (midi_options.front());
1074 midi_option_combo.set_sensitive (true);
1076 midi_option_combo.set_sensitive (false);
1082 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1084 if (ARDOUR::Profile->get_mixbus()) {
1088 uint32_t cnt = (uint32_t) sb->get_value();
1090 sb->set_text (_("all available channels"));
1093 snprintf (buf, sizeof (buf), "%d", cnt);
1099 // @return true if there are drivers available
1101 EngineControl::set_driver_popdown_strings ()
1103 DEBUG_ECONTROL ("set_driver_popdown_strings");
1104 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1105 vector<string> drivers = backend->enumerate_drivers();
1107 if (drivers.empty ()) {
1108 // This is an error...?
1112 string current_driver = backend->driver_name ();
1114 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1116 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1119 current_driver = drivers.front ();
1122 set_popdown_strings (driver_combo, drivers);
1124 string_compose ("driver_combo.set_active_text: %1", current_driver));
1125 driver_combo.set_active_text (current_driver);
1130 EngineControl::get_default_device(const string& current_device_name,
1131 const vector<string>& available_devices)
1133 // If the current device is available, use it as default
1134 if (std::find (available_devices.begin (),
1135 available_devices.end (),
1136 current_device_name) != available_devices.end ()) {
1138 return current_device_name;
1141 using namespace ARDOUR;
1143 string default_device_name =
1144 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1146 vector<string>::const_iterator i;
1148 // If there is a "Default" device available, use it
1149 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1150 if (*i == default_device_name) {
1155 string none_device_name =
1156 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1158 // Use the first device that isn't "None"
1159 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1160 if (*i != none_device_name) {
1165 // Use "None" if there are no other available
1166 return available_devices.front();
1169 // @return true if there are devices available
1171 EngineControl::set_device_popdown_strings ()
1173 DEBUG_ECONTROL ("set_device_popdown_strings");
1174 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1175 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1177 /* NOTE: Ardour currently does not display the "available" field of the
1180 * Doing so would require a different GUI widget than the combo
1181 * box/popdown that we currently use, since it has no way to list
1182 * items that are not selectable. Something more like a popup menu,
1183 * which could have unselectable items, would be appropriate.
1186 vector<string> available_devices;
1188 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1189 available_devices.push_back (i->name);
1192 if (available_devices.empty ()) {
1196 set_popdown_strings (device_combo, available_devices);
1198 std::string default_device =
1199 get_default_device(backend->device_name(), available_devices);
1202 string_compose ("set device_combo active text: %1", default_device));
1204 device_combo.set_active_text(default_device);
1208 // @return true if there are input devices available
1210 EngineControl::set_input_device_popdown_strings ()
1212 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1213 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1214 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1216 vector<string> available_devices;
1218 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1219 available_devices.push_back (i->name);
1222 if (available_devices.empty()) {
1226 set_popdown_strings (input_device_combo, available_devices);
1228 std::string default_device =
1229 get_default_device(backend->input_device_name(), available_devices);
1232 string_compose ("set input_device_combo active text: %1", default_device));
1233 input_device_combo.set_active_text(default_device);
1237 // @return true if there are output devices available
1239 EngineControl::set_output_device_popdown_strings ()
1241 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1242 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1243 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1245 vector<string> available_devices;
1247 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1248 available_devices.push_back (i->name);
1251 if (available_devices.empty()) {
1255 set_popdown_strings (output_device_combo, available_devices);
1257 std::string default_device =
1258 get_default_device(backend->output_device_name(), available_devices);
1261 string_compose ("set output_device_combo active text: %1", default_device));
1262 output_device_combo.set_active_text(default_device);
1267 EngineControl::list_devices ()
1269 DEBUG_ECONTROL ("list_devices");
1270 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1273 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1275 bool devices_available = false;
1277 if (backend->use_separate_input_and_output_devices ()) {
1278 bool input_devices_available = set_input_device_popdown_strings ();
1279 bool output_devices_available = set_output_device_popdown_strings ();
1280 devices_available = input_devices_available || output_devices_available;
1282 devices_available = set_device_popdown_strings ();
1285 if (devices_available) {
1288 device_combo.clear();
1289 input_device_combo.clear();
1290 output_device_combo.clear();
1292 update_sensitivity ();
1296 EngineControl::driver_changed ()
1298 SignalBlocker blocker (*this, "driver_changed");
1299 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1302 backend->set_driver (driver_combo.get_active_text());
1305 // TODO load LRU device(s) for backend + driver combo
1307 if (!ignore_changes) {
1308 maybe_display_saved_state ();
1313 EngineControl::get_sample_rates_for_all_devices ()
1315 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1316 ARDOUR::AudioEngine::instance ()->current_backend ();
1317 vector<float> all_rates;
1319 if (backend->use_separate_input_and_output_devices ()) {
1320 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1322 all_rates = backend->available_sample_rates (get_device_name ());
1328 EngineControl::get_default_sample_rates ()
1330 vector<float> rates;
1331 rates.push_back (8000.0f);
1332 rates.push_back (16000.0f);
1333 rates.push_back (32000.0f);
1334 rates.push_back (44100.0f);
1335 rates.push_back (48000.0f);
1336 rates.push_back (88200.0f);
1337 rates.push_back (96000.0f);
1338 rates.push_back (192000.0f);
1339 rates.push_back (384000.0f);
1344 EngineControl::set_samplerate_popdown_strings ()
1346 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1347 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1352 if (_have_control) {
1353 sr = get_sample_rates_for_all_devices ();
1355 sr = get_default_sample_rates ();
1358 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1359 s.push_back (rate_as_string (*x));
1360 if (*x == _desired_sample_rate) {
1365 set_popdown_strings (sample_rate_combo, s);
1368 if (desired.empty ()) {
1369 float new_active_sr = backend->default_sample_rate ();
1371 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1372 new_active_sr = sr.front ();
1375 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1377 sample_rate_combo.set_active_text (desired);
1381 update_sensitivity ();
1385 EngineControl::get_buffer_sizes_for_all_devices ()
1387 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1388 ARDOUR::AudioEngine::instance ()->current_backend ();
1389 vector<uint32_t> all_sizes;
1391 if (backend->use_separate_input_and_output_devices ()) {
1392 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1394 all_sizes = backend->available_buffer_sizes (get_device_name ());
1400 EngineControl::get_default_buffer_sizes ()
1402 vector<uint32_t> sizes;
1403 sizes.push_back (8);
1404 sizes.push_back (16);
1405 sizes.push_back (32);
1406 sizes.push_back (64);
1407 sizes.push_back (128);
1408 sizes.push_back (256);
1409 sizes.push_back (512);
1410 sizes.push_back (1024);
1411 sizes.push_back (2048);
1412 sizes.push_back (4096);
1413 sizes.push_back (8192);
1418 EngineControl::set_buffersize_popdown_strings ()
1420 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1421 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1422 vector<uint32_t> bs;
1425 if (_have_control) {
1426 bs = get_buffer_sizes_for_all_devices ();
1427 } else if (backend->can_change_buffer_size_when_running()) {
1428 bs = get_default_buffer_sizes ();
1431 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1432 s.push_back (bufsize_as_string (*x));
1435 uint32_t previous_size = 0;
1436 if (!buffer_size_combo.get_active_text().empty()) {
1437 previous_size = get_buffer_size ();
1440 set_popdown_strings (buffer_size_combo, s);
1444 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1445 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1448 buffer_size_combo.set_active_text(s.front());
1450 uint32_t period = backend->buffer_size();
1451 if (0 == period && backend->use_separate_input_and_output_devices()) {
1452 period = backend->default_buffer_size(get_input_device_name());
1454 if (0 == period && backend->use_separate_input_and_output_devices()) {
1455 period = backend->default_buffer_size(get_output_device_name());
1457 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1458 period = backend->default_buffer_size(get_device_name());
1461 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1463 show_buffer_duration ();
1465 update_sensitivity ();
1469 EngineControl::set_nperiods_popdown_strings ()
1471 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1472 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1473 vector<uint32_t> np;
1476 if (backend->can_set_period_size()) {
1477 np = backend->available_period_sizes (get_driver());
1480 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1481 s.push_back (nperiods_as_string (*x));
1484 set_popdown_strings (nperiods_combo, s);
1487 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1490 update_sensitivity ();
1494 EngineControl::device_changed ()
1496 SignalBlocker blocker (*this, "device_changed");
1497 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1500 string device_name_in;
1501 string device_name_out; // only used if backend support separate I/O devices
1503 if (backend->use_separate_input_and_output_devices()) {
1504 device_name_in = get_input_device_name ();
1505 device_name_out = get_output_device_name ();
1507 device_name_in = get_device_name ();
1510 /* we set the backend-device to query various device related intormation.
1511 * This has the side effect that backend->device_name() will match
1512 * the device_name and 'change_device' will never be true.
1513 * so work around this by setting...
1515 if (backend->use_separate_input_and_output_devices()) {
1516 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1517 queue_device_changed = true;
1520 if (device_name_in != backend->device_name()) {
1521 queue_device_changed = true;
1525 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1526 if (backend->use_separate_input_and_output_devices()) {
1527 backend->set_input_device_name (device_name_in);
1528 backend->set_output_device_name (device_name_out);
1530 backend->set_device_name(device_name_in);
1534 /* don't allow programmatic change to combos to cause a
1535 recursive call to this method.
1537 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1539 set_samplerate_popdown_strings ();
1540 set_buffersize_popdown_strings ();
1541 set_nperiods_popdown_strings ();
1543 /* TODO set min + max channel counts here */
1545 manage_control_app_sensitivity ();
1548 /* pick up any saved state for this device */
1550 if (!ignore_changes) {
1551 maybe_display_saved_state ();
1556 EngineControl::input_device_changed ()
1558 DEBUG_ECONTROL ("input_device_changed");
1563 EngineControl::output_device_changed ()
1565 DEBUG_ECONTROL ("output_device_changed");
1570 EngineControl::bufsize_as_string (uint32_t sz)
1572 /* Translators: "samples" is always plural here, so no
1573 need for plural+singular forms.
1576 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1581 EngineControl::nperiods_as_string (uint32_t np)
1584 snprintf (buf, sizeof (buf), "%u", np);
1590 EngineControl::sample_rate_changed ()
1592 DEBUG_ECONTROL ("sample_rate_changed");
1593 /* reset the strings for buffer size to show the correct msec value
1594 (reflecting the new sample rate).
1597 show_buffer_duration ();
1602 EngineControl::buffer_size_changed ()
1604 DEBUG_ECONTROL ("buffer_size_changed");
1605 show_buffer_duration ();
1609 EngineControl::nperiods_changed ()
1611 DEBUG_ECONTROL ("nperiods_changed");
1612 show_buffer_duration ();
1616 EngineControl::show_buffer_duration ()
1618 DEBUG_ECONTROL ("show_buffer_duration");
1619 /* buffer sizes - convert from just samples to samples + msecs for
1620 * the displayed string
1623 string bs_text = buffer_size_combo.get_active_text ();
1624 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1625 uint32_t rate = get_rate();
1627 /* Except for ALSA and Dummy backends, we don't know the number of periods
1628 * per cycle and settings.
1630 * jack1 vs jack2 have different default latencies since jack2 start
1631 * in async-mode unless --sync is given which adds an extra cycle
1632 * of latency. The value is not known if jackd is started externally..
1634 * So just display the period size, that's also what
1635 * ARDOUR_UI::update_sample_rate() does for the status bar.
1636 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1637 * but still, that's the buffer period, not [round-trip] latency)
1640 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1641 buffer_size_duration_label.set_text (buf);
1645 EngineControl::midi_option_changed ()
1647 DEBUG_ECONTROL ("midi_option_changed");
1648 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1651 backend->set_midi_option (get_midi_option());
1653 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1655 //_midi_devices.clear(); // TODO merge with state-saved settings..
1656 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1657 std::vector<MidiDeviceSettings> new_devices;
1659 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1660 MidiDeviceSettings mds = find_midi_device (i->name);
1661 if (i->available && !mds) {
1662 uint32_t input_latency = 0;
1663 uint32_t output_latency = 0;
1664 if (_can_set_midi_latencies) {
1665 input_latency = backend->systemic_midi_input_latency (i->name);
1666 output_latency = backend->systemic_midi_output_latency (i->name);
1668 bool enabled = backend->midi_device_enabled (i->name);
1669 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1670 new_devices.push_back (ptr);
1671 } else if (i->available) {
1672 new_devices.push_back (mds);
1675 _midi_devices = new_devices;
1677 if (_midi_devices.empty()) {
1678 midi_devices_button.set_sensitive (false);
1680 midi_devices_button.set_sensitive (true);
1685 EngineControl::parameter_changed ()
1689 EngineControl::State
1690 EngineControl::get_matching_state (const string& backend)
1692 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1693 if ((*i)->backend == backend) {
1700 EngineControl::State
1701 EngineControl::get_matching_state (
1702 const string& backend,
1703 const string& driver,
1704 const string& device)
1706 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1707 if ((*i)->backend == backend &&
1708 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1716 EngineControl::State
1717 EngineControl::get_matching_state (
1718 const string& backend,
1719 const string& driver,
1720 const string& input_device,
1721 const string& output_device)
1723 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1724 if ((*i)->backend == backend &&
1725 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1733 EngineControl::State
1734 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1736 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1739 if (backend->use_separate_input_and_output_devices ()) {
1740 return get_matching_state (backend_combo.get_active_text(),
1741 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1742 input_device_combo.get_active_text(),
1743 output_device_combo.get_active_text());
1745 return get_matching_state (backend_combo.get_active_text(),
1746 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1747 device_combo.get_active_text());
1751 return get_matching_state (backend_combo.get_active_text(),
1753 device_combo.get_active_text());
1756 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1757 const EngineControl::State& state2)
1759 if (state1->backend == state2->backend &&
1760 state1->driver == state2->driver &&
1761 state1->device == state2->device &&
1762 state1->input_device == state2->input_device &&
1763 state1->output_device == state2->output_device) {
1770 EngineControl::state_sort_cmp (const State &a, const State &b) {
1774 else if (b->active) {
1778 return a->lru < b->lru;
1782 EngineControl::State
1783 EngineControl::save_state ()
1787 if (!_have_control) {
1788 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1790 state->lru = time (NULL) ;
1793 state.reset(new StateStruct);
1794 state->backend = get_backend ();
1796 state.reset(new StateStruct);
1797 store_state (state);
1800 for (StateList::iterator i = states.begin(); i != states.end();) {
1801 if (equivalent_states (*i, state)) {
1802 i = states.erase(i);
1808 states.push_back (state);
1810 states.sort (state_sort_cmp);
1816 EngineControl::store_state (State state)
1818 state->backend = get_backend ();
1819 state->driver = get_driver ();
1820 state->device = get_device_name ();
1821 state->input_device = get_input_device_name ();
1822 state->output_device = get_output_device_name ();
1823 state->sample_rate = get_rate ();
1824 state->buffer_size = get_buffer_size ();
1825 state->n_periods = get_nperiods ();
1826 state->input_latency = get_input_latency ();
1827 state->output_latency = get_output_latency ();
1828 state->input_channels = get_input_channels ();
1829 state->output_channels = get_output_channels ();
1830 state->midi_option = get_midi_option ();
1831 state->midi_devices = _midi_devices;
1832 state->lru = time (NULL) ;
1836 EngineControl::maybe_display_saved_state ()
1838 if (!_have_control) {
1842 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1845 DEBUG_ECONTROL ("Restoring saved state");
1846 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1848 if (!_desired_sample_rate) {
1849 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1851 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1853 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1854 /* call this explicitly because we're ignoring changes to
1855 the controls at this point.
1857 show_buffer_duration ();
1858 input_latency.set_value (state->input_latency);
1859 output_latency.set_value (state->output_latency);
1861 if (!state->midi_option.empty()) {
1862 midi_option_combo.set_active_text (state->midi_option);
1863 _midi_devices = state->midi_devices;
1866 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1871 EngineControl::get_state ()
1873 LocaleGuard lg (X_("C"));
1875 XMLNode* root = new XMLNode ("AudioMIDISetup");
1878 if (!states.empty()) {
1879 XMLNode* state_nodes = new XMLNode ("EngineStates");
1881 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1883 XMLNode* node = new XMLNode ("State");
1885 node->add_property ("backend", (*i)->backend);
1886 node->add_property ("driver", (*i)->driver);
1887 node->add_property ("device", (*i)->device);
1888 node->add_property ("input-device", (*i)->input_device);
1889 node->add_property ("output-device", (*i)->output_device);
1890 node->add_property ("sample-rate", (*i)->sample_rate);
1891 node->add_property ("buffer-size", (*i)->buffer_size);
1892 node->add_property ("n-periods", (*i)->n_periods);
1893 node->add_property ("input-latency", (*i)->input_latency);
1894 node->add_property ("output-latency", (*i)->output_latency);
1895 node->add_property ("input-channels", (*i)->input_channels);
1896 node->add_property ("output-channels", (*i)->output_channels);
1897 node->add_property ("active", (*i)->active ? "yes" : "no");
1898 node->add_property ("midi-option", (*i)->midi_option);
1899 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1901 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1902 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1903 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1904 midi_device_stuff->add_property (X_("name"), (*p)->name);
1905 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1906 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1907 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1908 midi_devices->add_child_nocopy (*midi_device_stuff);
1910 node->add_child_nocopy (*midi_devices);
1912 state_nodes->add_child_nocopy (*node);
1915 root->add_child_nocopy (*state_nodes);
1922 EngineControl::set_default_state ()
1924 vector<string> backend_names;
1925 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1927 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1928 backend_names.push_back ((*b)->name);
1930 backend_combo.set_active_text (backend_names.front());
1932 // We could set default backends per platform etc here
1938 EngineControl::set_state (const XMLNode& root)
1940 XMLNodeList clist, cclist;
1941 XMLNodeConstIterator citer, cciter;
1943 XMLNode* grandchild;
1944 XMLProperty* prop = NULL;
1946 fprintf (stderr, "EngineControl::set_state\n");
1948 if (root.name() != "AudioMIDISetup") {
1952 clist = root.children();
1956 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1960 if (child->name() != "EngineStates") {
1964 cclist = child->children();
1966 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1967 State state (new StateStruct);
1969 grandchild = *cciter;
1971 if (grandchild->name() != "State") {
1975 if ((prop = grandchild->property ("backend")) == 0) {
1978 state->backend = prop->value ();
1980 if ((prop = grandchild->property ("driver")) == 0) {
1983 state->driver = prop->value ();
1985 if ((prop = grandchild->property ("device")) == 0) {
1988 state->device = prop->value ();
1990 if ((prop = grandchild->property ("input-device")) == 0) {
1993 state->input_device = prop->value ();
1995 if ((prop = grandchild->property ("output-device")) == 0) {
1998 state->output_device = prop->value ();
2000 if ((prop = grandchild->property ("sample-rate")) == 0) {
2003 state->sample_rate = atof (prop->value ());
2005 if ((prop = grandchild->property ("buffer-size")) == 0) {
2008 state->buffer_size = atoi (prop->value ());
2010 if ((prop = grandchild->property ("n-periods")) == 0) {
2011 // optional (new value in 4.5)
2012 state->n_periods = 0;
2014 state->n_periods = atoi (prop->value ());
2017 if ((prop = grandchild->property ("input-latency")) == 0) {
2020 state->input_latency = atoi (prop->value ());
2022 if ((prop = grandchild->property ("output-latency")) == 0) {
2025 state->output_latency = atoi (prop->value ());
2027 if ((prop = grandchild->property ("input-channels")) == 0) {
2030 state->input_channels = atoi (prop->value ());
2032 if ((prop = grandchild->property ("output-channels")) == 0) {
2035 state->output_channels = atoi (prop->value ());
2037 if ((prop = grandchild->property ("active")) == 0) {
2040 state->active = string_is_affirmative (prop->value ());
2042 if ((prop = grandchild->property ("midi-option")) == 0) {
2045 state->midi_option = prop->value ();
2047 state->midi_devices.clear();
2049 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2050 const XMLNodeList mnc = midinode->children();
2051 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2052 if ((*n)->property (X_("name")) == 0
2053 || (*n)->property (X_("enabled")) == 0
2054 || (*n)->property (X_("input-latency")) == 0
2055 || (*n)->property (X_("output-latency")) == 0
2060 MidiDeviceSettings ptr (new MidiDeviceSetting(
2061 (*n)->property (X_("name"))->value (),
2062 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2063 atoi ((*n)->property (X_("input-latency"))->value ()),
2064 atoi ((*n)->property (X_("output-latency"))->value ())
2066 state->midi_devices.push_back (ptr);
2070 if ((prop = grandchild->property ("lru"))) {
2071 state->lru = atoi (prop->value ());
2075 /* remove accumulated duplicates (due to bug in ealier version)
2076 * this can be removed again before release
2078 for (StateList::iterator i = states.begin(); i != states.end();) {
2079 if ((*i)->backend == state->backend &&
2080 (*i)->driver == state->driver &&
2081 (*i)->device == state->device) {
2082 i = states.erase(i);
2089 states.push_back (state);
2093 /* now see if there was an active state and switch the setup to it */
2095 // purge states of backend that are not available in this built
2096 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2097 vector<std::string> backend_names;
2099 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2100 backend_names.push_back((*i)->name);
2102 for (StateList::iterator i = states.begin(); i != states.end();) {
2103 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2104 i = states.erase(i);
2110 states.sort (state_sort_cmp);
2112 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2115 return set_current_state (*i);
2122 EngineControl::set_current_state (const State& state)
2124 DEBUG_ECONTROL ("set_current_state");
2126 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2128 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2129 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2130 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2131 // this shouldn't happen as the invalid backend names should have been
2132 // removed from the list of states.
2136 // now reflect the change in the backend in the GUI so backend_changed will
2137 // do the right thing
2138 backend_combo.set_active_text (state->backend);
2140 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2142 // we don't have control don't restore state
2147 if (!state->driver.empty ()) {
2148 if (!backend->requires_driver_selection ()) {
2149 DEBUG_ECONTROL ("Backend should require driver selection");
2150 // A backend has changed from having driver selection to not having
2151 // it or someone has been manually editing a config file and messed
2156 if (backend->set_driver (state->driver) != 0) {
2157 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2158 // Driver names for a backend have changed and the name in the
2159 // config file is now invalid or support for driver is no longer
2160 // included in the backend
2163 // no need to set the driver_combo as backend_changed will use
2164 // backend->driver_name to set the active driver
2167 if (!state->device.empty ()) {
2168 if (backend->set_device_name (state->device) != 0) {
2170 string_compose ("Unable to set device name %1", state->device));
2171 // device is no longer available on the system
2174 // no need to set active device as it will be picked up in
2175 // via backend_changed ()/set_device_popdown_strings
2178 // backend supports separate input/output devices
2179 if (backend->set_input_device_name (state->input_device) != 0) {
2180 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2181 state->input_device));
2182 // input device is no longer available on the system
2186 if (backend->set_output_device_name (state->output_device) != 0) {
2187 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2188 state->input_device));
2189 // output device is no longer available on the system
2192 // no need to set active devices as it will be picked up in via
2193 // backend_changed ()/set_*_device_popdown_strings
2198 // Now restore the state of the rest of the controls
2200 // We don't use a SignalBlocker as set_current_state is currently only
2201 // called from set_state before any signals are connected. If at some point
2202 // a more general named state mechanism is implemented and
2203 // set_current_state is called while signals are connected then a
2204 // SignalBlocker will need to be instantiated before setting these.
2206 device_combo.set_active_text (state->device);
2207 input_device_combo.set_active_text (state->input_device);
2208 output_device_combo.set_active_text (state->output_device);
2209 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2210 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2211 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2212 input_latency.set_value (state->input_latency);
2213 output_latency.set_value (state->output_latency);
2214 midi_option_combo.set_active_text (state->midi_option);
2219 EngineControl::push_state_to_backend (bool start)
2221 DEBUG_ECONTROL ("push_state_to_backend");
2222 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2228 /* figure out what is going to change */
2230 bool restart_required = false;
2231 bool was_running = ARDOUR::AudioEngine::instance()->running();
2232 bool change_driver = false;
2233 bool change_device = false;
2234 bool change_rate = false;
2235 bool change_bufsize = false;
2236 bool change_nperiods = false;
2237 bool change_latency = false;
2238 bool change_channels = false;
2239 bool change_midi = false;
2241 uint32_t ochan = get_output_channels ();
2242 uint32_t ichan = get_input_channels ();
2244 if (_have_control) {
2246 if (started_at_least_once) {
2248 /* we can control the backend */
2250 if (backend->requires_driver_selection()) {
2251 if (get_driver() != backend->driver_name()) {
2252 change_driver = true;
2256 if (backend->use_separate_input_and_output_devices()) {
2257 if (get_input_device_name() != backend->input_device_name()) {
2258 change_device = true;
2260 if (get_output_device_name() != backend->output_device_name()) {
2261 change_device = true;
2264 if (get_device_name() != backend->device_name()) {
2265 change_device = true;
2269 if (queue_device_changed) {
2270 change_device = true;
2273 if (get_rate() != backend->sample_rate()) {
2277 if (get_buffer_size() != backend->buffer_size()) {
2278 change_bufsize = true;
2281 if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2282 && get_nperiods() != backend->period_size()) {
2283 change_nperiods = true;
2286 if (get_midi_option() != backend->midi_option()) {
2290 /* zero-requested channels means "all available" */
2293 ichan = backend->input_channels();
2297 ochan = backend->output_channels();
2300 if (ichan != backend->input_channels()) {
2301 change_channels = true;
2304 if (ochan != backend->output_channels()) {
2305 change_channels = true;
2308 if (get_input_latency() != backend->systemic_input_latency() ||
2309 get_output_latency() != backend->systemic_output_latency()) {
2310 change_latency = true;
2313 /* backend never started, so we have to force a group
2316 change_device = true;
2317 if (backend->requires_driver_selection()) {
2318 change_driver = true;
2321 change_bufsize = true;
2322 change_channels = true;
2323 change_latency = true;
2325 change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2330 /* we have no control over the backend, meaning that we can
2331 * only possibly change sample rate and buffer size.
2335 if (get_rate() != backend->sample_rate()) {
2336 change_bufsize = true;
2339 if (get_buffer_size() != backend->buffer_size()) {
2340 change_bufsize = true;
2344 queue_device_changed = false;
2346 if (!_have_control) {
2348 /* We do not have control over the backend, so the best we can
2349 * do is try to change the sample rate and/or bufsize and get
2353 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2357 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2362 backend->set_sample_rate (get_rate());
2365 if (change_bufsize) {
2366 backend->set_buffer_size (get_buffer_size());
2370 if (ARDOUR::AudioEngine::instance()->start ()) {
2371 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2381 /* determine if we need to stop the backend before changing parameters */
2383 if (change_driver || change_device || change_channels || change_nperiods ||
2384 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2385 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2387 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2388 restart_required = true;
2390 restart_required = false;
2395 if (restart_required) {
2396 if (ARDOUR::AudioEngine::instance()->stop()) {
2402 if (change_driver && backend->set_driver (get_driver())) {
2403 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2406 if (backend->use_separate_input_and_output_devices()) {
2407 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2408 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2411 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2412 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2416 if (change_device && backend->set_device_name (get_device_name())) {
2417 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2421 if (change_rate && backend->set_sample_rate (get_rate())) {
2422 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2425 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2426 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2429 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2430 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2434 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2435 if (backend->set_input_channels (get_input_channels())) {
2436 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2439 if (backend->set_output_channels (get_output_channels())) {
2440 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2444 if (change_latency) {
2445 if (backend->set_systemic_input_latency (get_input_latency())) {
2446 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2449 if (backend->set_systemic_output_latency (get_output_latency())) {
2450 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2456 backend->set_midi_option (get_midi_option());
2460 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2461 if (_measure_midi) {
2462 if (*p == _measure_midi) {
2463 backend->set_midi_device_enabled ((*p)->name, true);
2465 backend->set_midi_device_enabled ((*p)->name, false);
2467 if (backend->can_change_systemic_latency_when_running ()) {
2468 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2469 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2473 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2474 if (backend->can_set_systemic_midi_latencies()) {
2475 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2476 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2481 if (start || (was_running && restart_required)) {
2482 if (ARDOUR::AudioEngine::instance()->start()) {
2493 EngineControl::post_push ()
2495 /* get a pointer to the current state object, creating one if
2499 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2502 state = save_state ();
2508 states.sort (state_sort_cmp);
2512 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2513 (*i)->active = false;
2516 /* mark this one active (to be used next time the dialog is
2520 state->active = true;
2522 if (_have_control) { // XXX
2523 manage_control_app_sensitivity ();
2526 /* schedule a redisplay of MIDI ports */
2527 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2532 EngineControl::get_rate () const
2534 float r = atof (sample_rate_combo.get_active_text ());
2535 /* the string may have been translated with an abbreviation for
2536 * thousands, so use a crude heuristic to fix this.
2546 EngineControl::get_buffer_size () const
2548 string txt = buffer_size_combo.get_active_text ();
2551 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2552 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2553 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2561 EngineControl::get_nperiods () const
2563 string txt = nperiods_combo.get_active_text ();
2564 return atoi (txt.c_str());
2568 EngineControl::get_midi_option () const
2570 return midi_option_combo.get_active_text();
2574 EngineControl::get_input_channels() const
2576 if (ARDOUR::Profile->get_mixbus()) {
2577 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2578 if (!backend) return 0;
2579 return backend->input_channels();
2581 return (uint32_t) input_channels_adjustment.get_value();
2585 EngineControl::get_output_channels() const
2587 if (ARDOUR::Profile->get_mixbus()) {
2588 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2589 if (!backend) return 0;
2590 return backend->input_channels();
2592 return (uint32_t) output_channels_adjustment.get_value();
2596 EngineControl::get_input_latency() const
2598 return (uint32_t) input_latency_adjustment.get_value();
2602 EngineControl::get_output_latency() const
2604 return (uint32_t) output_latency_adjustment.get_value();
2608 EngineControl::get_backend () const
2610 return backend_combo.get_active_text ();
2614 EngineControl::get_driver () const
2616 if (driver_combo.get_parent()) {
2617 return driver_combo.get_active_text ();
2624 EngineControl::get_device_name () const
2626 return device_combo.get_active_text ();
2630 EngineControl::get_input_device_name () const
2632 return input_device_combo.get_active_text ();
2636 EngineControl::get_output_device_name () const
2638 return output_device_combo.get_active_text ();
2642 EngineControl::control_app_button_clicked ()
2644 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2650 backend->launch_control_app ();
2654 EngineControl::start_stop_button_clicked ()
2656 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2662 if (ARDOUR::AudioEngine::instance()->running()) {
2663 ARDOUR::AudioEngine::instance()->stop ();
2670 EngineControl::update_devices_button_clicked ()
2672 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2678 if (backend->update_devices()) {
2679 device_list_changed ();
2684 EngineControl::manage_control_app_sensitivity ()
2686 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2692 string appname = backend->control_app_name();
2694 if (appname.empty()) {
2695 control_app_button.set_sensitive (false);
2697 control_app_button.set_sensitive (true);
2702 EngineControl::set_desired_sample_rate (uint32_t sr)
2704 _desired_sample_rate = sr;
2709 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2711 if (page_num == 0) {
2712 cancel_button->set_sensitive (true);
2713 _measure_midi.reset();
2714 update_sensitivity ();
2716 cancel_button->set_sensitive (false);
2717 ok_button->set_sensitive (false);
2720 if (page_num == midi_tab) {
2722 refresh_midi_display ();
2725 if (page_num == latency_tab) {
2728 if (ARDOUR::AudioEngine::instance()->running()) {
2733 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2735 /* save any existing latency values */
2737 uint32_t il = (uint32_t) input_latency.get_value ();
2738 uint32_t ol = (uint32_t) input_latency.get_value ();
2740 /* reset to zero so that our new test instance
2741 will be clean of any existing latency measures.
2743 NB. this should really be done by the backend
2744 when stated for latency measurement.
2747 input_latency.set_value (0);
2748 output_latency.set_value (0);
2750 push_state_to_backend (false);
2754 input_latency.set_value (il);
2755 output_latency.set_value (ol);
2758 // This should be done in push_state_to_backend()
2759 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2760 disable_latency_tab ();
2763 enable_latency_tab ();
2767 end_latency_detection ();
2768 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2773 /* latency measurement */
2776 EngineControl::check_audio_latency_measurement ()
2778 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2780 if (mtdm->resolve () < 0) {
2781 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2785 if (mtdm->err () > 0.3) {
2791 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2793 if (sample_rate == 0) {
2794 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2795 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2799 int frames_total = mtdm->del();
2800 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2802 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2803 _("Detected roundtrip latency: "),
2804 frames_total, frames_total * 1000.0f/sample_rate,
2805 _("Systemic latency: "),
2806 extra, extra * 1000.0f/sample_rate);
2810 if (mtdm->err () > 0.2) {
2812 strcat (buf, _("(signal detection error)"));
2818 strcat (buf, _("(inverted - bad wiring)"));
2822 lm_results.set_markup (string_compose (results_markup, buf));
2825 have_lm_results = true;
2826 end_latency_detection ();
2827 lm_use_button.set_sensitive (true);
2835 EngineControl::check_midi_latency_measurement ()
2837 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2839 if (!mididm->have_signal () || mididm->latency () == 0) {
2840 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2845 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2847 if (sample_rate == 0) {
2848 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2849 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2853 ARDOUR::framecnt_t frames_total = mididm->latency();
2854 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2855 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2856 _("Detected roundtrip latency: "),
2857 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2858 _("Systemic latency: "),
2859 extra, extra * 1000.0f / sample_rate);
2863 if (!mididm->ok ()) {
2865 strcat (buf, _("(averaging)"));
2869 if (mididm->deviation () > 50.0) {
2871 strcat (buf, _("(too large jitter)"));
2873 } else if (mididm->deviation () > 10.0) {
2875 strcat (buf, _("(large jitter)"));
2879 have_lm_results = true;
2880 end_latency_detection ();
2881 lm_use_button.set_sensitive (true);
2882 lm_results.set_markup (string_compose (results_markup, buf));
2884 } else if (mididm->processed () > 400) {
2885 have_lm_results = false;
2886 end_latency_detection ();
2887 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2891 lm_results.set_markup (string_compose (results_markup, buf));
2897 EngineControl::start_latency_detection ()
2899 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2900 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2902 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2903 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2904 if (_measure_midi) {
2905 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2907 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2909 lm_measure_label.set_text (_("Cancel"));
2910 have_lm_results = false;
2911 lm_use_button.set_sensitive (false);
2912 lm_input_channel_combo.set_sensitive (false);
2913 lm_output_channel_combo.set_sensitive (false);
2919 EngineControl::end_latency_detection ()
2921 latency_timeout.disconnect ();
2922 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2923 lm_measure_label.set_text (_("Measure"));
2924 if (!have_lm_results) {
2925 lm_use_button.set_sensitive (false);
2927 lm_input_channel_combo.set_sensitive (true);
2928 lm_output_channel_combo.set_sensitive (true);
2933 EngineControl::latency_button_clicked ()
2936 start_latency_detection ();
2938 end_latency_detection ();
2943 EngineControl::latency_back_button_clicked ()
2945 ARDOUR::AudioEngine::instance()->stop(true);
2946 notebook.set_current_page(0);
2950 EngineControl::use_latency_button_clicked ()
2952 if (_measure_midi) {
2953 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2957 ARDOUR::framecnt_t frames_total = mididm->latency();
2958 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2959 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2960 _measure_midi->input_latency = one_way;
2961 _measure_midi->output_latency = one_way;
2962 notebook.set_current_page (midi_tab);
2964 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2970 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2971 one_way = std::max (0., one_way);
2973 input_latency_adjustment.set_value (one_way);
2974 output_latency_adjustment.set_value (one_way);
2976 /* back to settings page */
2977 notebook.set_current_page (0);
2982 EngineControl::on_delete_event (GdkEventAny* ev)
2984 if (notebook.get_current_page() == 2) {
2985 /* currently on latency tab - be sure to clean up */
2986 end_latency_detection ();
2988 return ArdourDialog::on_delete_event (ev);
2992 EngineControl::engine_running ()
2994 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2997 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2998 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3000 if (backend->can_set_period_size ()) {
3001 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3004 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3005 connect_disconnect_button.show();
3007 started_at_least_once = true;
3008 if (_have_control) {
3009 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3011 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3013 update_sensitivity();
3017 EngineControl::engine_stopped ()
3019 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3022 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3023 connect_disconnect_button.show();
3025 if (_have_control) {
3026 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3028 engine_status.set_markup(X_(""));
3031 update_sensitivity();
3035 EngineControl::device_list_changed ()
3037 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3039 midi_option_changed();
3043 EngineControl::connect_disconnect_click()
3045 if (ARDOUR::AudioEngine::instance()->running()) {
3053 EngineControl::calibrate_audio_latency ()
3055 _measure_midi.reset ();
3056 have_lm_results = false;
3057 lm_use_button.set_sensitive (false);
3058 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3059 notebook.set_current_page (latency_tab);
3063 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3066 have_lm_results = false;
3067 lm_use_button.set_sensitive (false);
3068 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3069 notebook.set_current_page (latency_tab);
3073 EngineControl::configure_midi_devices ()
3075 notebook.set_current_page (midi_tab);