2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
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 static const unsigned int midi_tab = 2;
66 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
68 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
70 EngineControl::EngineControl ()
71 : ArdourDialog (_("Audio/MIDI Setup"))
74 , input_latency_adjustment (0, 0, 99999, 1)
75 , input_latency (input_latency_adjustment)
76 , output_latency_adjustment (0, 0, 99999, 1)
77 , output_latency (output_latency_adjustment)
78 , input_channels_adjustment (0, 0, 256, 1)
79 , input_channels (input_channels_adjustment)
80 , output_channels_adjustment (0, 0, 256, 1)
81 , output_channels (output_channels_adjustment)
82 , ports_adjustment (128, 8, 1024, 1, 16)
83 , ports_spinner (ports_adjustment)
84 , control_app_button (_("Device Control Panel"))
85 , midi_devices_button (_("Midi Device Setup"))
86 , lm_measure_label (_("Measure"))
87 , lm_use_button (_("Use results"))
88 , lm_back_button (_("Back to settings ... (ignore results)"))
89 , lm_button_audio (_("Calibrate Audio"))
91 , have_lm_results (false)
93 , midi_back_button (_("Back to settings"))
95 , _desired_sample_rate (0)
96 , started_at_least_once (false)
97 , queue_device_changed (false)
99 using namespace Notebook_Helpers;
100 vector<string> backend_names;
102 AttachOptions xopt = AttachOptions (FILL|EXPAND);
105 set_name (X_("AudioMIDISetup"));
107 /* the backend combo is the one thing that is ALWAYS visible */
109 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
111 if (backends.empty()) {
112 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));
114 throw failed_constructor ();
117 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
118 backend_names.push_back ((*b)->name);
121 set_popdown_strings (backend_combo, backend_names);
122 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
124 /* setup basic packing characteristics for the table used on the main
125 * tab of the notebook
128 basic_packer.set_spacings (6);
129 basic_packer.set_border_width (12);
130 basic_packer.set_homogeneous (false);
134 basic_hbox.pack_start (basic_packer, false, false);
136 /* latency measurement tab */
138 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
141 lm_table.set_row_spacings (12);
142 lm_table.set_col_spacings (6);
143 lm_table.set_homogeneous (false);
145 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
148 lm_preamble.set_width_chars (60);
149 lm_preamble.set_line_wrap (true);
150 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
152 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
155 Gtk::Label* preamble;
156 preamble = manage (new Label);
157 preamble->set_width_chars (60);
158 preamble->set_line_wrap (true);
159 preamble->set_markup (_("Select two channels below and connect them using a cable."));
161 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
164 label = manage (new Label (_("Output channel")));
165 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
167 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
168 misc_align->add (lm_output_channel_combo);
169 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
172 label = manage (new Label (_("Input channel")));
173 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
175 misc_align = manage (new Alignment (0.0, 0.5));
176 misc_align->add (lm_input_channel_combo);
177 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
180 xopt = AttachOptions(0);
182 lm_measure_label.set_padding (10, 10);
183 lm_measure_button.add (lm_measure_label);
184 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
185 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
186 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
188 lm_use_button.set_sensitive (false);
190 /* Increase the default spacing around the labels of these three
196 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
197 l->set_padding (10, 10);
200 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
201 l->set_padding (10, 10);
204 preamble = manage (new Label);
205 preamble->set_width_chars (60);
206 preamble->set_line_wrap (true);
207 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
208 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
211 preamble = manage (new Label);
212 preamble->set_width_chars (60);
213 preamble->set_line_wrap (true);
214 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
215 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 ++row; // skip a row in the table
218 ++row; // skip a row in the table
220 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222 ++row; // skip a row in the table
223 ++row; // skip a row in the table
225 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
231 lm_vbox.set_border_width (12);
232 lm_vbox.pack_start (lm_table, false, false);
234 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
238 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
239 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
240 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
241 notebook.set_border_width (12);
243 notebook.set_show_tabs (false);
244 notebook.show_all ();
246 notebook.set_name ("SettingsNotebook");
248 /* packup the notebook */
250 get_vbox()->set_border_width (12);
251 get_vbox()->pack_start (notebook);
253 get_action_area()->pack_start (engine_status);
254 engine_status.show();
256 /* need a special function to print "all available channels" when the
257 * channel counts hit zero.
260 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
261 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
263 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
264 midi_devices_button.set_sensitive (false);
265 midi_devices_button.set_name ("generic button");
266 midi_devices_button.set_can_focus(true);
268 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
269 manage_control_app_sensitivity ();
271 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
272 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
273 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
275 /* Pick up any existing audio setup configuration, if appropriate */
277 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
279 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
280 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
281 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
282 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
285 set_state (*audio_setup);
288 if (backend_combo.get_active_text().empty()) {
289 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
290 backend_combo.set_active_text (backend_names.front());
295 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
296 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
297 backend_combo.set_active_text (backend_names.back());
298 /* ignore: don't save state */
299 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
304 /* Connect to signals */
306 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
307 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
308 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
309 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
310 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
312 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
313 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
314 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
315 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
317 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
319 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
320 connect_disconnect_button.set_no_show_all();
325 EngineControl::on_show ()
327 ArdourDialog::on_show ();
328 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
329 // re-check _have_control (jackd running) see #6041
333 ok_button->grab_focus();
337 EngineControl::on_response (int response_id)
339 ArdourDialog::on_response (response_id);
341 switch (response_id) {
343 push_state_to_backend (true);
346 #ifdef PLATFORM_WINDOWS
347 // For some reason we don't understand, 'hide()'
348 // needs to get called first in Windows
351 // But if there's no session open, this can produce
352 // a long gap when nothing appears to be happening.
353 // Let's show the splash image while we're waiting.
354 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
355 if ( ARDOUR_UI::instance() ) {
356 if ( !ARDOUR_UI::instance()->session_loaded ) {
357 ARDOUR_UI::instance()->show_splash();
361 push_state_to_backend (true);
364 push_state_to_backend (true);
368 case RESPONSE_DELETE_EVENT:
371 ev.type = GDK_BUTTON_PRESS;
373 on_delete_event ((GdkEventAny*) &ev);
382 EngineControl::build_notebook ()
385 AttachOptions xopt = AttachOptions (FILL|EXPAND);
387 /* clear the table */
389 Gtkmm2ext::container_clear (basic_vbox);
390 Gtkmm2ext::container_clear (basic_packer);
392 if (control_app_button.get_parent()) {
393 control_app_button.get_parent()->remove (control_app_button);
396 label = manage (left_aligned_label (_("Audio System:")));
397 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
398 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
400 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
401 lm_button_audio.set_name ("generic button");
402 lm_button_audio.set_can_focus(true);
405 build_full_control_notebook ();
407 build_no_control_notebook ();
410 basic_vbox.pack_start (basic_hbox, false, false);
413 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
414 basic_vbox.show_all ();
419 EngineControl::build_full_control_notebook ()
421 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
424 using namespace Notebook_Helpers;
426 vector<string> strings;
427 AttachOptions xopt = AttachOptions (FILL|EXPAND);
428 int row = 1; // row zero == backend combo
430 /* start packing it up */
432 if (backend->requires_driver_selection()) {
433 label = manage (left_aligned_label (_("Driver:")));
434 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
435 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
439 label = manage (left_aligned_label (_("Device:")));
440 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
441 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
444 label = manage (left_aligned_label (_("Sample rate:")));
445 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
446 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
450 label = manage (left_aligned_label (_("Buffer size:")));
451 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
452 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
453 buffer_size_duration_label.set_alignment (0.0); /* left-align */
454 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
456 /* button spans 2 rows */
458 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
461 input_channels.set_name ("InputChannels");
462 input_channels.set_flags (Gtk::CAN_FOCUS);
463 input_channels.set_digits (0);
464 input_channels.set_wrap (false);
465 output_channels.set_editable (true);
467 if (!ARDOUR::Profile->get_mixbus()) {
468 label = manage (left_aligned_label (_("Input Channels:")));
469 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
470 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
474 output_channels.set_name ("OutputChannels");
475 output_channels.set_flags (Gtk::CAN_FOCUS);
476 output_channels.set_digits (0);
477 output_channels.set_wrap (false);
478 output_channels.set_editable (true);
480 if (!ARDOUR::Profile->get_mixbus()) {
481 label = manage (left_aligned_label (_("Output Channels:")));
482 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
483 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
487 input_latency.set_name ("InputLatency");
488 input_latency.set_flags (Gtk::CAN_FOCUS);
489 input_latency.set_digits (0);
490 input_latency.set_wrap (false);
491 input_latency.set_editable (true);
493 label = manage (left_aligned_label (_("Hardware input latency:")));
494 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
495 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
496 label = manage (left_aligned_label (_("samples")));
497 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
500 output_latency.set_name ("OutputLatency");
501 output_latency.set_flags (Gtk::CAN_FOCUS);
502 output_latency.set_digits (0);
503 output_latency.set_wrap (false);
504 output_latency.set_editable (true);
506 label = manage (left_aligned_label (_("Hardware output latency:")));
507 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
508 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
509 label = manage (left_aligned_label (_("samples")));
510 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
512 /* button spans 2 rows */
514 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
517 label = manage (left_aligned_label (_("MIDI System:")));
518 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
519 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
520 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
525 EngineControl::build_no_control_notebook ()
527 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
530 using namespace Notebook_Helpers;
532 vector<string> strings;
533 AttachOptions xopt = AttachOptions (FILL|EXPAND);
534 int row = 1; // row zero == backend combo
535 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
537 label = manage (new Label);
538 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
539 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
542 if (backend->can_change_sample_rate_when_running()) {
543 label = manage (left_aligned_label (_("Sample rate:")));
544 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
545 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
549 if (backend->can_change_buffer_size_when_running()) {
550 label = manage (left_aligned_label (_("Buffer size:")));
551 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
552 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
553 buffer_size_duration_label.set_alignment (0.0); /* left-align */
554 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
558 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
562 EngineControl::~EngineControl ()
564 ignore_changes = true;
568 EngineControl::disable_latency_tab ()
570 vector<string> empty;
571 set_popdown_strings (lm_output_channel_combo, empty);
572 set_popdown_strings (lm_input_channel_combo, empty);
573 lm_measure_button.set_sensitive (false);
574 lm_use_button.set_sensitive (false);
578 EngineControl::enable_latency_tab ()
580 vector<string> outputs;
581 vector<string> inputs;
583 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
584 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
585 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
587 if (!ARDOUR::AudioEngine::instance()->running()) {
588 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
589 notebook.set_current_page (0);
593 else if (inputs.empty() || outputs.empty()) {
594 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
595 notebook.set_current_page (0);
600 lm_back_button_signal.disconnect();
602 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
605 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
609 set_popdown_strings (lm_output_channel_combo, outputs);
610 lm_output_channel_combo.set_active_text (outputs.front());
611 lm_output_channel_combo.set_sensitive (true);
613 set_popdown_strings (lm_input_channel_combo, inputs);
614 lm_input_channel_combo.set_active_text (inputs.front());
615 lm_input_channel_combo.set_sensitive (true);
617 lm_measure_button.set_sensitive (true);
621 EngineControl::setup_midi_tab_for_backend ()
623 string backend = backend_combo.get_active_text ();
625 Gtkmm2ext::container_clear (midi_vbox);
627 midi_vbox.set_border_width (12);
628 midi_device_table.set_border_width (12);
630 if (backend == "JACK") {
631 setup_midi_tab_for_jack ();
634 midi_vbox.pack_start (midi_device_table, true, true);
635 midi_vbox.pack_start (midi_back_button, false, false);
636 midi_vbox.show_all ();
640 EngineControl::setup_midi_tab_for_jack ()
645 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
647 device->input_latency = a->get_value();
649 device->output_latency = a->get_value();
654 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
655 b->set_active (!b->get_active());
656 device->enabled = b->get_active();
657 refresh_midi_display(device->name);
661 EngineControl::refresh_midi_display (std::string focus)
663 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
667 AttachOptions xopt = AttachOptions (FILL|EXPAND);
670 Gtkmm2ext::container_clear (midi_device_table);
672 midi_device_table.set_spacings (6);
674 l = manage (new Label);
675 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
676 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
677 l->set_alignment (0.5, 0.5);
681 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
682 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
683 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
684 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
686 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
687 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
688 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
689 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
692 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
697 bool enabled = (*p)->enabled;
699 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
700 m->set_name ("midi device");
701 m->set_can_focus (Gtk::CAN_FOCUS);
702 m->add_events (Gdk::BUTTON_RELEASE_MASK);
703 m->set_active (enabled);
704 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
705 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
706 if ((*p)->name == focus) {
710 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
711 s = manage (new Gtk::SpinButton (*a));
712 a->set_value ((*p)->input_latency);
713 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
714 s->set_sensitive (_can_set_midi_latencies && enabled);
715 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
717 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
718 s = manage (new Gtk::SpinButton (*a));
719 a->set_value ((*p)->output_latency);
720 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
721 s->set_sensitive (_can_set_midi_latencies && enabled);
722 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
724 b = manage (new Button (_("Calibrate")));
725 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
726 b->set_sensitive (_can_set_midi_latencies && enabled);
727 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
734 EngineControl::update_sensitivity ()
739 EngineControl::backend_changed ()
741 string backend_name = backend_combo.get_active_text();
742 boost::shared_ptr<ARDOUR::AudioBackend> backend;
744 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
745 /* eh? setting the backend failed... how ? */
746 /* A: stale config contains a backend that does not exist in current build */
750 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
753 setup_midi_tab_for_backend ();
754 _midi_devices.clear();
756 if (backend->requires_driver_selection()) {
757 vector<string> drivers = backend->enumerate_drivers();
758 driver_combo.set_sensitive (true);
760 if (!drivers.empty()) {
762 string current_driver;
763 current_driver = backend->driver_name ();
765 // driver might not have been set yet
766 if (current_driver == "") {
767 current_driver = driver_combo.get_active_text ();
768 if (current_driver == "")
769 // driver has never been set, make sure it's not blank
770 current_driver = drivers.front ();
773 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
774 set_popdown_strings (driver_combo, drivers);
775 driver_combo.set_active_text (current_driver);
782 driver_combo.set_sensitive (false);
783 /* this will change the device text which will cause a call to
784 * device changed which will set up parameters
789 vector<string> midi_options = backend->enumerate_midi_options();
791 if (midi_options.size() == 1) {
792 /* only contains the "none" option */
793 midi_option_combo.set_sensitive (false);
796 set_popdown_strings (midi_option_combo, midi_options);
797 midi_option_combo.set_active_text (midi_options.front());
798 midi_option_combo.set_sensitive (true);
800 midi_option_combo.set_sensitive (false);
804 connect_disconnect_button.hide();
806 midi_option_changed();
808 started_at_least_once = false;
810 if (!ignore_changes) {
811 maybe_display_saved_state ();
816 EngineControl::print_channel_count (Gtk::SpinButton* sb)
818 if (ARDOUR::Profile->get_mixbus()) {
822 uint32_t cnt = (uint32_t) sb->get_value();
824 sb->set_text (_("all available channels"));
827 snprintf (buf, sizeof (buf), "%d", cnt);
834 EngineControl::list_devices ()
836 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
839 /* now fill out devices, mark sample rates, buffer sizes insensitive */
841 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
843 /* NOTE: Ardour currently does not display the "available" field of the
846 * Doing so would require a different GUI widget than the combo
847 * box/popdown that we currently use, since it has no way to list
848 * items that are not selectable. Something more like a popup menu,
849 * which could have unselectable items, would be appropriate.
852 vector<string> available_devices;
854 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
855 available_devices.push_back (i->name);
858 if (!available_devices.empty()) {
860 update_sensitivity ();
863 string current_device, found_device;
864 current_device = device_combo.get_active_text ();
865 if (current_device == "") {
866 current_device = backend->device_name ();
869 // Make sure that the active text is still relevant for this
870 // device (it might only be relevant to the previous device!!)
871 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
872 if (*i == current_device)
873 found_device = current_device;
875 if (found_device == "")
876 // device has never been set (or was not relevant
877 // for this backend) Let's make sure it's not blank
878 current_device = available_devices.front ();
880 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
881 set_popdown_strings (device_combo, available_devices);
883 device_combo.set_active_text (current_device);
888 input_latency.set_sensitive (true);
889 output_latency.set_sensitive (true);
890 input_channels.set_sensitive (true);
891 output_channels.set_sensitive (true);
893 ok_button->set_sensitive (true);
894 apply_button->set_sensitive (true);
897 device_combo.clear();
898 sample_rate_combo.set_sensitive (false);
899 buffer_size_combo.set_sensitive (false);
900 input_latency.set_sensitive (false);
901 output_latency.set_sensitive (false);
902 input_channels.set_sensitive (false);
903 output_channels.set_sensitive (false);
905 ok_button->set_sensitive (false);
906 apply_button->set_sensitive (false);
908 ok_button->set_sensitive (true);
909 apply_button->set_sensitive (true);
910 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
911 sample_rate_combo.set_sensitive (true);
913 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
914 buffer_size_combo.set_sensitive (true);
922 EngineControl::driver_changed ()
924 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
927 backend->set_driver (driver_combo.get_active_text());
930 if (!ignore_changes) {
931 maybe_display_saved_state ();
936 EngineControl::device_changed ()
939 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
941 string device_name = device_combo.get_active_text ();
944 if (device_name != backend->device_name()) {
945 /* we set the backend-device to query various device related intormation.
946 * This has the side effect that backend->device_name() will match
947 * the device_name and 'change_device' will never be true.
948 * so work around this by setting...
950 queue_device_changed = true;
953 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
954 backend->set_device_name(device_name);
957 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
959 /* don't allow programmatic change to combos to cause a
960 recursive call to this method.
970 sr = backend->available_sample_rates (device_name);
973 sr.push_back (8000.0f);
974 sr.push_back (16000.0f);
975 sr.push_back (32000.0f);
976 sr.push_back (44100.0f);
977 sr.push_back (48000.0f);
978 sr.push_back (88200.0f);
979 sr.push_back (96000.0f);
980 sr.push_back (192000.0f);
981 sr.push_back (384000.0f);
984 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
985 s.push_back (rate_as_string (*x));
986 if (*x == _desired_sample_rate) {
992 sample_rate_combo.set_sensitive (true);
993 set_popdown_strings (sample_rate_combo, s);
995 if (desired.empty()) {
996 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
998 sample_rate_combo.set_active_text (desired);
1002 sample_rate_combo.set_sensitive (false);
1007 vector<uint32_t> bs;
1009 if (_have_control) {
1010 bs = backend->available_buffer_sizes (device_name);
1011 } else if (backend->can_change_buffer_size_when_running()) {
1019 bs.push_back (1024);
1020 bs.push_back (2048);
1021 bs.push_back (4096);
1022 bs.push_back (8192);
1025 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1026 s.push_back (bufsize_as_string (*x));
1030 buffer_size_combo.set_sensitive (true);
1031 set_popdown_strings (buffer_size_combo, s);
1033 uint32_t period = backend->buffer_size();
1035 period = backend->default_buffer_size(device_name);
1037 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1038 show_buffer_duration ();
1040 buffer_size_combo.set_sensitive (false);
1043 /* XXX theoretically need to set min + max channel counts here
1046 manage_control_app_sensitivity ();
1049 /* pick up any saved state for this device */
1051 if (!ignore_changes) {
1052 maybe_display_saved_state ();
1057 EngineControl::bufsize_as_string (uint32_t sz)
1059 /* Translators: "samples" is always plural here, so no
1060 need for plural+singular forms.
1063 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1068 EngineControl::sample_rate_changed ()
1070 /* reset the strings for buffer size to show the correct msec value
1071 (reflecting the new sample rate).
1074 show_buffer_duration ();
1079 EngineControl::buffer_size_changed ()
1081 show_buffer_duration ();
1085 EngineControl::show_buffer_duration ()
1088 /* buffer sizes - convert from just samples to samples + msecs for
1089 * the displayed string
1092 string bs_text = buffer_size_combo.get_active_text ();
1093 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1094 uint32_t rate = get_rate();
1096 /* Developers: note the hard-coding of a double buffered model
1097 in the (2 * samples) computation of latency. we always start
1098 the audiobackend in this configuration.
1100 /* note to jack1 developers: ardour also always starts the engine
1101 * in async mode (no jack2 --sync option) which adds an extra cycle
1102 * of latency with jack2 (and *3 would be correct)
1103 * The value can also be wrong if jackd is started externally..
1105 * At the time of writing the ALSA backend always uses double-buffering *2,
1106 * The Dummy backend *1, and who knows what ASIO really does :)
1108 * So just display the period size, that's also what
1109 * ARDOUR_UI::update_sample_rate() does for the status bar.
1110 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1111 * but still, that's the buffer period, not [round-trip] latency)
1114 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1115 buffer_size_duration_label.set_text (buf);
1119 EngineControl::midi_option_changed ()
1121 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1124 backend->set_midi_option (get_midi_option());
1126 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1128 //_midi_devices.clear(); // TODO merge with state-saved settings..
1129 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1130 std::vector<MidiDeviceSettings> new_devices;
1132 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1133 MidiDeviceSettings mds = find_midi_device (i->name);
1134 if (i->available && !mds) {
1135 uint32_t input_latency = 0;
1136 uint32_t output_latency = 0;
1137 if (_can_set_midi_latencies) {
1138 input_latency = backend->systemic_midi_input_latency (i->name);
1139 output_latency = backend->systemic_midi_output_latency (i->name);
1141 bool enabled = backend->midi_device_enabled (i->name);
1142 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1143 new_devices.push_back (ptr);
1144 } else if (i->available) {
1145 new_devices.push_back (mds);
1148 _midi_devices = new_devices;
1150 if (_midi_devices.empty()) {
1151 midi_devices_button.set_sensitive (false);
1153 midi_devices_button.set_sensitive (true);
1158 EngineControl::parameter_changed ()
1162 EngineControl::State
1163 EngineControl::get_matching_state (
1164 const string& backend,
1165 const string& driver,
1166 const string& device)
1168 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1169 if ((*i)->backend == backend &&
1170 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1178 EngineControl::State
1179 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1181 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1184 return get_matching_state (backend_combo.get_active_text(),
1185 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1186 device_combo.get_active_text());
1190 return get_matching_state (backend_combo.get_active_text(),
1192 device_combo.get_active_text());
1195 EngineControl::State
1196 EngineControl::save_state ()
1200 if (!_have_control) {
1201 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1205 state.reset(new StateStruct);
1206 state->backend = get_backend ();
1208 state.reset(new StateStruct);
1209 store_state (state);
1212 for (StateList::iterator i = states.begin(); i != states.end();) {
1213 if ((*i)->backend == state->backend &&
1214 (*i)->driver == state->driver &&
1215 (*i)->device == state->device) {
1216 i = states.erase(i);
1222 states.push_back (state);
1228 EngineControl::store_state (State state)
1230 state->backend = get_backend ();
1231 state->driver = get_driver ();
1232 state->device = get_device_name ();
1233 state->sample_rate = get_rate ();
1234 state->buffer_size = get_buffer_size ();
1235 state->input_latency = get_input_latency ();
1236 state->output_latency = get_output_latency ();
1237 state->input_channels = get_input_channels ();
1238 state->output_channels = get_output_channels ();
1239 state->midi_option = get_midi_option ();
1240 state->midi_devices = _midi_devices;
1244 EngineControl::maybe_display_saved_state ()
1246 if (!_have_control) {
1250 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1253 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1255 if (!_desired_sample_rate) {
1256 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1258 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1259 /* call this explicitly because we're ignoring changes to
1260 the controls at this point.
1262 show_buffer_duration ();
1263 input_latency.set_value (state->input_latency);
1264 output_latency.set_value (state->output_latency);
1266 if (!state->midi_option.empty()) {
1267 midi_option_combo.set_active_text (state->midi_option);
1268 _midi_devices = state->midi_devices;
1274 EngineControl::get_state ()
1276 XMLNode* root = new XMLNode ("AudioMIDISetup");
1279 if (!states.empty()) {
1280 XMLNode* state_nodes = new XMLNode ("EngineStates");
1282 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1284 XMLNode* node = new XMLNode ("State");
1286 node->add_property ("backend", (*i)->backend);
1287 node->add_property ("driver", (*i)->driver);
1288 node->add_property ("device", (*i)->device);
1289 node->add_property ("sample-rate", (*i)->sample_rate);
1290 node->add_property ("buffer-size", (*i)->buffer_size);
1291 node->add_property ("input-latency", (*i)->input_latency);
1292 node->add_property ("output-latency", (*i)->output_latency);
1293 node->add_property ("input-channels", (*i)->input_channels);
1294 node->add_property ("output-channels", (*i)->output_channels);
1295 node->add_property ("active", (*i)->active ? "yes" : "no");
1296 node->add_property ("midi-option", (*i)->midi_option);
1298 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1299 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1300 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1301 midi_device_stuff->add_property (X_("name"), (*p)->name);
1302 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1303 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1304 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1305 midi_devices->add_child_nocopy (*midi_device_stuff);
1307 node->add_child_nocopy (*midi_devices);
1309 state_nodes->add_child_nocopy (*node);
1312 root->add_child_nocopy (*state_nodes);
1319 EngineControl::set_state (const XMLNode& root)
1321 XMLNodeList clist, cclist;
1322 XMLNodeConstIterator citer, cciter;
1324 XMLNode* grandchild;
1325 XMLProperty* prop = NULL;
1327 if (root.name() != "AudioMIDISetup") {
1331 clist = root.children();
1335 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1339 if (child->name() != "EngineStates") {
1343 cclist = child->children();
1345 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1346 State state (new StateStruct);
1348 grandchild = *cciter;
1350 if (grandchild->name() != "State") {
1354 if ((prop = grandchild->property ("backend")) == 0) {
1357 state->backend = prop->value ();
1359 if ((prop = grandchild->property ("driver")) == 0) {
1362 state->driver = prop->value ();
1364 if ((prop = grandchild->property ("device")) == 0) {
1367 state->device = prop->value ();
1369 if ((prop = grandchild->property ("sample-rate")) == 0) {
1372 state->sample_rate = atof (prop->value ());
1374 if ((prop = grandchild->property ("buffer-size")) == 0) {
1377 state->buffer_size = atoi (prop->value ());
1379 if ((prop = grandchild->property ("input-latency")) == 0) {
1382 state->input_latency = atoi (prop->value ());
1384 if ((prop = grandchild->property ("output-latency")) == 0) {
1387 state->output_latency = atoi (prop->value ());
1389 if ((prop = grandchild->property ("input-channels")) == 0) {
1392 state->input_channels = atoi (prop->value ());
1394 if ((prop = grandchild->property ("output-channels")) == 0) {
1397 state->output_channels = atoi (prop->value ());
1399 if ((prop = grandchild->property ("active")) == 0) {
1402 state->active = string_is_affirmative (prop->value ());
1404 if ((prop = grandchild->property ("midi-option")) == 0) {
1407 state->midi_option = prop->value ();
1409 state->midi_devices.clear();
1411 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1412 const XMLNodeList mnc = midinode->children();
1413 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1414 if ((*n)->property (X_("name")) == 0
1415 || (*n)->property (X_("enabled")) == 0
1416 || (*n)->property (X_("input-latency")) == 0
1417 || (*n)->property (X_("output-latency")) == 0
1422 MidiDeviceSettings ptr (new MidiDeviceSetting(
1423 (*n)->property (X_("name"))->value (),
1424 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1425 atoi ((*n)->property (X_("input-latency"))->value ()),
1426 atoi ((*n)->property (X_("output-latency"))->value ())
1428 state->midi_devices.push_back (ptr);
1433 /* remove accumulated duplicates (due to bug in ealier version)
1434 * this can be removed again before release
1436 for (StateList::iterator i = states.begin(); i != states.end();) {
1437 if ((*i)->backend == state->backend &&
1438 (*i)->driver == state->driver &&
1439 (*i)->device == state->device) {
1440 i = states.erase(i);
1447 states.push_back (state);
1451 /* now see if there was an active state and switch the setup to it */
1453 // purge states of backend that are not available in this built
1454 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1455 vector<std::string> backend_names;
1457 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1458 backend_names.push_back((*i)->name);
1460 for (StateList::iterator i = states.begin(); i != states.end();) {
1461 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1462 i = states.erase(i);
1468 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1471 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1472 backend_combo.set_active_text ((*i)->backend);
1473 driver_combo.set_active_text ((*i)->driver);
1474 device_combo.set_active_text ((*i)->device);
1475 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1476 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1477 input_latency.set_value ((*i)->input_latency);
1478 output_latency.set_value ((*i)->output_latency);
1479 midi_option_combo.set_active_text ((*i)->midi_option);
1486 EngineControl::push_state_to_backend (bool start)
1488 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1494 /* figure out what is going to change */
1496 bool restart_required = false;
1497 bool was_running = ARDOUR::AudioEngine::instance()->running();
1498 bool change_driver = false;
1499 bool change_device = false;
1500 bool change_rate = false;
1501 bool change_bufsize = false;
1502 bool change_latency = false;
1503 bool change_channels = false;
1504 bool change_midi = false;
1506 uint32_t ochan = get_output_channels ();
1507 uint32_t ichan = get_input_channels ();
1509 if (_have_control) {
1511 if (started_at_least_once) {
1513 /* we can control the backend */
1515 if (backend->requires_driver_selection()) {
1516 if (get_driver() != backend->driver_name()) {
1517 change_driver = true;
1521 if (queue_device_changed || get_device_name() != backend->device_name()) {
1522 change_device = true;
1525 if (get_rate() != backend->sample_rate()) {
1529 if (get_buffer_size() != backend->buffer_size()) {
1530 change_bufsize = true;
1533 if (get_midi_option() != backend->midi_option()) {
1537 /* zero-requested channels means "all available" */
1540 ichan = backend->input_channels();
1544 ochan = backend->output_channels();
1547 if (ichan != backend->input_channels()) {
1548 change_channels = true;
1551 if (ochan != backend->output_channels()) {
1552 change_channels = true;
1555 if (get_input_latency() != backend->systemic_input_latency() ||
1556 get_output_latency() != backend->systemic_output_latency()) {
1557 change_latency = true;
1560 /* backend never started, so we have to force a group
1563 change_device = true;
1564 if (backend->requires_driver_selection()) {
1565 change_driver = true;
1568 change_bufsize = true;
1569 change_channels = true;
1570 change_latency = true;
1576 /* we have no control over the backend, meaning that we can
1577 * only possibly change sample rate and buffer size.
1581 if (get_rate() != backend->sample_rate()) {
1582 change_bufsize = true;
1585 if (get_buffer_size() != backend->buffer_size()) {
1586 change_bufsize = true;
1590 queue_device_changed = false;
1592 if (!_have_control) {
1594 /* We do not have control over the backend, so the best we can
1595 * do is try to change the sample rate and/or bufsize and get
1599 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1603 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1608 backend->set_sample_rate (get_rate());
1611 if (change_bufsize) {
1612 backend->set_buffer_size (get_buffer_size());
1616 if (ARDOUR::AudioEngine::instance()->start ()) {
1617 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1627 /* determine if we need to stop the backend before changing parameters */
1629 if (change_driver || change_device || change_channels || change_latency ||
1630 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1632 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1633 restart_required = true;
1635 restart_required = false;
1640 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1641 /* no changes in any parameters that absolutely require a
1642 * restart, so check those that might be changeable without a
1646 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1647 /* can't do this while running ... */
1648 restart_required = true;
1651 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1652 /* can't do this while running ... */
1653 restart_required = true;
1659 if (restart_required) {
1660 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1667 if (change_driver && backend->set_driver (get_driver())) {
1668 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1671 if (change_device && backend->set_device_name (get_device_name())) {
1672 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1675 if (change_rate && backend->set_sample_rate (get_rate())) {
1676 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1679 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1680 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1684 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1685 if (backend->set_input_channels (get_input_channels())) {
1686 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1689 if (backend->set_output_channels (get_output_channels())) {
1690 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1694 if (change_latency) {
1695 if (backend->set_systemic_input_latency (get_input_latency())) {
1696 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1699 if (backend->set_systemic_output_latency (get_output_latency())) {
1700 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1706 backend->set_midi_option (get_midi_option());
1710 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1711 if (_measure_midi) {
1712 if (*p == _measure_midi) {
1713 backend->set_midi_device_enabled ((*p)->name, true);
1715 backend->set_midi_device_enabled ((*p)->name, false);
1719 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1720 if (backend->can_set_systemic_midi_latencies()) {
1721 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1722 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1727 if (start || (was_running && restart_required)) {
1728 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1739 EngineControl::post_push ()
1741 /* get a pointer to the current state object, creating one if
1745 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1748 state = save_state ();
1756 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1757 (*i)->active = false;
1760 /* mark this one active (to be used next time the dialog is
1764 state->active = true;
1766 if (_have_control) { // XXX
1767 manage_control_app_sensitivity ();
1770 /* schedule a redisplay of MIDI ports */
1771 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1776 EngineControl::get_rate () const
1778 float r = atof (sample_rate_combo.get_active_text ());
1779 /* the string may have been translated with an abbreviation for
1780 * thousands, so use a crude heuristic to fix this.
1790 EngineControl::get_buffer_size () const
1792 string txt = buffer_size_combo.get_active_text ();
1795 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1796 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
1797 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
1805 EngineControl::get_midi_option () const
1807 return midi_option_combo.get_active_text();
1811 EngineControl::get_input_channels() const
1813 if (ARDOUR::Profile->get_mixbus()) {
1814 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1815 if (!backend) return 0;
1816 return backend->input_channels();
1818 return (uint32_t) input_channels_adjustment.get_value();
1822 EngineControl::get_output_channels() const
1824 if (ARDOUR::Profile->get_mixbus()) {
1825 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1826 if (!backend) return 0;
1827 return backend->input_channels();
1829 return (uint32_t) output_channels_adjustment.get_value();
1833 EngineControl::get_input_latency() const
1835 return (uint32_t) input_latency_adjustment.get_value();
1839 EngineControl::get_output_latency() const
1841 return (uint32_t) output_latency_adjustment.get_value();
1845 EngineControl::get_backend () const
1847 return backend_combo.get_active_text ();
1851 EngineControl::get_driver () const
1853 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1854 return driver_combo.get_active_text ();
1861 EngineControl::get_device_name () const
1863 return device_combo.get_active_text ();
1867 EngineControl::control_app_button_clicked ()
1869 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1875 backend->launch_control_app ();
1879 EngineControl::manage_control_app_sensitivity ()
1881 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1887 string appname = backend->control_app_name();
1889 if (appname.empty()) {
1890 control_app_button.set_sensitive (false);
1892 control_app_button.set_sensitive (true);
1897 EngineControl::set_desired_sample_rate (uint32_t sr)
1899 _desired_sample_rate = sr;
1904 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1906 if (page_num == 0) {
1907 cancel_button->set_sensitive (true);
1908 ok_button->set_sensitive (true);
1909 apply_button->set_sensitive (true);
1910 _measure_midi.reset();
1912 cancel_button->set_sensitive (false);
1913 ok_button->set_sensitive (false);
1914 apply_button->set_sensitive (false);
1917 if (page_num == midi_tab) {
1919 refresh_midi_display ();
1922 if (page_num == latency_tab) {
1925 if (ARDOUR::AudioEngine::instance()->running()) {
1926 // TODO - mark as 'stopped for latency
1927 ARDOUR_UI::instance()->disconnect_from_engine ();
1931 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1933 /* save any existing latency values */
1935 uint32_t il = (uint32_t) input_latency.get_value ();
1936 uint32_t ol = (uint32_t) input_latency.get_value ();
1938 /* reset to zero so that our new test instance
1939 will be clean of any existing latency measures.
1941 NB. this should really be done by the backend
1942 when stated for latency measurement.
1945 input_latency.set_value (0);
1946 output_latency.set_value (0);
1948 push_state_to_backend (false);
1952 input_latency.set_value (il);
1953 output_latency.set_value (ol);
1956 // This should be done in push_state_to_backend()
1957 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1958 disable_latency_tab ();
1961 enable_latency_tab ();
1965 end_latency_detection ();
1966 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1971 /* latency measurement */
1974 EngineControl::check_audio_latency_measurement ()
1976 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1978 if (mtdm->resolve () < 0) {
1979 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1983 if (mtdm->err () > 0.3) {
1989 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1991 if (sample_rate == 0) {
1992 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1993 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1997 int frames_total = mtdm->del();
1998 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2000 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2001 _("Detected roundtrip latency: "),
2002 frames_total, frames_total * 1000.0f/sample_rate,
2003 _("Systemic latency: "),
2004 extra, extra * 1000.0f/sample_rate);
2008 if (mtdm->err () > 0.2) {
2010 strcat (buf, _("(signal detection error)"));
2016 strcat (buf, _("(inverted - bad wiring)"));
2020 lm_results.set_markup (string_compose (results_markup, buf));
2023 have_lm_results = true;
2024 end_latency_detection ();
2025 lm_use_button.set_sensitive (true);
2033 EngineControl::check_midi_latency_measurement ()
2035 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2037 if (!mididm->have_signal () || mididm->latency () == 0) {
2038 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2043 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2045 if (sample_rate == 0) {
2046 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2047 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2051 ARDOUR::framecnt_t frames_total = mididm->latency();
2052 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2053 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2054 _("Detected roundtrip latency: "),
2055 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2056 _("Systemic latency: "),
2057 extra, extra * 1000.0f / sample_rate);
2061 if (!mididm->ok ()) {
2063 strcat (buf, _("(averaging)"));
2067 if (mididm->deviation () > 50.0) {
2069 strcat (buf, _("(too large jitter)"));
2071 } else if (mididm->deviation () > 10.0) {
2073 strcat (buf, _("(large jitter)"));
2077 have_lm_results = true;
2078 end_latency_detection ();
2079 lm_use_button.set_sensitive (true);
2080 lm_results.set_markup (string_compose (results_markup, buf));
2082 } else if (mididm->processed () > 400) {
2083 have_lm_results = false;
2084 end_latency_detection ();
2085 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2089 lm_results.set_markup (string_compose (results_markup, buf));
2095 EngineControl::start_latency_detection ()
2097 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2098 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2100 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2101 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2102 if (_measure_midi) {
2103 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2105 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2107 lm_measure_label.set_text (_("Cancel"));
2108 have_lm_results = false;
2109 lm_use_button.set_sensitive (false);
2110 lm_input_channel_combo.set_sensitive (false);
2111 lm_output_channel_combo.set_sensitive (false);
2117 EngineControl::end_latency_detection ()
2119 latency_timeout.disconnect ();
2120 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2121 lm_measure_label.set_text (_("Measure"));
2122 if (!have_lm_results) {
2123 lm_use_button.set_sensitive (false);
2125 lm_input_channel_combo.set_sensitive (true);
2126 lm_output_channel_combo.set_sensitive (true);
2131 EngineControl::latency_button_clicked ()
2134 start_latency_detection ();
2136 end_latency_detection ();
2141 EngineControl::use_latency_button_clicked ()
2143 if (_measure_midi) {
2144 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2148 ARDOUR::framecnt_t frames_total = mididm->latency();
2149 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2150 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2151 _measure_midi->input_latency = one_way;
2152 _measure_midi->output_latency = one_way;
2153 notebook.set_current_page (midi_tab);
2155 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2161 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2162 one_way = std::max (0., one_way);
2164 input_latency_adjustment.set_value (one_way);
2165 output_latency_adjustment.set_value (one_way);
2167 /* back to settings page */
2168 notebook.set_current_page (0);
2174 EngineControl::on_delete_event (GdkEventAny* ev)
2176 if (notebook.get_current_page() == 2) {
2177 /* currently on latency tab - be sure to clean up */
2178 end_latency_detection ();
2180 return ArdourDialog::on_delete_event (ev);
2184 EngineControl::engine_running ()
2186 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2189 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2190 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2192 buffer_size_combo.set_sensitive (true);
2193 sample_rate_combo.set_sensitive (true);
2195 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2196 connect_disconnect_button.show();
2198 started_at_least_once = true;
2199 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2203 EngineControl::engine_stopped ()
2205 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2208 buffer_size_combo.set_sensitive (false);
2209 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2210 connect_disconnect_button.show();
2212 sample_rate_combo.set_sensitive (true);
2213 buffer_size_combo.set_sensitive (true);
2214 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2218 EngineControl::device_list_changed ()
2220 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2222 midi_option_changed();
2226 EngineControl::connect_disconnect_click()
2228 if (ARDOUR::AudioEngine::instance()->running()) {
2229 ARDOUR_UI::instance()->disconnect_from_engine ();
2231 ARDOUR_UI::instance()->reconnect_to_engine ();
2236 EngineControl::calibrate_audio_latency ()
2238 _measure_midi.reset ();
2239 have_lm_results = false;
2240 lm_use_button.set_sensitive (false);
2241 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2242 notebook.set_current_page (latency_tab);
2246 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2249 have_lm_results = false;
2250 lm_use_button.set_sensitive (false);
2251 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2252 notebook.set_current_page (latency_tab);
2256 EngineControl::configure_midi_devices ()
2258 notebook.set_current_page (midi_tab);