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);
855 if (backend->can_set_period_size()) {
861 start_stop_button.set_sensitive(true);
862 start_stop_button.show();
863 if (ARDOUR::AudioEngine::instance()->running()) {
864 start_stop_button.set_text("Stop");
865 update_devices_button.set_sensitive(false);
867 if (backend->can_request_update_devices()) {
868 update_devices_button.show();
870 update_devices_button.hide();
872 start_stop_button.set_text("Start");
873 update_devices_button.set_sensitive(true);
876 update_devices_button.set_sensitive(false);
877 update_devices_button.hide();
878 start_stop_button.set_sensitive(false);
879 start_stop_button.hide();
882 if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
883 input_device_combo.set_sensitive (false);
884 output_device_combo.set_sensitive (false);
885 device_combo.set_sensitive (false);
886 driver_combo.set_sensitive (false);
888 input_device_combo.set_sensitive (true);
889 output_device_combo.set_sensitive (true);
890 device_combo.set_sensitive (true);
891 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
892 driver_combo.set_sensitive (true);
894 driver_combo.set_sensitive (false);
898 if (valid || !_have_control) {
899 ok_button->set_sensitive (true);
901 ok_button->set_sensitive (false);
906 EngineControl::setup_midi_tab_for_jack ()
911 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
913 device->input_latency = a->get_value();
915 device->output_latency = a->get_value();
920 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
921 b->set_active (!b->get_active());
922 device->enabled = b->get_active();
923 refresh_midi_display(device->name);
927 EngineControl::refresh_midi_display (std::string focus)
929 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
933 AttachOptions xopt = AttachOptions (FILL|EXPAND);
936 Gtkmm2ext::container_clear (midi_device_table);
938 midi_device_table.set_spacings (6);
940 l = manage (new Label);
941 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
942 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
943 l->set_alignment (0.5, 0.5);
947 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
948 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
949 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
950 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
952 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
953 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
954 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
955 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
958 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
963 bool enabled = (*p)->enabled;
965 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
966 m->set_name ("midi device");
967 m->set_can_focus (Gtk::CAN_FOCUS);
968 m->add_events (Gdk::BUTTON_RELEASE_MASK);
969 m->set_active (enabled);
970 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
971 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
972 if ((*p)->name == focus) {
976 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
977 s = manage (new Gtk::SpinButton (*a));
978 a->set_value ((*p)->input_latency);
979 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
980 s->set_sensitive (_can_set_midi_latencies && enabled);
981 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
983 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
984 s = manage (new Gtk::SpinButton (*a));
985 a->set_value ((*p)->output_latency);
986 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
987 s->set_sensitive (_can_set_midi_latencies && enabled);
988 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
990 b = manage (new Button (_("Calibrate")));
991 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
992 b->set_sensitive (_can_set_midi_latencies && enabled);
993 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1000 EngineControl::backend_changed ()
1002 SignalBlocker blocker (*this, "backend_changed");
1003 string backend_name = backend_combo.get_active_text();
1004 boost::shared_ptr<ARDOUR::AudioBackend> backend;
1006 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1007 /* eh? setting the backend failed... how ? */
1008 /* A: stale config contains a backend that does not exist in current build */
1012 DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1014 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1017 setup_midi_tab_for_backend ();
1018 _midi_devices.clear();
1020 if (backend->requires_driver_selection()) {
1021 if (set_driver_popdown_strings ()) {
1025 /* this will change the device text which will cause a call to
1026 * device changed which will set up parameters
1031 update_midi_options ();
1033 connect_disconnect_button.hide();
1035 midi_option_changed();
1037 started_at_least_once = false;
1039 /* changing the backend implies stopping the engine
1040 * ARDOUR::AudioEngine() may or may not emit this signal
1041 * depending on previous engine state
1043 engine_stopped (); // set "active/inactive"
1045 if (!_have_control) {
1046 // set settings from backend that we do have control over
1047 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1050 if (_have_control && !ignore_changes) {
1051 // set driver & devices
1052 State state = get_matching_state (backend_combo.get_active_text());
1054 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1055 set_current_state (state);
1059 if (!ignore_changes) {
1060 maybe_display_saved_state ();
1065 EngineControl::update_midi_options ()
1067 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1068 vector<string> midi_options = backend->enumerate_midi_options();
1070 if (midi_options.size() == 1) {
1071 /* only contains the "none" option */
1072 midi_option_combo.set_sensitive (false);
1074 if (_have_control) {
1075 set_popdown_strings (midi_option_combo, midi_options);
1076 midi_option_combo.set_active_text (midi_options.front());
1077 midi_option_combo.set_sensitive (true);
1079 midi_option_combo.set_sensitive (false);
1085 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1087 if (ARDOUR::Profile->get_mixbus()) {
1091 uint32_t cnt = (uint32_t) sb->get_value();
1093 sb->set_text (_("all available channels"));
1096 snprintf (buf, sizeof (buf), "%d", cnt);
1102 // @return true if there are drivers available
1104 EngineControl::set_driver_popdown_strings ()
1106 DEBUG_ECONTROL ("set_driver_popdown_strings");
1107 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1108 vector<string> drivers = backend->enumerate_drivers();
1110 if (drivers.empty ()) {
1111 // This is an error...?
1115 string current_driver = backend->driver_name ();
1117 DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1119 if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1122 current_driver = drivers.front ();
1125 set_popdown_strings (driver_combo, drivers);
1127 string_compose ("driver_combo.set_active_text: %1", current_driver));
1128 driver_combo.set_active_text (current_driver);
1133 EngineControl::get_default_device(const string& current_device_name,
1134 const vector<string>& available_devices)
1136 // If the current device is available, use it as default
1137 if (std::find (available_devices.begin (),
1138 available_devices.end (),
1139 current_device_name) != available_devices.end ()) {
1141 return current_device_name;
1144 using namespace ARDOUR;
1146 string default_device_name =
1147 AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1149 vector<string>::const_iterator i;
1151 // If there is a "Default" device available, use it
1152 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1153 if (*i == default_device_name) {
1158 string none_device_name =
1159 AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1161 // Use the first device that isn't "None"
1162 for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1163 if (*i != none_device_name) {
1168 // Use "None" if there are no other available
1169 return available_devices.front();
1172 // @return true if there are devices available
1174 EngineControl::set_device_popdown_strings ()
1176 DEBUG_ECONTROL ("set_device_popdown_strings");
1177 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1178 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1180 /* NOTE: Ardour currently does not display the "available" field of the
1183 * Doing so would require a different GUI widget than the combo
1184 * box/popdown that we currently use, since it has no way to list
1185 * items that are not selectable. Something more like a popup menu,
1186 * which could have unselectable items, would be appropriate.
1189 vector<string> available_devices;
1191 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1192 available_devices.push_back (i->name);
1195 if (available_devices.empty ()) {
1199 set_popdown_strings (device_combo, available_devices);
1201 std::string default_device =
1202 get_default_device(backend->device_name(), available_devices);
1205 string_compose ("set device_combo active text: %1", default_device));
1207 device_combo.set_active_text(default_device);
1211 // @return true if there are input devices available
1213 EngineControl::set_input_device_popdown_strings ()
1215 DEBUG_ECONTROL ("set_input_device_popdown_strings");
1216 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1217 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1219 vector<string> available_devices;
1221 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1222 available_devices.push_back (i->name);
1225 if (available_devices.empty()) {
1229 set_popdown_strings (input_device_combo, available_devices);
1231 std::string default_device =
1232 get_default_device(backend->input_device_name(), available_devices);
1235 string_compose ("set input_device_combo active text: %1", default_device));
1236 input_device_combo.set_active_text(default_device);
1240 // @return true if there are output devices available
1242 EngineControl::set_output_device_popdown_strings ()
1244 DEBUG_ECONTROL ("set_output_device_popdown_strings");
1245 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1246 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1248 vector<string> available_devices;
1250 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1251 available_devices.push_back (i->name);
1254 if (available_devices.empty()) {
1258 set_popdown_strings (output_device_combo, available_devices);
1260 std::string default_device =
1261 get_default_device(backend->output_device_name(), available_devices);
1264 string_compose ("set output_device_combo active text: %1", default_device));
1265 output_device_combo.set_active_text(default_device);
1270 EngineControl::list_devices ()
1272 DEBUG_ECONTROL ("list_devices");
1273 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1276 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1278 bool devices_available = false;
1280 if (backend->use_separate_input_and_output_devices ()) {
1281 bool input_devices_available = set_input_device_popdown_strings ();
1282 bool output_devices_available = set_output_device_popdown_strings ();
1283 devices_available = input_devices_available || output_devices_available;
1285 devices_available = set_device_popdown_strings ();
1288 if (devices_available) {
1291 device_combo.clear();
1292 input_device_combo.clear();
1293 output_device_combo.clear();
1295 update_sensitivity ();
1299 EngineControl::driver_changed ()
1301 SignalBlocker blocker (*this, "driver_changed");
1302 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1305 backend->set_driver (driver_combo.get_active_text());
1308 // TODO load LRU device(s) for backend + driver combo
1310 if (!ignore_changes) {
1311 maybe_display_saved_state ();
1316 EngineControl::get_sample_rates_for_all_devices ()
1318 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1319 ARDOUR::AudioEngine::instance ()->current_backend ();
1320 vector<float> all_rates;
1322 if (backend->use_separate_input_and_output_devices ()) {
1323 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1325 all_rates = backend->available_sample_rates (get_device_name ());
1331 EngineControl::get_default_sample_rates ()
1333 vector<float> rates;
1334 rates.push_back (8000.0f);
1335 rates.push_back (16000.0f);
1336 rates.push_back (32000.0f);
1337 rates.push_back (44100.0f);
1338 rates.push_back (48000.0f);
1339 rates.push_back (88200.0f);
1340 rates.push_back (96000.0f);
1341 rates.push_back (192000.0f);
1342 rates.push_back (384000.0f);
1347 EngineControl::set_samplerate_popdown_strings ()
1349 DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1350 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1355 if (_have_control) {
1356 sr = get_sample_rates_for_all_devices ();
1358 sr = get_default_sample_rates ();
1361 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1362 s.push_back (rate_as_string (*x));
1363 if (*x == _desired_sample_rate) {
1368 set_popdown_strings (sample_rate_combo, s);
1371 if (desired.empty ()) {
1372 float new_active_sr = backend->default_sample_rate ();
1374 if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1375 new_active_sr = sr.front ();
1378 sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1380 sample_rate_combo.set_active_text (desired);
1384 update_sensitivity ();
1388 EngineControl::get_buffer_sizes_for_all_devices ()
1390 boost::shared_ptr<ARDOUR::AudioBackend> backend =
1391 ARDOUR::AudioEngine::instance ()->current_backend ();
1392 vector<uint32_t> all_sizes;
1394 if (backend->use_separate_input_and_output_devices ()) {
1395 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1397 all_sizes = backend->available_buffer_sizes (get_device_name ());
1403 EngineControl::get_default_buffer_sizes ()
1405 vector<uint32_t> sizes;
1406 sizes.push_back (8);
1407 sizes.push_back (16);
1408 sizes.push_back (32);
1409 sizes.push_back (64);
1410 sizes.push_back (128);
1411 sizes.push_back (256);
1412 sizes.push_back (512);
1413 sizes.push_back (1024);
1414 sizes.push_back (2048);
1415 sizes.push_back (4096);
1416 sizes.push_back (8192);
1421 EngineControl::set_buffersize_popdown_strings ()
1423 DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1424 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1425 vector<uint32_t> bs;
1428 if (_have_control) {
1429 bs = get_buffer_sizes_for_all_devices ();
1430 } else if (backend->can_change_buffer_size_when_running()) {
1431 bs = get_default_buffer_sizes ();
1434 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1435 s.push_back (bufsize_as_string (*x));
1438 uint32_t previous_size = 0;
1439 if (!buffer_size_combo.get_active_text().empty()) {
1440 previous_size = get_buffer_size ();
1443 set_popdown_strings (buffer_size_combo, s);
1447 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1448 buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1451 buffer_size_combo.set_active_text(s.front());
1453 uint32_t period = backend->buffer_size();
1454 if (0 == period && backend->use_separate_input_and_output_devices()) {
1455 period = backend->default_buffer_size(get_input_device_name());
1457 if (0 == period && backend->use_separate_input_and_output_devices()) {
1458 period = backend->default_buffer_size(get_output_device_name());
1460 if (0 == period && !backend->use_separate_input_and_output_devices()) {
1461 period = backend->default_buffer_size(get_device_name());
1464 set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1466 show_buffer_duration ();
1468 update_sensitivity ();
1472 EngineControl::set_nperiods_popdown_strings ()
1474 DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1475 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1476 vector<uint32_t> np;
1479 if (backend->can_set_period_size()) {
1480 np = backend->available_period_sizes (get_driver());
1483 for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1484 s.push_back (nperiods_as_string (*x));
1487 set_popdown_strings (nperiods_combo, s);
1490 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1493 update_sensitivity ();
1497 EngineControl::device_changed ()
1499 SignalBlocker blocker (*this, "device_changed");
1500 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1503 string device_name_in;
1504 string device_name_out; // only used if backend support separate I/O devices
1506 if (backend->use_separate_input_and_output_devices()) {
1507 device_name_in = get_input_device_name ();
1508 device_name_out = get_output_device_name ();
1510 device_name_in = get_device_name ();
1513 /* we set the backend-device to query various device related intormation.
1514 * This has the side effect that backend->device_name() will match
1515 * the device_name and 'change_device' will never be true.
1516 * so work around this by setting...
1518 if (backend->use_separate_input_and_output_devices()) {
1519 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1520 queue_device_changed = true;
1523 if (device_name_in != backend->device_name()) {
1524 queue_device_changed = true;
1528 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1529 if (backend->use_separate_input_and_output_devices()) {
1530 backend->set_input_device_name (device_name_in);
1531 backend->set_output_device_name (device_name_out);
1533 backend->set_device_name(device_name_in);
1537 /* don't allow programmatic change to combos to cause a
1538 recursive call to this method.
1540 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1542 set_samplerate_popdown_strings ();
1543 set_buffersize_popdown_strings ();
1544 set_nperiods_popdown_strings ();
1546 /* TODO set min + max channel counts here */
1548 manage_control_app_sensitivity ();
1551 /* pick up any saved state for this device */
1553 if (!ignore_changes) {
1554 maybe_display_saved_state ();
1559 EngineControl::input_device_changed ()
1561 DEBUG_ECONTROL ("input_device_changed");
1566 EngineControl::output_device_changed ()
1568 DEBUG_ECONTROL ("output_device_changed");
1573 EngineControl::bufsize_as_string (uint32_t sz)
1575 /* Translators: "samples" is always plural here, so no
1576 need for plural+singular forms.
1579 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1584 EngineControl::nperiods_as_string (uint32_t np)
1587 snprintf (buf, sizeof (buf), "%u", np);
1593 EngineControl::sample_rate_changed ()
1595 DEBUG_ECONTROL ("sample_rate_changed");
1596 /* reset the strings for buffer size to show the correct msec value
1597 (reflecting the new sample rate).
1600 show_buffer_duration ();
1605 EngineControl::buffer_size_changed ()
1607 DEBUG_ECONTROL ("buffer_size_changed");
1608 show_buffer_duration ();
1612 EngineControl::nperiods_changed ()
1614 DEBUG_ECONTROL ("nperiods_changed");
1615 show_buffer_duration ();
1619 EngineControl::show_buffer_duration ()
1621 DEBUG_ECONTROL ("show_buffer_duration");
1622 /* buffer sizes - convert from just samples to samples + msecs for
1623 * the displayed string
1626 string bs_text = buffer_size_combo.get_active_text ();
1627 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1628 uint32_t rate = get_rate();
1630 /* Except for ALSA and Dummy backends, we don't know the number of periods
1631 * per cycle and settings.
1633 * jack1 vs jack2 have different default latencies since jack2 start
1634 * in async-mode unless --sync is given which adds an extra cycle
1635 * of latency. The value is not known if jackd is started externally..
1637 * So just display the period size, that's also what
1638 * ARDOUR_UI::update_sample_rate() does for the status bar.
1639 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1640 * but still, that's the buffer period, not [round-trip] latency)
1643 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1644 buffer_size_duration_label.set_text (buf);
1648 EngineControl::midi_option_changed ()
1650 DEBUG_ECONTROL ("midi_option_changed");
1651 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1654 backend->set_midi_option (get_midi_option());
1656 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1658 //_midi_devices.clear(); // TODO merge with state-saved settings..
1659 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1660 std::vector<MidiDeviceSettings> new_devices;
1662 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1663 MidiDeviceSettings mds = find_midi_device (i->name);
1664 if (i->available && !mds) {
1665 uint32_t input_latency = 0;
1666 uint32_t output_latency = 0;
1667 if (_can_set_midi_latencies) {
1668 input_latency = backend->systemic_midi_input_latency (i->name);
1669 output_latency = backend->systemic_midi_output_latency (i->name);
1671 bool enabled = backend->midi_device_enabled (i->name);
1672 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1673 new_devices.push_back (ptr);
1674 } else if (i->available) {
1675 new_devices.push_back (mds);
1678 _midi_devices = new_devices;
1680 if (_midi_devices.empty()) {
1681 midi_devices_button.set_sensitive (false);
1683 midi_devices_button.set_sensitive (true);
1688 EngineControl::parameter_changed ()
1692 EngineControl::State
1693 EngineControl::get_matching_state (const string& backend)
1695 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1696 if ((*i)->backend == backend) {
1703 EngineControl::State
1704 EngineControl::get_matching_state (
1705 const string& backend,
1706 const string& driver,
1707 const string& device)
1709 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1710 if ((*i)->backend == backend &&
1711 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1719 EngineControl::State
1720 EngineControl::get_matching_state (
1721 const string& backend,
1722 const string& driver,
1723 const string& input_device,
1724 const string& output_device)
1726 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1727 if ((*i)->backend == backend &&
1728 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1736 EngineControl::State
1737 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1739 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1742 if (backend->use_separate_input_and_output_devices ()) {
1743 return get_matching_state (backend_combo.get_active_text(),
1744 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1745 input_device_combo.get_active_text(),
1746 output_device_combo.get_active_text());
1748 return get_matching_state (backend_combo.get_active_text(),
1749 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1750 device_combo.get_active_text());
1754 return get_matching_state (backend_combo.get_active_text(),
1756 device_combo.get_active_text());
1759 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1760 const EngineControl::State& state2)
1762 if (state1->backend == state2->backend &&
1763 state1->driver == state2->driver &&
1764 state1->device == state2->device &&
1765 state1->input_device == state2->input_device &&
1766 state1->output_device == state2->output_device) {
1773 EngineControl::state_sort_cmp (const State &a, const State &b) {
1777 else if (b->active) {
1781 return a->lru < b->lru;
1785 EngineControl::State
1786 EngineControl::save_state ()
1790 if (!_have_control) {
1791 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1793 state->lru = time (NULL) ;
1796 state.reset(new StateStruct);
1797 state->backend = get_backend ();
1799 state.reset(new StateStruct);
1800 store_state (state);
1803 for (StateList::iterator i = states.begin(); i != states.end();) {
1804 if (equivalent_states (*i, state)) {
1805 i = states.erase(i);
1811 states.push_back (state);
1813 states.sort (state_sort_cmp);
1819 EngineControl::store_state (State state)
1821 state->backend = get_backend ();
1822 state->driver = get_driver ();
1823 state->device = get_device_name ();
1824 state->input_device = get_input_device_name ();
1825 state->output_device = get_output_device_name ();
1826 state->sample_rate = get_rate ();
1827 state->buffer_size = get_buffer_size ();
1828 state->n_periods = get_nperiods ();
1829 state->input_latency = get_input_latency ();
1830 state->output_latency = get_output_latency ();
1831 state->input_channels = get_input_channels ();
1832 state->output_channels = get_output_channels ();
1833 state->midi_option = get_midi_option ();
1834 state->midi_devices = _midi_devices;
1835 state->lru = time (NULL) ;
1839 EngineControl::maybe_display_saved_state ()
1841 if (!_have_control) {
1845 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1848 DEBUG_ECONTROL ("Restoring saved state");
1849 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1851 if (!_desired_sample_rate) {
1852 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1854 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1856 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1857 /* call this explicitly because we're ignoring changes to
1858 the controls at this point.
1860 show_buffer_duration ();
1861 input_latency.set_value (state->input_latency);
1862 output_latency.set_value (state->output_latency);
1864 if (!state->midi_option.empty()) {
1865 midi_option_combo.set_active_text (state->midi_option);
1866 _midi_devices = state->midi_devices;
1869 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1874 EngineControl::get_state ()
1876 LocaleGuard lg (X_("C"));
1878 XMLNode* root = new XMLNode ("AudioMIDISetup");
1881 if (!states.empty()) {
1882 XMLNode* state_nodes = new XMLNode ("EngineStates");
1884 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1886 XMLNode* node = new XMLNode ("State");
1888 node->add_property ("backend", (*i)->backend);
1889 node->add_property ("driver", (*i)->driver);
1890 node->add_property ("device", (*i)->device);
1891 node->add_property ("input-device", (*i)->input_device);
1892 node->add_property ("output-device", (*i)->output_device);
1893 node->add_property ("sample-rate", (*i)->sample_rate);
1894 node->add_property ("buffer-size", (*i)->buffer_size);
1895 node->add_property ("n-periods", (*i)->n_periods);
1896 node->add_property ("input-latency", (*i)->input_latency);
1897 node->add_property ("output-latency", (*i)->output_latency);
1898 node->add_property ("input-channels", (*i)->input_channels);
1899 node->add_property ("output-channels", (*i)->output_channels);
1900 node->add_property ("active", (*i)->active ? "yes" : "no");
1901 node->add_property ("midi-option", (*i)->midi_option);
1902 node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1904 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1905 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1906 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1907 midi_device_stuff->add_property (X_("name"), (*p)->name);
1908 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1909 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1910 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1911 midi_devices->add_child_nocopy (*midi_device_stuff);
1913 node->add_child_nocopy (*midi_devices);
1915 state_nodes->add_child_nocopy (*node);
1918 root->add_child_nocopy (*state_nodes);
1925 EngineControl::set_default_state ()
1927 vector<string> backend_names;
1928 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1930 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
1931 backend_names.push_back ((*b)->name);
1933 backend_combo.set_active_text (backend_names.front());
1935 // We could set default backends per platform etc here
1941 EngineControl::set_state (const XMLNode& root)
1943 XMLNodeList clist, cclist;
1944 XMLNodeConstIterator citer, cciter;
1946 XMLNode* grandchild;
1947 XMLProperty* prop = NULL;
1949 fprintf (stderr, "EngineControl::set_state\n");
1951 if (root.name() != "AudioMIDISetup") {
1955 clist = root.children();
1959 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1963 if (child->name() != "EngineStates") {
1967 cclist = child->children();
1969 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1970 State state (new StateStruct);
1972 grandchild = *cciter;
1974 if (grandchild->name() != "State") {
1978 if ((prop = grandchild->property ("backend")) == 0) {
1981 state->backend = prop->value ();
1983 if ((prop = grandchild->property ("driver")) == 0) {
1986 state->driver = prop->value ();
1988 if ((prop = grandchild->property ("device")) == 0) {
1991 state->device = prop->value ();
1993 if ((prop = grandchild->property ("input-device")) == 0) {
1996 state->input_device = prop->value ();
1998 if ((prop = grandchild->property ("output-device")) == 0) {
2001 state->output_device = prop->value ();
2003 if ((prop = grandchild->property ("sample-rate")) == 0) {
2006 state->sample_rate = atof (prop->value ());
2008 if ((prop = grandchild->property ("buffer-size")) == 0) {
2011 state->buffer_size = atoi (prop->value ());
2013 if ((prop = grandchild->property ("n-periods")) == 0) {
2014 // optional (new value in 4.5)
2015 state->n_periods = 0;
2017 state->n_periods = atoi (prop->value ());
2020 if ((prop = grandchild->property ("input-latency")) == 0) {
2023 state->input_latency = atoi (prop->value ());
2025 if ((prop = grandchild->property ("output-latency")) == 0) {
2028 state->output_latency = atoi (prop->value ());
2030 if ((prop = grandchild->property ("input-channels")) == 0) {
2033 state->input_channels = atoi (prop->value ());
2035 if ((prop = grandchild->property ("output-channels")) == 0) {
2038 state->output_channels = atoi (prop->value ());
2040 if ((prop = grandchild->property ("active")) == 0) {
2043 state->active = string_is_affirmative (prop->value ());
2045 if ((prop = grandchild->property ("midi-option")) == 0) {
2048 state->midi_option = prop->value ();
2050 state->midi_devices.clear();
2052 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2053 const XMLNodeList mnc = midinode->children();
2054 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2055 if ((*n)->property (X_("name")) == 0
2056 || (*n)->property (X_("enabled")) == 0
2057 || (*n)->property (X_("input-latency")) == 0
2058 || (*n)->property (X_("output-latency")) == 0
2063 MidiDeviceSettings ptr (new MidiDeviceSetting(
2064 (*n)->property (X_("name"))->value (),
2065 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2066 atoi ((*n)->property (X_("input-latency"))->value ()),
2067 atoi ((*n)->property (X_("output-latency"))->value ())
2069 state->midi_devices.push_back (ptr);
2073 if ((prop = grandchild->property ("lru"))) {
2074 state->lru = atoi (prop->value ());
2078 /* remove accumulated duplicates (due to bug in ealier version)
2079 * this can be removed again before release
2081 for (StateList::iterator i = states.begin(); i != states.end();) {
2082 if ((*i)->backend == state->backend &&
2083 (*i)->driver == state->driver &&
2084 (*i)->device == state->device) {
2085 i = states.erase(i);
2092 states.push_back (state);
2096 /* now see if there was an active state and switch the setup to it */
2098 // purge states of backend that are not available in this built
2099 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2100 vector<std::string> backend_names;
2102 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2103 backend_names.push_back((*i)->name);
2105 for (StateList::iterator i = states.begin(); i != states.end();) {
2106 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2107 i = states.erase(i);
2113 states.sort (state_sort_cmp);
2115 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2118 return set_current_state (*i);
2125 EngineControl::set_current_state (const State& state)
2127 DEBUG_ECONTROL ("set_current_state");
2129 boost::shared_ptr<ARDOUR::AudioBackend> backend;
2131 if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2132 state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2133 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2134 // this shouldn't happen as the invalid backend names should have been
2135 // removed from the list of states.
2139 // now reflect the change in the backend in the GUI so backend_changed will
2140 // do the right thing
2141 backend_combo.set_active_text (state->backend);
2143 if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2145 // we don't have control don't restore state
2150 if (!state->driver.empty ()) {
2151 if (!backend->requires_driver_selection ()) {
2152 DEBUG_ECONTROL ("Backend should require driver selection");
2153 // A backend has changed from having driver selection to not having
2154 // it or someone has been manually editing a config file and messed
2159 if (backend->set_driver (state->driver) != 0) {
2160 DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2161 // Driver names for a backend have changed and the name in the
2162 // config file is now invalid or support for driver is no longer
2163 // included in the backend
2166 // no need to set the driver_combo as backend_changed will use
2167 // backend->driver_name to set the active driver
2170 if (!state->device.empty ()) {
2171 if (backend->set_device_name (state->device) != 0) {
2173 string_compose ("Unable to set device name %1", state->device));
2174 // device is no longer available on the system
2177 // no need to set active device as it will be picked up in
2178 // via backend_changed ()/set_device_popdown_strings
2181 // backend supports separate input/output devices
2182 if (backend->set_input_device_name (state->input_device) != 0) {
2183 DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2184 state->input_device));
2185 // input device is no longer available on the system
2189 if (backend->set_output_device_name (state->output_device) != 0) {
2190 DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2191 state->input_device));
2192 // output device is no longer available on the system
2195 // no need to set active devices as it will be picked up in via
2196 // backend_changed ()/set_*_device_popdown_strings
2201 // Now restore the state of the rest of the controls
2203 // We don't use a SignalBlocker as set_current_state is currently only
2204 // called from set_state before any signals are connected. If at some point
2205 // a more general named state mechanism is implemented and
2206 // set_current_state is called while signals are connected then a
2207 // SignalBlocker will need to be instantiated before setting these.
2209 device_combo.set_active_text (state->device);
2210 input_device_combo.set_active_text (state->input_device);
2211 output_device_combo.set_active_text (state->output_device);
2212 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2213 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2214 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2215 input_latency.set_value (state->input_latency);
2216 output_latency.set_value (state->output_latency);
2217 midi_option_combo.set_active_text (state->midi_option);
2222 EngineControl::push_state_to_backend (bool start)
2224 DEBUG_ECONTROL ("push_state_to_backend");
2225 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2231 /* figure out what is going to change */
2233 bool restart_required = false;
2234 bool was_running = ARDOUR::AudioEngine::instance()->running();
2235 bool change_driver = false;
2236 bool change_device = false;
2237 bool change_rate = false;
2238 bool change_bufsize = false;
2239 bool change_nperiods = false;
2240 bool change_latency = false;
2241 bool change_channels = false;
2242 bool change_midi = false;
2244 uint32_t ochan = get_output_channels ();
2245 uint32_t ichan = get_input_channels ();
2247 if (_have_control) {
2249 if (started_at_least_once) {
2251 /* we can control the backend */
2253 if (backend->requires_driver_selection()) {
2254 if (get_driver() != backend->driver_name()) {
2255 change_driver = true;
2259 if (backend->use_separate_input_and_output_devices()) {
2260 if (get_input_device_name() != backend->input_device_name()) {
2261 change_device = true;
2263 if (get_output_device_name() != backend->output_device_name()) {
2264 change_device = true;
2267 if (get_device_name() != backend->device_name()) {
2268 change_device = true;
2272 if (queue_device_changed) {
2273 change_device = true;
2276 if (get_rate() != backend->sample_rate()) {
2280 if (get_buffer_size() != backend->buffer_size()) {
2281 change_bufsize = true;
2284 if (backend->can_set_period_size() && get_nperiods() != backend->period_size()) {
2285 change_nperiods = true;
2288 if (get_midi_option() != backend->midi_option()) {
2292 /* zero-requested channels means "all available" */
2295 ichan = backend->input_channels();
2299 ochan = backend->output_channels();
2302 if (ichan != backend->input_channels()) {
2303 change_channels = true;
2306 if (ochan != backend->output_channels()) {
2307 change_channels = true;
2310 if (get_input_latency() != backend->systemic_input_latency() ||
2311 get_output_latency() != backend->systemic_output_latency()) {
2312 change_latency = true;
2315 /* backend never started, so we have to force a group
2318 change_device = true;
2319 if (backend->requires_driver_selection()) {
2320 change_driver = true;
2323 change_bufsize = true;
2324 change_channels = true;
2325 change_latency = true;
2327 change_nperiods = backend->can_set_period_size();
2332 /* we have no control over the backend, meaning that we can
2333 * only possibly change sample rate and buffer size.
2337 if (get_rate() != backend->sample_rate()) {
2338 change_bufsize = true;
2341 if (get_buffer_size() != backend->buffer_size()) {
2342 change_bufsize = true;
2346 queue_device_changed = false;
2348 if (!_have_control) {
2350 /* We do not have control over the backend, so the best we can
2351 * do is try to change the sample rate and/or bufsize and get
2355 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2359 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2364 backend->set_sample_rate (get_rate());
2367 if (change_bufsize) {
2368 backend->set_buffer_size (get_buffer_size());
2372 if (ARDOUR::AudioEngine::instance()->start ()) {
2373 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2383 /* determine if we need to stop the backend before changing parameters */
2385 if (change_driver || change_device || change_channels || change_nperiods ||
2386 (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2387 (change_rate && !backend->can_change_sample_rate_when_running()) ||
2389 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2390 restart_required = true;
2392 restart_required = false;
2397 if (restart_required) {
2398 if (ARDOUR::AudioEngine::instance()->stop()) {
2404 if (change_driver && backend->set_driver (get_driver())) {
2405 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2408 if (backend->use_separate_input_and_output_devices()) {
2409 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2410 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2413 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2414 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2418 if (change_device && backend->set_device_name (get_device_name())) {
2419 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2423 if (change_rate && backend->set_sample_rate (get_rate())) {
2424 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2427 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2428 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2431 if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2432 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2436 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2437 if (backend->set_input_channels (get_input_channels())) {
2438 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2441 if (backend->set_output_channels (get_output_channels())) {
2442 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2446 if (change_latency) {
2447 if (backend->set_systemic_input_latency (get_input_latency())) {
2448 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2451 if (backend->set_systemic_output_latency (get_output_latency())) {
2452 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2458 backend->set_midi_option (get_midi_option());
2462 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2463 if (_measure_midi) {
2464 if (*p == _measure_midi) {
2465 backend->set_midi_device_enabled ((*p)->name, true);
2467 backend->set_midi_device_enabled ((*p)->name, false);
2469 if (backend->can_change_systemic_latency_when_running ()) {
2470 backend->set_systemic_midi_input_latency ((*p)->name, 0);
2471 backend->set_systemic_midi_output_latency ((*p)->name, 0);
2475 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2476 if (backend->can_set_systemic_midi_latencies()) {
2477 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2478 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2483 if (start || (was_running && restart_required)) {
2484 if (ARDOUR::AudioEngine::instance()->start()) {
2495 EngineControl::post_push ()
2497 /* get a pointer to the current state object, creating one if
2501 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2504 state = save_state ();
2510 states.sort (state_sort_cmp);
2514 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2515 (*i)->active = false;
2518 /* mark this one active (to be used next time the dialog is
2522 state->active = true;
2524 if (_have_control) { // XXX
2525 manage_control_app_sensitivity ();
2528 /* schedule a redisplay of MIDI ports */
2529 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2534 EngineControl::get_rate () const
2536 float r = atof (sample_rate_combo.get_active_text ());
2537 /* the string may have been translated with an abbreviation for
2538 * thousands, so use a crude heuristic to fix this.
2548 EngineControl::get_buffer_size () const
2550 string txt = buffer_size_combo.get_active_text ();
2553 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2554 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2555 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2563 EngineControl::get_nperiods () const
2565 string txt = nperiods_combo.get_active_text ();
2566 return atoi (txt.c_str());
2570 EngineControl::get_midi_option () const
2572 return midi_option_combo.get_active_text();
2576 EngineControl::get_input_channels() const
2578 if (ARDOUR::Profile->get_mixbus()) {
2579 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2580 if (!backend) return 0;
2581 return backend->input_channels();
2583 return (uint32_t) input_channels_adjustment.get_value();
2587 EngineControl::get_output_channels() const
2589 if (ARDOUR::Profile->get_mixbus()) {
2590 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2591 if (!backend) return 0;
2592 return backend->input_channels();
2594 return (uint32_t) output_channels_adjustment.get_value();
2598 EngineControl::get_input_latency() const
2600 return (uint32_t) input_latency_adjustment.get_value();
2604 EngineControl::get_output_latency() const
2606 return (uint32_t) output_latency_adjustment.get_value();
2610 EngineControl::get_backend () const
2612 return backend_combo.get_active_text ();
2616 EngineControl::get_driver () const
2618 if (driver_combo.get_parent()) {
2619 return driver_combo.get_active_text ();
2626 EngineControl::get_device_name () const
2628 return device_combo.get_active_text ();
2632 EngineControl::get_input_device_name () const
2634 return input_device_combo.get_active_text ();
2638 EngineControl::get_output_device_name () const
2640 return output_device_combo.get_active_text ();
2644 EngineControl::control_app_button_clicked ()
2646 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2652 backend->launch_control_app ();
2656 EngineControl::start_stop_button_clicked ()
2658 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2664 if (ARDOUR::AudioEngine::instance()->running()) {
2665 ARDOUR::AudioEngine::instance()->stop ();
2672 EngineControl::update_devices_button_clicked ()
2674 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2680 if (backend->update_devices()) {
2681 device_list_changed ();
2686 EngineControl::manage_control_app_sensitivity ()
2688 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2694 string appname = backend->control_app_name();
2696 if (appname.empty()) {
2697 control_app_button.set_sensitive (false);
2699 control_app_button.set_sensitive (true);
2704 EngineControl::set_desired_sample_rate (uint32_t sr)
2706 _desired_sample_rate = sr;
2711 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2713 if (page_num == 0) {
2714 cancel_button->set_sensitive (true);
2715 _measure_midi.reset();
2716 update_sensitivity ();
2718 cancel_button->set_sensitive (false);
2719 ok_button->set_sensitive (false);
2722 if (page_num == midi_tab) {
2724 refresh_midi_display ();
2727 if (page_num == latency_tab) {
2730 if (ARDOUR::AudioEngine::instance()->running()) {
2735 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2737 /* save any existing latency values */
2739 uint32_t il = (uint32_t) input_latency.get_value ();
2740 uint32_t ol = (uint32_t) input_latency.get_value ();
2742 /* reset to zero so that our new test instance
2743 will be clean of any existing latency measures.
2745 NB. this should really be done by the backend
2746 when stated for latency measurement.
2749 input_latency.set_value (0);
2750 output_latency.set_value (0);
2752 push_state_to_backend (false);
2756 input_latency.set_value (il);
2757 output_latency.set_value (ol);
2760 // This should be done in push_state_to_backend()
2761 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2762 disable_latency_tab ();
2765 enable_latency_tab ();
2769 end_latency_detection ();
2770 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2775 /* latency measurement */
2778 EngineControl::check_audio_latency_measurement ()
2780 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2782 if (mtdm->resolve () < 0) {
2783 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
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 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3041 midi_option_changed();
3045 EngineControl::connect_disconnect_click()
3047 if (ARDOUR::AudioEngine::instance()->running()) {
3055 EngineControl::calibrate_audio_latency ()
3057 _measure_midi.reset ();
3058 have_lm_results = false;
3059 lm_use_button.set_sensitive (false);
3060 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3061 notebook.set_current_page (latency_tab);
3065 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3068 have_lm_results = false;
3069 lm_use_button.set_sensitive (false);
3070 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3071 notebook.set_current_page (latency_tab);
3075 EngineControl::configure_midi_devices ()
3077 notebook.set_current_page (midi_tab);