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);
123 /* setup basic packing characteristics for the table used on the main
124 * tab of the notebook
127 basic_packer.set_spacings (6);
128 basic_packer.set_border_width (12);
129 basic_packer.set_homogeneous (false);
133 basic_hbox.pack_start (basic_packer, false, false);
135 /* latency measurement tab */
137 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
140 lm_table.set_row_spacings (12);
141 lm_table.set_col_spacings (6);
142 lm_table.set_homogeneous (false);
144 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
147 lm_preamble.set_width_chars (60);
148 lm_preamble.set_line_wrap (true);
149 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
151 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
154 Gtk::Label* preamble;
155 preamble = manage (new Label);
156 preamble->set_width_chars (60);
157 preamble->set_line_wrap (true);
158 preamble->set_markup (_("Select two channels below and connect them using a cable."));
160 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
163 label = manage (new Label (_("Output channel")));
164 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
166 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
167 misc_align->add (lm_output_channel_combo);
168 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
171 label = manage (new Label (_("Input channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_input_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
179 lm_measure_label.set_padding (10, 10);
180 lm_measure_button.add (lm_measure_label);
181 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
182 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
183 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
185 lm_use_button.set_sensitive (false);
187 /* Increase the default spacing around the labels of these three
193 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
194 l->set_padding (10, 10);
197 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
198 l->set_padding (10, 10);
201 preamble = manage (new Label);
202 preamble->set_width_chars (60);
203 preamble->set_line_wrap (true);
204 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
205 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
208 preamble = manage (new Label);
209 preamble->set_width_chars (60);
210 preamble->set_line_wrap (true);
211 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
212 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
214 ++row; // skip a row in the table
215 ++row; // skip a row in the table
217 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219 ++row; // skip a row in the table
220 ++row; // skip a row in the table
222 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
228 lm_vbox.set_border_width (12);
229 lm_vbox.pack_start (lm_table, false, false);
231 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
235 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
236 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
237 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
238 notebook.set_border_width (12);
240 notebook.set_show_tabs (false);
241 notebook.show_all ();
243 notebook.set_name ("SettingsNotebook");
245 /* packup the notebook */
247 get_vbox()->set_border_width (12);
248 get_vbox()->pack_start (notebook);
250 get_action_area()->pack_start (engine_status);
251 engine_status.show();
253 /* need a special function to print "all available channels" when the
254 * channel counts hit zero.
257 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
258 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
260 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
261 midi_devices_button.set_sensitive (false);
262 midi_devices_button.set_name ("generic button");
263 midi_devices_button.set_can_focus(true);
265 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
266 manage_control_app_sensitivity ();
268 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
269 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
270 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
272 /* Pick up any existing audio setup configuration, if appropriate */
274 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
276 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
277 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
278 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
279 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
282 set_state (*audio_setup);
285 if (backend_combo.get_active_text().empty()) {
286 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
287 backend_combo.set_active_text (backend_names.front());
292 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
293 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
294 backend_combo.set_active_text (backend_names.back());
295 /* ignore: don't save state */
296 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
301 /* Connect to signals */
303 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
304 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
305 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
306 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
307 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
308 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
310 input_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::input_device_changed));
311 output_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::output_device_changed));
313 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
314 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
315 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
316 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
318 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
320 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
321 connect_disconnect_button.set_no_show_all();
326 EngineControl::on_show ()
328 ArdourDialog::on_show ();
329 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
330 // re-check _have_control (jackd running) see #6041
334 input_device_changed ();
335 output_device_changed ();
336 ok_button->grab_focus();
340 EngineControl::on_response (int response_id)
342 ArdourDialog::on_response (response_id);
344 switch (response_id) {
346 push_state_to_backend (true);
349 #ifdef PLATFORM_WINDOWS
350 // For some reason we don't understand, 'hide()'
351 // needs to get called first in Windows
354 // But if there's no session open, this can produce
355 // a long gap when nothing appears to be happening.
356 // Let's show the splash image while we're waiting.
357 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
358 if ( ARDOUR_UI::instance() ) {
359 if ( !ARDOUR_UI::instance()->session_loaded ) {
360 ARDOUR_UI::instance()->show_splash();
364 push_state_to_backend (true);
367 push_state_to_backend (true);
371 case RESPONSE_DELETE_EVENT:
374 ev.type = GDK_BUTTON_PRESS;
376 on_delete_event ((GdkEventAny*) &ev);
385 EngineControl::build_notebook ()
388 AttachOptions xopt = AttachOptions (FILL|EXPAND);
390 /* clear the table */
392 Gtkmm2ext::container_clear (basic_vbox);
393 Gtkmm2ext::container_clear (basic_packer);
395 if (control_app_button.get_parent()) {
396 control_app_button.get_parent()->remove (control_app_button);
399 label = manage (left_aligned_label (_("Audio System:")));
400 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
401 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
403 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
404 lm_button_audio.set_name ("generic button");
405 lm_button_audio.set_can_focus(true);
408 build_full_control_notebook ();
410 build_no_control_notebook ();
413 basic_vbox.pack_start (basic_hbox, false, false);
416 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
417 basic_vbox.show_all ();
422 EngineControl::build_full_control_notebook ()
424 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
427 using namespace Notebook_Helpers;
429 vector<string> strings;
430 AttachOptions xopt = AttachOptions (FILL|EXPAND);
431 int row = 1; // row zero == backend combo
433 /* start packing it up */
435 if (backend->requires_driver_selection()) {
436 label = manage (left_aligned_label (_("Driver:")));
437 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
438 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
442 if (backend->use_separate_input_and_output_devices()) {
443 label = manage (left_aligned_label (_("Input Device:")));
444 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
445 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
447 label = manage (left_aligned_label (_("Output Device:")));
448 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
449 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
451 // reset so it isn't used in state comparisons
452 device_combo.set_active_text ("");
454 label = manage (left_aligned_label (_("Device:")));
455 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
456 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
458 // reset these so they don't get used in state comparisons
459 input_device_combo.set_active_text ("");
460 output_device_combo.set_active_text ("");
463 label = manage (left_aligned_label (_("Sample rate:")));
464 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
465 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
469 label = manage (left_aligned_label (_("Buffer size:")));
470 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
471 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
472 buffer_size_duration_label.set_alignment (0.0); /* left-align */
473 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
475 /* button spans 2 rows */
477 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
480 input_channels.set_name ("InputChannels");
481 input_channels.set_flags (Gtk::CAN_FOCUS);
482 input_channels.set_digits (0);
483 input_channels.set_wrap (false);
484 output_channels.set_editable (true);
486 if (!ARDOUR::Profile->get_mixbus()) {
487 label = manage (left_aligned_label (_("Input Channels:")));
488 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
489 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
493 output_channels.set_name ("OutputChannels");
494 output_channels.set_flags (Gtk::CAN_FOCUS);
495 output_channels.set_digits (0);
496 output_channels.set_wrap (false);
497 output_channels.set_editable (true);
499 if (!ARDOUR::Profile->get_mixbus()) {
500 label = manage (left_aligned_label (_("Output Channels:")));
501 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
502 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
506 input_latency.set_name ("InputLatency");
507 input_latency.set_flags (Gtk::CAN_FOCUS);
508 input_latency.set_digits (0);
509 input_latency.set_wrap (false);
510 input_latency.set_editable (true);
512 label = manage (left_aligned_label (_("Hardware input latency:")));
513 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
514 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
515 label = manage (left_aligned_label (_("samples")));
516 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
519 output_latency.set_name ("OutputLatency");
520 output_latency.set_flags (Gtk::CAN_FOCUS);
521 output_latency.set_digits (0);
522 output_latency.set_wrap (false);
523 output_latency.set_editable (true);
525 label = manage (left_aligned_label (_("Hardware output latency:")));
526 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
527 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
528 label = manage (left_aligned_label (_("samples")));
529 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
531 /* button spans 2 rows */
533 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
536 label = manage (left_aligned_label (_("MIDI System:")));
537 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
538 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
539 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
544 EngineControl::build_no_control_notebook ()
546 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
549 using namespace Notebook_Helpers;
551 vector<string> strings;
552 AttachOptions xopt = AttachOptions (FILL|EXPAND);
553 int row = 1; // row zero == backend combo
554 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
556 label = manage (new Label);
557 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
558 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
561 if (backend->can_change_sample_rate_when_running()) {
562 label = manage (left_aligned_label (_("Sample rate:")));
563 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
564 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
568 if (backend->can_change_buffer_size_when_running()) {
569 label = manage (left_aligned_label (_("Buffer size:")));
570 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
571 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
572 buffer_size_duration_label.set_alignment (0.0); /* left-align */
573 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
577 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
581 EngineControl::~EngineControl ()
583 ignore_changes = true;
587 EngineControl::disable_latency_tab ()
589 vector<string> empty;
590 set_popdown_strings (lm_output_channel_combo, empty);
591 set_popdown_strings (lm_input_channel_combo, empty);
592 lm_measure_button.set_sensitive (false);
593 lm_use_button.set_sensitive (false);
597 EngineControl::enable_latency_tab ()
599 vector<string> outputs;
600 vector<string> inputs;
602 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
603 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
604 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
606 if (!ARDOUR::AudioEngine::instance()->running()) {
607 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
608 notebook.set_current_page (0);
612 else if (inputs.empty() || outputs.empty()) {
613 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
614 notebook.set_current_page (0);
619 lm_back_button_signal.disconnect();
621 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
624 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
628 set_popdown_strings (lm_output_channel_combo, outputs);
629 lm_output_channel_combo.set_active_text (outputs.front());
630 lm_output_channel_combo.set_sensitive (true);
632 set_popdown_strings (lm_input_channel_combo, inputs);
633 lm_input_channel_combo.set_active_text (inputs.front());
634 lm_input_channel_combo.set_sensitive (true);
636 lm_measure_button.set_sensitive (true);
640 EngineControl::setup_midi_tab_for_backend ()
642 string backend = backend_combo.get_active_text ();
644 Gtkmm2ext::container_clear (midi_vbox);
646 midi_vbox.set_border_width (12);
647 midi_device_table.set_border_width (12);
649 if (backend == "JACK") {
650 setup_midi_tab_for_jack ();
653 midi_vbox.pack_start (midi_device_table, true, true);
654 midi_vbox.pack_start (midi_back_button, false, false);
655 midi_vbox.show_all ();
659 EngineControl::setup_midi_tab_for_jack ()
664 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
666 device->input_latency = a->get_value();
668 device->output_latency = a->get_value();
673 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
674 b->set_active (!b->get_active());
675 device->enabled = b->get_active();
676 refresh_midi_display(device->name);
680 EngineControl::refresh_midi_display (std::string focus)
682 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
686 AttachOptions xopt = AttachOptions (FILL|EXPAND);
689 Gtkmm2ext::container_clear (midi_device_table);
691 midi_device_table.set_spacings (6);
693 l = manage (new Label);
694 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
695 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
696 l->set_alignment (0.5, 0.5);
700 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
701 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
702 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
703 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
705 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
706 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
707 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
708 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
711 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
716 bool enabled = (*p)->enabled;
718 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
719 m->set_name ("midi device");
720 m->set_can_focus (Gtk::CAN_FOCUS);
721 m->add_events (Gdk::BUTTON_RELEASE_MASK);
722 m->set_active (enabled);
723 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
724 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
725 if ((*p)->name == focus) {
729 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
730 s = manage (new Gtk::SpinButton (*a));
731 a->set_value ((*p)->input_latency);
732 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
733 s->set_sensitive (_can_set_midi_latencies && enabled);
734 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
736 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
737 s = manage (new Gtk::SpinButton (*a));
738 a->set_value ((*p)->output_latency);
739 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
740 s->set_sensitive (_can_set_midi_latencies && enabled);
741 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
743 b = manage (new Button (_("Calibrate")));
744 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
745 b->set_sensitive (_can_set_midi_latencies && enabled);
746 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
753 EngineControl::update_sensitivity ()
758 EngineControl::backend_changed ()
760 string backend_name = backend_combo.get_active_text();
761 boost::shared_ptr<ARDOUR::AudioBackend> backend;
763 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
764 /* eh? setting the backend failed... how ? */
765 /* A: stale config contains a backend that does not exist in current build */
769 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
772 setup_midi_tab_for_backend ();
773 _midi_devices.clear();
775 if (backend->requires_driver_selection()) {
776 vector<string> drivers = backend->enumerate_drivers();
777 driver_combo.set_sensitive (true);
779 if (!drivers.empty()) {
781 string current_driver;
782 current_driver = backend->driver_name ();
784 // driver might not have been set yet
785 if (current_driver == "") {
786 current_driver = driver_combo.get_active_text ();
787 if (current_driver == "")
788 // driver has never been set, make sure it's not blank
789 current_driver = drivers.front ();
792 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
793 set_popdown_strings (driver_combo, drivers);
794 driver_combo.set_active_text (current_driver);
801 driver_combo.set_sensitive (false);
802 /* this will change the device text which will cause a call to
803 * device changed which will set up parameters
808 vector<string> midi_options = backend->enumerate_midi_options();
810 if (midi_options.size() == 1) {
811 /* only contains the "none" option */
812 midi_option_combo.set_sensitive (false);
815 set_popdown_strings (midi_option_combo, midi_options);
816 midi_option_combo.set_active_text (midi_options.front());
817 midi_option_combo.set_sensitive (true);
819 midi_option_combo.set_sensitive (false);
823 connect_disconnect_button.hide();
825 midi_option_changed();
827 started_at_least_once = false;
829 if (!ignore_changes) {
830 maybe_display_saved_state ();
835 EngineControl::print_channel_count (Gtk::SpinButton* sb)
837 if (ARDOUR::Profile->get_mixbus()) {
841 uint32_t cnt = (uint32_t) sb->get_value();
843 sb->set_text (_("all available channels"));
846 snprintf (buf, sizeof (buf), "%d", cnt);
853 EngineControl::set_driver_popdown_strings ()
855 string backend_name = backend_combo.get_active_text();
856 boost::shared_ptr<ARDOUR::AudioBackend> backend;
858 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
859 /* eh? setting the backend failed... how ? */
860 /* A: stale config contains a backend that does not exist in current build */
864 vector<string> drivers = backend->enumerate_drivers();
865 set_popdown_strings (driver_combo, drivers);
869 // @return true if there are devices available
871 EngineControl::set_device_popdown_strings ()
873 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
874 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
876 /* NOTE: Ardour currently does not display the "available" field of the
879 * Doing so would require a different GUI widget than the combo
880 * box/popdown that we currently use, since it has no way to list
881 * items that are not selectable. Something more like a popup menu,
882 * which could have unselectable items, would be appropriate.
885 vector<string> available_devices;
887 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
888 available_devices.push_back (i->name);
892 if (!available_devices.empty()) {
893 update_sensitivity ();
896 string current_device, found_device;
897 current_device = device_combo.get_active_text ();
898 if (current_device == "") {
899 current_device = backend->device_name ();
902 // Make sure that the active text is still relevant for this
903 // device (it might only be relevant to the previous device!!)
904 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
905 if (*i == current_device)
906 found_device = current_device;
908 if (found_device == "")
909 // device has never been set (or was not relevant
910 // for this backend) Let's make sure it's not blank
911 current_device = available_devices.front ();
913 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
914 set_popdown_strings (device_combo, available_devices);
916 device_combo.set_active_text (current_device);
925 // @return true if there are input devices available
927 EngineControl::set_input_device_popdown_strings ()
929 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
930 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
932 vector<string> available_devices;
934 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
935 available_devices.push_back (i->name);
938 if (!available_devices.empty()) {
939 update_sensitivity ();
942 string current_device, found_device;
943 current_device = input_device_combo.get_active_text ();
944 if (current_device == "") {
945 current_device = backend->input_device_name ();
948 // Make sure that the active text is still relevant for this
949 // device (it might only be relevant to the previous device!!)
950 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
951 if (*i == current_device)
952 found_device = current_device;
954 if (found_device == "")
955 // device has never been set (or was not relevant
956 // for this backend) Let's make sure it's not blank
957 current_device = available_devices.front ();
959 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
960 set_popdown_strings (input_device_combo, available_devices);
962 input_device_combo.set_active_text (current_device);
965 input_device_changed ();
972 // @return true if there are output devices available
974 EngineControl::set_output_device_popdown_strings ()
976 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
977 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
979 vector<string> available_devices;
981 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
982 available_devices.push_back (i->name);
985 if (!available_devices.empty()) {
986 update_sensitivity ();
989 string current_device, found_device;
990 current_device = output_device_combo.get_active_text ();
991 if (current_device == "") {
992 current_device = backend->output_device_name ();
995 // Make sure that the active text is still relevant for this
996 // device (it might only be relevant to the previous device!!)
997 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
998 if (*i == current_device)
999 found_device = current_device;
1001 if (found_device == "")
1002 // device has never been set (or was not relevant
1003 // for this backend) Let's make sure it's not blank
1004 current_device = available_devices.front ();
1006 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1007 set_popdown_strings (output_device_combo, available_devices);
1009 output_device_combo.set_active_text (current_device);
1012 output_device_changed ();
1020 EngineControl::list_devices ()
1022 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1025 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1027 bool devices_available = false;
1029 if (backend->use_separate_input_and_output_devices ()) {
1030 bool input_devices_available = set_input_device_popdown_strings ();
1031 bool output_devices_available = set_output_device_popdown_strings ();
1032 devices_available = input_devices_available || output_devices_available;
1034 devices_available = set_device_popdown_strings ();
1037 if (devices_available) {
1038 input_latency.set_sensitive (true);
1039 output_latency.set_sensitive (true);
1040 input_channels.set_sensitive (true);
1041 output_channels.set_sensitive (true);
1043 ok_button->set_sensitive (true);
1044 apply_button->set_sensitive (true);
1047 device_combo.clear();
1048 input_device_combo.clear();
1049 output_device_combo.clear();
1050 sample_rate_combo.set_sensitive (false);
1051 buffer_size_combo.set_sensitive (false);
1052 input_latency.set_sensitive (false);
1053 output_latency.set_sensitive (false);
1054 input_channels.set_sensitive (false);
1055 output_channels.set_sensitive (false);
1056 if (_have_control) {
1057 ok_button->set_sensitive (false);
1058 apply_button->set_sensitive (false);
1060 ok_button->set_sensitive (true);
1061 apply_button->set_sensitive (true);
1062 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1063 sample_rate_combo.set_sensitive (true);
1065 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1066 buffer_size_combo.set_sensitive (true);
1074 EngineControl::driver_changed ()
1076 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1079 backend->set_driver (driver_combo.get_active_text());
1082 if (!ignore_changes) {
1083 maybe_display_saved_state ();
1088 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1090 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1095 if (_have_control) {
1096 sr = backend->available_sample_rates (device_name);
1099 sr.push_back (8000.0f);
1100 sr.push_back (16000.0f);
1101 sr.push_back (32000.0f);
1102 sr.push_back (44100.0f);
1103 sr.push_back (48000.0f);
1104 sr.push_back (88200.0f);
1105 sr.push_back (96000.0f);
1106 sr.push_back (192000.0f);
1107 sr.push_back (384000.0f);
1110 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1111 s.push_back (rate_as_string (*x));
1112 if (*x == _desired_sample_rate) {
1118 sample_rate_combo.set_sensitive (true);
1119 set_popdown_strings (sample_rate_combo, s);
1121 if (desired.empty()) {
1122 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1124 sample_rate_combo.set_active_text (desired);
1128 sample_rate_combo.set_sensitive (false);
1133 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1135 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1136 vector<uint32_t> bs;
1139 if (_have_control) {
1140 bs = backend->available_buffer_sizes (device_name);
1141 } else if (backend->can_change_buffer_size_when_running()) {
1149 bs.push_back (1024);
1150 bs.push_back (2048);
1151 bs.push_back (4096);
1152 bs.push_back (8192);
1155 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1156 s.push_back (bufsize_as_string (*x));
1160 buffer_size_combo.set_sensitive (true);
1161 set_popdown_strings (buffer_size_combo, s);
1162 buffer_size_combo.set_active_text (s.front());
1164 uint32_t period = backend->buffer_size();
1166 period = backend->default_buffer_size(device_name);
1168 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1169 show_buffer_duration ();
1171 buffer_size_combo.set_sensitive (false);
1176 EngineControl::device_changed ()
1178 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1181 string device_name_in;
1182 string device_name_out; // only used if backend support separate I/O devices
1184 if (backend->use_separate_input_and_output_devices()) {
1185 device_name_in = get_input_device_name ();
1186 device_name_out = get_output_device_name ();
1188 device_name_in = get_device_name ();
1191 /* we set the backend-device to query various device related intormation.
1192 * This has the side effect that backend->device_name() will match
1193 * the device_name and 'change_device' will never be true.
1194 * so work around this by setting...
1196 if (backend->use_separate_input_and_output_devices()) {
1197 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1198 queue_device_changed = true;
1201 if (device_name_in != backend->device_name()) {
1202 queue_device_changed = true;
1206 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1207 if (backend->use_separate_input_and_output_devices()) {
1208 backend->set_input_device_name (device_name_in);
1209 backend->set_output_device_name (device_name_out);
1211 backend->set_device_name(device_name_in);
1215 /* don't allow programmatic change to combos to cause a
1216 recursive call to this method.
1218 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1220 /* backends that support separate devices, need to ignore
1221 * the device-name - and use the devies set above
1223 set_samplerate_popdown_strings (device_name_in);
1224 set_buffersize_popdown_strings (device_name_in);
1225 /* XXX theoretically need to set min + max channel counts here
1228 manage_control_app_sensitivity ();
1231 /* pick up any saved state for this device */
1233 if (!ignore_changes) {
1234 maybe_display_saved_state ();
1239 EngineControl::input_device_changed ()
1241 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1243 string input_device_name = input_device_combo.get_active_text ();
1245 if (!ignore_changes && input_device_name != backend->input_device_name()) {
1246 queue_device_changed = true;
1249 backend->set_input_device_name(input_device_name);
1252 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1254 set_samplerate_popdown_strings (input_device_name);
1255 set_buffersize_popdown_strings (input_device_name);
1256 /* XXX theoretically need to set min + max channel counts here
1259 manage_control_app_sensitivity ();
1262 /* pick up any saved state for this device */
1264 if (!ignore_changes) {
1265 maybe_display_saved_state ();
1270 EngineControl::output_device_changed ()
1272 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1274 string output_device_name = output_device_combo.get_active_text ();
1276 if (!ignore_changes && output_device_name != backend->output_device_name()) {
1277 queue_device_changed = true;
1280 backend->set_output_device_name(output_device_name);
1283 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1285 set_samplerate_popdown_strings (output_device_name);
1286 set_buffersize_popdown_strings (output_device_name);
1287 /* XXX theoretically need to set min + max channel counts here
1290 manage_control_app_sensitivity ();
1293 /* pick up any saved state for this device */
1295 if (!ignore_changes) {
1296 maybe_display_saved_state ();
1301 EngineControl::bufsize_as_string (uint32_t sz)
1303 /* Translators: "samples" is always plural here, so no
1304 need for plural+singular forms.
1307 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1312 EngineControl::sample_rate_changed ()
1314 /* reset the strings for buffer size to show the correct msec value
1315 (reflecting the new sample rate).
1318 show_buffer_duration ();
1323 EngineControl::buffer_size_changed ()
1325 show_buffer_duration ();
1329 EngineControl::show_buffer_duration ()
1332 /* buffer sizes - convert from just samples to samples + msecs for
1333 * the displayed string
1336 string bs_text = buffer_size_combo.get_active_text ();
1337 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1338 uint32_t rate = get_rate();
1340 /* Developers: note the hard-coding of a double buffered model
1341 in the (2 * samples) computation of latency. we always start
1342 the audiobackend in this configuration.
1344 /* note to jack1 developers: ardour also always starts the engine
1345 * in async mode (no jack2 --sync option) which adds an extra cycle
1346 * of latency with jack2 (and *3 would be correct)
1347 * The value can also be wrong if jackd is started externally..
1349 * At the time of writing the ALSA backend always uses double-buffering *2,
1350 * The Dummy backend *1, and who knows what ASIO really does :)
1352 * So just display the period size, that's also what
1353 * ARDOUR_UI::update_sample_rate() does for the status bar.
1354 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1355 * but still, that's the buffer period, not [round-trip] latency)
1358 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1359 buffer_size_duration_label.set_text (buf);
1363 EngineControl::midi_option_changed ()
1365 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1368 backend->set_midi_option (get_midi_option());
1370 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1372 //_midi_devices.clear(); // TODO merge with state-saved settings..
1373 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1374 std::vector<MidiDeviceSettings> new_devices;
1376 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1377 MidiDeviceSettings mds = find_midi_device (i->name);
1378 if (i->available && !mds) {
1379 uint32_t input_latency = 0;
1380 uint32_t output_latency = 0;
1381 if (_can_set_midi_latencies) {
1382 input_latency = backend->systemic_midi_input_latency (i->name);
1383 output_latency = backend->systemic_midi_output_latency (i->name);
1385 bool enabled = backend->midi_device_enabled (i->name);
1386 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1387 new_devices.push_back (ptr);
1388 } else if (i->available) {
1389 new_devices.push_back (mds);
1392 _midi_devices = new_devices;
1394 if (_midi_devices.empty()) {
1395 midi_devices_button.set_sensitive (false);
1397 midi_devices_button.set_sensitive (true);
1402 EngineControl::parameter_changed ()
1406 EngineControl::State
1407 EngineControl::get_matching_state (
1408 const string& backend,
1409 const string& driver,
1410 const string& device)
1412 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1413 if ((*i)->backend == backend &&
1414 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1422 EngineControl::State
1423 EngineControl::get_matching_state (
1424 const string& backend,
1425 const string& driver,
1426 const string& input_device,
1427 const string& output_device)
1429 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1430 if ((*i)->backend == backend &&
1431 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1439 EngineControl::State
1440 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1442 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1445 if (backend->use_separate_input_and_output_devices ()) {
1446 return get_matching_state (backend_combo.get_active_text(),
1447 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1448 input_device_combo.get_active_text(),
1449 output_device_combo.get_active_text());
1451 return get_matching_state (backend_combo.get_active_text(),
1452 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1453 device_combo.get_active_text());
1457 return get_matching_state (backend_combo.get_active_text(),
1459 device_combo.get_active_text());
1462 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1463 const EngineControl::State& state2)
1465 if (state1->backend == state2->backend &&
1466 state1->driver == state2->driver &&
1467 state1->device == state2->device &&
1468 state1->input_device == state2->input_device &&
1469 state1->output_device == state2->output_device) {
1475 EngineControl::State
1476 EngineControl::save_state ()
1480 if (!_have_control) {
1481 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1485 state.reset(new StateStruct);
1486 state->backend = get_backend ();
1488 state.reset(new StateStruct);
1489 store_state (state);
1492 for (StateList::iterator i = states.begin(); i != states.end();) {
1493 if (equivalent_states (*i, state)) {
1494 i = states.erase(i);
1500 states.push_back (state);
1506 EngineControl::store_state (State state)
1508 state->backend = get_backend ();
1509 state->driver = get_driver ();
1510 state->device = get_device_name ();
1511 state->input_device = get_input_device_name ();
1512 state->output_device = get_output_device_name ();
1513 state->sample_rate = get_rate ();
1514 state->buffer_size = get_buffer_size ();
1515 state->input_latency = get_input_latency ();
1516 state->output_latency = get_output_latency ();
1517 state->input_channels = get_input_channels ();
1518 state->output_channels = get_output_channels ();
1519 state->midi_option = get_midi_option ();
1520 state->midi_devices = _midi_devices;
1524 EngineControl::maybe_display_saved_state ()
1526 if (!_have_control) {
1530 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1533 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1535 if (!_desired_sample_rate) {
1536 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1538 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1539 /* call this explicitly because we're ignoring changes to
1540 the controls at this point.
1542 show_buffer_duration ();
1543 input_latency.set_value (state->input_latency);
1544 output_latency.set_value (state->output_latency);
1546 if (!state->midi_option.empty()) {
1547 midi_option_combo.set_active_text (state->midi_option);
1548 _midi_devices = state->midi_devices;
1554 EngineControl::get_state ()
1556 LocaleGuard lg (X_("C"));
1558 XMLNode* root = new XMLNode ("AudioMIDISetup");
1561 if (!states.empty()) {
1562 XMLNode* state_nodes = new XMLNode ("EngineStates");
1564 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1566 XMLNode* node = new XMLNode ("State");
1568 node->add_property ("backend", (*i)->backend);
1569 node->add_property ("driver", (*i)->driver);
1570 node->add_property ("device", (*i)->device);
1571 node->add_property ("input-device", (*i)->input_device);
1572 node->add_property ("output-device", (*i)->output_device);
1573 node->add_property ("sample-rate", (*i)->sample_rate);
1574 node->add_property ("buffer-size", (*i)->buffer_size);
1575 node->add_property ("input-latency", (*i)->input_latency);
1576 node->add_property ("output-latency", (*i)->output_latency);
1577 node->add_property ("input-channels", (*i)->input_channels);
1578 node->add_property ("output-channels", (*i)->output_channels);
1579 node->add_property ("active", (*i)->active ? "yes" : "no");
1580 node->add_property ("midi-option", (*i)->midi_option);
1582 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1583 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1584 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1585 midi_device_stuff->add_property (X_("name"), (*p)->name);
1586 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1587 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1588 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1589 midi_devices->add_child_nocopy (*midi_device_stuff);
1591 node->add_child_nocopy (*midi_devices);
1593 state_nodes->add_child_nocopy (*node);
1596 root->add_child_nocopy (*state_nodes);
1603 EngineControl::set_state (const XMLNode& root)
1605 XMLNodeList clist, cclist;
1606 XMLNodeConstIterator citer, cciter;
1608 XMLNode* grandchild;
1609 XMLProperty* prop = NULL;
1611 fprintf (stderr, "EngineControl::set_state\n");
1613 if (root.name() != "AudioMIDISetup") {
1617 clist = root.children();
1621 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1625 if (child->name() != "EngineStates") {
1629 cclist = child->children();
1631 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1632 State state (new StateStruct);
1634 grandchild = *cciter;
1636 if (grandchild->name() != "State") {
1640 if ((prop = grandchild->property ("backend")) == 0) {
1643 state->backend = prop->value ();
1645 if ((prop = grandchild->property ("driver")) == 0) {
1648 state->driver = prop->value ();
1650 if ((prop = grandchild->property ("device")) == 0) {
1653 state->device = prop->value ();
1655 if ((prop = grandchild->property ("input-device")) == 0) {
1658 state->input_device = prop->value ();
1660 if ((prop = grandchild->property ("output-device")) == 0) {
1663 state->output_device = prop->value ();
1665 if ((prop = grandchild->property ("sample-rate")) == 0) {
1668 state->sample_rate = atof (prop->value ());
1670 if ((prop = grandchild->property ("buffer-size")) == 0) {
1673 state->buffer_size = atoi (prop->value ());
1675 if ((prop = grandchild->property ("input-latency")) == 0) {
1678 state->input_latency = atoi (prop->value ());
1680 if ((prop = grandchild->property ("output-latency")) == 0) {
1683 state->output_latency = atoi (prop->value ());
1685 if ((prop = grandchild->property ("input-channels")) == 0) {
1688 state->input_channels = atoi (prop->value ());
1690 if ((prop = grandchild->property ("output-channels")) == 0) {
1693 state->output_channels = atoi (prop->value ());
1695 if ((prop = grandchild->property ("active")) == 0) {
1698 state->active = string_is_affirmative (prop->value ());
1700 if ((prop = grandchild->property ("midi-option")) == 0) {
1703 state->midi_option = prop->value ();
1705 state->midi_devices.clear();
1707 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1708 const XMLNodeList mnc = midinode->children();
1709 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1710 if ((*n)->property (X_("name")) == 0
1711 || (*n)->property (X_("enabled")) == 0
1712 || (*n)->property (X_("input-latency")) == 0
1713 || (*n)->property (X_("output-latency")) == 0
1718 MidiDeviceSettings ptr (new MidiDeviceSetting(
1719 (*n)->property (X_("name"))->value (),
1720 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1721 atoi ((*n)->property (X_("input-latency"))->value ()),
1722 atoi ((*n)->property (X_("output-latency"))->value ())
1724 state->midi_devices.push_back (ptr);
1729 /* remove accumulated duplicates (due to bug in ealier version)
1730 * this can be removed again before release
1732 for (StateList::iterator i = states.begin(); i != states.end();) {
1733 if ((*i)->backend == state->backend &&
1734 (*i)->driver == state->driver &&
1735 (*i)->device == state->device) {
1736 i = states.erase(i);
1743 states.push_back (state);
1747 /* now see if there was an active state and switch the setup to it */
1749 // purge states of backend that are not available in this built
1750 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1751 vector<std::string> backend_names;
1753 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1754 backend_names.push_back((*i)->name);
1756 for (StateList::iterator i = states.begin(); i != states.end();) {
1757 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1758 i = states.erase(i);
1764 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1767 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1768 backend_combo.set_active_text ((*i)->backend);
1770 /* The driver popdown strings need to be populated now so that
1771 * set_active_text will actually set a valid entry. Then
1772 * backend_changed() will populate all the other combo's so they
1773 * can also be set to valid entries and the state will be restored
1776 if (!(*i)->driver.empty()) {
1777 set_driver_popdown_strings ();
1779 driver_combo.set_active_text ((*i)->driver);
1782 device_combo.set_active_text ((*i)->device);
1783 input_device_combo.set_active_text ((*i)->input_device);
1784 output_device_combo.set_active_text ((*i)->output_device);
1785 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1786 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1787 input_latency.set_value ((*i)->input_latency);
1788 output_latency.set_value ((*i)->output_latency);
1789 midi_option_combo.set_active_text ((*i)->midi_option);
1796 EngineControl::push_state_to_backend (bool start)
1798 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1804 /* figure out what is going to change */
1806 bool restart_required = false;
1807 bool was_running = ARDOUR::AudioEngine::instance()->running();
1808 bool change_driver = false;
1809 bool change_device = false;
1810 bool change_rate = false;
1811 bool change_bufsize = false;
1812 bool change_latency = false;
1813 bool change_channels = false;
1814 bool change_midi = false;
1816 uint32_t ochan = get_output_channels ();
1817 uint32_t ichan = get_input_channels ();
1819 if (_have_control) {
1821 if (started_at_least_once) {
1823 /* we can control the backend */
1825 if (backend->requires_driver_selection()) {
1826 if (get_driver() != backend->driver_name()) {
1827 change_driver = true;
1831 if (backend->use_separate_input_and_output_devices()) {
1832 if (get_input_device_name() != backend->input_device_name()) {
1833 change_device = true;
1835 if (get_output_device_name() != backend->output_device_name()) {
1836 change_device = true;
1839 if (get_device_name() != backend->device_name()) {
1840 change_device = true;
1844 if (queue_device_changed) {
1845 change_device = true;
1848 if (get_rate() != backend->sample_rate()) {
1852 if (get_buffer_size() != backend->buffer_size()) {
1853 change_bufsize = true;
1856 if (get_midi_option() != backend->midi_option()) {
1860 /* zero-requested channels means "all available" */
1863 ichan = backend->input_channels();
1867 ochan = backend->output_channels();
1870 if (ichan != backend->input_channels()) {
1871 change_channels = true;
1874 if (ochan != backend->output_channels()) {
1875 change_channels = true;
1878 if (get_input_latency() != backend->systemic_input_latency() ||
1879 get_output_latency() != backend->systemic_output_latency()) {
1880 change_latency = true;
1883 /* backend never started, so we have to force a group
1886 change_device = true;
1887 if (backend->requires_driver_selection()) {
1888 change_driver = true;
1891 change_bufsize = true;
1892 change_channels = true;
1893 change_latency = true;
1899 /* we have no control over the backend, meaning that we can
1900 * only possibly change sample rate and buffer size.
1904 if (get_rate() != backend->sample_rate()) {
1905 change_bufsize = true;
1908 if (get_buffer_size() != backend->buffer_size()) {
1909 change_bufsize = true;
1913 queue_device_changed = false;
1915 if (!_have_control) {
1917 /* We do not have control over the backend, so the best we can
1918 * do is try to change the sample rate and/or bufsize and get
1922 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1926 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1931 backend->set_sample_rate (get_rate());
1934 if (change_bufsize) {
1935 backend->set_buffer_size (get_buffer_size());
1939 if (ARDOUR::AudioEngine::instance()->start ()) {
1940 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1950 /* determine if we need to stop the backend before changing parameters */
1952 if (change_driver || change_device || change_channels || change_latency ||
1953 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1955 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1956 restart_required = true;
1958 restart_required = false;
1963 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1964 /* no changes in any parameters that absolutely require a
1965 * restart, so check those that might be changeable without a
1969 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1970 /* can't do this while running ... */
1971 restart_required = true;
1974 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1975 /* can't do this while running ... */
1976 restart_required = true;
1982 if (restart_required) {
1983 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1990 if (change_driver && backend->set_driver (get_driver())) {
1991 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1994 if (backend->use_separate_input_and_output_devices()) {
1995 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1996 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1999 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2000 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2004 if (change_device && backend->set_device_name (get_device_name())) {
2005 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2009 if (change_rate && backend->set_sample_rate (get_rate())) {
2010 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2013 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2014 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2018 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2019 if (backend->set_input_channels (get_input_channels())) {
2020 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2023 if (backend->set_output_channels (get_output_channels())) {
2024 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2028 if (change_latency) {
2029 if (backend->set_systemic_input_latency (get_input_latency())) {
2030 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2033 if (backend->set_systemic_output_latency (get_output_latency())) {
2034 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2040 backend->set_midi_option (get_midi_option());
2044 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2045 if (_measure_midi) {
2046 if (*p == _measure_midi) {
2047 backend->set_midi_device_enabled ((*p)->name, true);
2049 backend->set_midi_device_enabled ((*p)->name, false);
2053 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2054 if (backend->can_set_systemic_midi_latencies()) {
2055 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2056 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2061 if (start || (was_running && restart_required)) {
2062 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2073 EngineControl::post_push ()
2075 /* get a pointer to the current state object, creating one if
2079 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2082 state = save_state ();
2090 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2091 (*i)->active = false;
2094 /* mark this one active (to be used next time the dialog is
2098 state->active = true;
2100 if (_have_control) { // XXX
2101 manage_control_app_sensitivity ();
2104 /* schedule a redisplay of MIDI ports */
2105 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2110 EngineControl::get_rate () const
2112 float r = atof (sample_rate_combo.get_active_text ());
2113 /* the string may have been translated with an abbreviation for
2114 * thousands, so use a crude heuristic to fix this.
2124 EngineControl::get_buffer_size () const
2126 string txt = buffer_size_combo.get_active_text ();
2129 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2130 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2131 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2139 EngineControl::get_midi_option () const
2141 return midi_option_combo.get_active_text();
2145 EngineControl::get_input_channels() const
2147 if (ARDOUR::Profile->get_mixbus()) {
2148 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2149 if (!backend) return 0;
2150 return backend->input_channels();
2152 return (uint32_t) input_channels_adjustment.get_value();
2156 EngineControl::get_output_channels() const
2158 if (ARDOUR::Profile->get_mixbus()) {
2159 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2160 if (!backend) return 0;
2161 return backend->input_channels();
2163 return (uint32_t) output_channels_adjustment.get_value();
2167 EngineControl::get_input_latency() const
2169 return (uint32_t) input_latency_adjustment.get_value();
2173 EngineControl::get_output_latency() const
2175 return (uint32_t) output_latency_adjustment.get_value();
2179 EngineControl::get_backend () const
2181 return backend_combo.get_active_text ();
2185 EngineControl::get_driver () const
2187 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2188 return driver_combo.get_active_text ();
2195 EngineControl::get_device_name () const
2197 return device_combo.get_active_text ();
2201 EngineControl::get_input_device_name () const
2203 return input_device_combo.get_active_text ();
2207 EngineControl::get_output_device_name () const
2209 return output_device_combo.get_active_text ();
2213 EngineControl::control_app_button_clicked ()
2215 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2221 backend->launch_control_app ();
2225 EngineControl::manage_control_app_sensitivity ()
2227 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2233 string appname = backend->control_app_name();
2235 if (appname.empty()) {
2236 control_app_button.set_sensitive (false);
2238 control_app_button.set_sensitive (true);
2243 EngineControl::set_desired_sample_rate (uint32_t sr)
2245 _desired_sample_rate = sr;
2247 input_device_changed ();
2248 output_device_changed ();
2252 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2254 if (page_num == 0) {
2255 cancel_button->set_sensitive (true);
2256 ok_button->set_sensitive (true);
2257 apply_button->set_sensitive (true);
2258 _measure_midi.reset();
2260 cancel_button->set_sensitive (false);
2261 ok_button->set_sensitive (false);
2262 apply_button->set_sensitive (false);
2265 if (page_num == midi_tab) {
2267 refresh_midi_display ();
2270 if (page_num == latency_tab) {
2273 if (ARDOUR::AudioEngine::instance()->running()) {
2274 // TODO - mark as 'stopped for latency
2275 ARDOUR_UI::instance()->disconnect_from_engine ();
2279 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2281 /* save any existing latency values */
2283 uint32_t il = (uint32_t) input_latency.get_value ();
2284 uint32_t ol = (uint32_t) input_latency.get_value ();
2286 /* reset to zero so that our new test instance
2287 will be clean of any existing latency measures.
2289 NB. this should really be done by the backend
2290 when stated for latency measurement.
2293 input_latency.set_value (0);
2294 output_latency.set_value (0);
2296 push_state_to_backend (false);
2300 input_latency.set_value (il);
2301 output_latency.set_value (ol);
2304 // This should be done in push_state_to_backend()
2305 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2306 disable_latency_tab ();
2309 enable_latency_tab ();
2313 end_latency_detection ();
2314 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2319 /* latency measurement */
2322 EngineControl::check_audio_latency_measurement ()
2324 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2326 if (mtdm->resolve () < 0) {
2327 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2331 if (mtdm->err () > 0.3) {
2337 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2339 if (sample_rate == 0) {
2340 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2341 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2345 int frames_total = mtdm->del();
2346 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2348 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2349 _("Detected roundtrip latency: "),
2350 frames_total, frames_total * 1000.0f/sample_rate,
2351 _("Systemic latency: "),
2352 extra, extra * 1000.0f/sample_rate);
2356 if (mtdm->err () > 0.2) {
2358 strcat (buf, _("(signal detection error)"));
2364 strcat (buf, _("(inverted - bad wiring)"));
2368 lm_results.set_markup (string_compose (results_markup, buf));
2371 have_lm_results = true;
2372 end_latency_detection ();
2373 lm_use_button.set_sensitive (true);
2381 EngineControl::check_midi_latency_measurement ()
2383 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2385 if (!mididm->have_signal () || mididm->latency () == 0) {
2386 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2391 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2393 if (sample_rate == 0) {
2394 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2395 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2399 ARDOUR::framecnt_t frames_total = mididm->latency();
2400 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2401 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2402 _("Detected roundtrip latency: "),
2403 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2404 _("Systemic latency: "),
2405 extra, extra * 1000.0f / sample_rate);
2409 if (!mididm->ok ()) {
2411 strcat (buf, _("(averaging)"));
2415 if (mididm->deviation () > 50.0) {
2417 strcat (buf, _("(too large jitter)"));
2419 } else if (mididm->deviation () > 10.0) {
2421 strcat (buf, _("(large jitter)"));
2425 have_lm_results = true;
2426 end_latency_detection ();
2427 lm_use_button.set_sensitive (true);
2428 lm_results.set_markup (string_compose (results_markup, buf));
2430 } else if (mididm->processed () > 400) {
2431 have_lm_results = false;
2432 end_latency_detection ();
2433 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2437 lm_results.set_markup (string_compose (results_markup, buf));
2443 EngineControl::start_latency_detection ()
2445 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2446 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2448 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2449 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2450 if (_measure_midi) {
2451 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2453 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2455 lm_measure_label.set_text (_("Cancel"));
2456 have_lm_results = false;
2457 lm_use_button.set_sensitive (false);
2458 lm_input_channel_combo.set_sensitive (false);
2459 lm_output_channel_combo.set_sensitive (false);
2465 EngineControl::end_latency_detection ()
2467 latency_timeout.disconnect ();
2468 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2469 lm_measure_label.set_text (_("Measure"));
2470 if (!have_lm_results) {
2471 lm_use_button.set_sensitive (false);
2473 lm_input_channel_combo.set_sensitive (true);
2474 lm_output_channel_combo.set_sensitive (true);
2479 EngineControl::latency_button_clicked ()
2482 start_latency_detection ();
2484 end_latency_detection ();
2489 EngineControl::use_latency_button_clicked ()
2491 if (_measure_midi) {
2492 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2496 ARDOUR::framecnt_t frames_total = mididm->latency();
2497 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2498 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2499 _measure_midi->input_latency = one_way;
2500 _measure_midi->output_latency = one_way;
2501 notebook.set_current_page (midi_tab);
2503 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2509 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2510 one_way = std::max (0., one_way);
2512 input_latency_adjustment.set_value (one_way);
2513 output_latency_adjustment.set_value (one_way);
2515 /* back to settings page */
2516 notebook.set_current_page (0);
2522 EngineControl::on_delete_event (GdkEventAny* ev)
2524 if (notebook.get_current_page() == 2) {
2525 /* currently on latency tab - be sure to clean up */
2526 end_latency_detection ();
2528 return ArdourDialog::on_delete_event (ev);
2532 EngineControl::engine_running ()
2534 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2537 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2538 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2540 buffer_size_combo.set_sensitive (true);
2541 sample_rate_combo.set_sensitive (true);
2543 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2544 connect_disconnect_button.show();
2546 started_at_least_once = true;
2547 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2551 EngineControl::engine_stopped ()
2553 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2556 buffer_size_combo.set_sensitive (false);
2557 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2558 connect_disconnect_button.show();
2560 sample_rate_combo.set_sensitive (true);
2561 buffer_size_combo.set_sensitive (true);
2562 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2566 EngineControl::device_list_changed ()
2568 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2570 midi_option_changed();
2574 EngineControl::connect_disconnect_click()
2576 if (ARDOUR::AudioEngine::instance()->running()) {
2577 ARDOUR_UI::instance()->disconnect_from_engine ();
2579 ARDOUR_UI::instance()->reconnect_to_engine ();
2584 EngineControl::calibrate_audio_latency ()
2586 _measure_midi.reset ();
2587 have_lm_results = false;
2588 lm_use_button.set_sensitive (false);
2589 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2590 notebook.set_current_page (latency_tab);
2594 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2597 have_lm_results = false;
2598 lm_use_button.set_sensitive (false);
2599 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2600 notebook.set_current_page (latency_tab);
2604 EngineControl::configure_midi_devices ()
2606 notebook.set_current_page (midi_tab);