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 xopt = AttachOptions(0);
181 lm_measure_label.set_padding (10, 10);
182 lm_measure_button.add (lm_measure_label);
183 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
184 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
185 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
187 lm_use_button.set_sensitive (false);
189 /* Increase the default spacing around the labels of these three
195 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
196 l->set_padding (10, 10);
199 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
200 l->set_padding (10, 10);
203 preamble = manage (new Label);
204 preamble->set_width_chars (60);
205 preamble->set_line_wrap (true);
206 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
207 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
210 preamble = manage (new Label);
211 preamble->set_width_chars (60);
212 preamble->set_line_wrap (true);
213 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
214 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
216 ++row; // skip a row in the table
217 ++row; // skip a row in the table
219 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
221 ++row; // skip a row in the table
222 ++row; // skip a row in the table
224 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
230 lm_vbox.set_border_width (12);
231 lm_vbox.pack_start (lm_table, false, false);
233 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
237 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
238 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
239 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
240 notebook.set_border_width (12);
242 notebook.set_show_tabs (false);
243 notebook.show_all ();
245 notebook.set_name ("SettingsNotebook");
247 /* packup the notebook */
249 get_vbox()->set_border_width (12);
250 get_vbox()->pack_start (notebook);
252 get_action_area()->pack_start (engine_status);
253 engine_status.show();
255 /* need a special function to print "all available channels" when the
256 * channel counts hit zero.
259 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
260 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
262 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
263 midi_devices_button.set_sensitive (false);
264 midi_devices_button.set_name ("generic button");
265 midi_devices_button.set_can_focus(true);
267 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
268 manage_control_app_sensitivity ();
270 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
271 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
272 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
274 /* Pick up any existing audio setup configuration, if appropriate */
276 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
278 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
279 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
280 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
281 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
284 set_state (*audio_setup);
287 if (backend_combo.get_active_text().empty()) {
288 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
289 backend_combo.set_active_text (backend_names.front());
294 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
295 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
296 backend_combo.set_active_text (backend_names.back());
297 /* ignore: don't save state */
298 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
303 /* Connect to signals */
305 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
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_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::input_device_changed));
313 output_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::output_device_changed));
315 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
316 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
317 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
318 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
320 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
322 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
323 connect_disconnect_button.set_no_show_all();
328 EngineControl::on_show ()
330 ArdourDialog::on_show ();
331 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
332 // re-check _have_control (jackd running) see #6041
336 input_device_changed ();
337 output_device_changed ();
338 ok_button->grab_focus();
342 EngineControl::on_response (int response_id)
344 ArdourDialog::on_response (response_id);
346 switch (response_id) {
348 push_state_to_backend (true);
351 #ifdef PLATFORM_WINDOWS
352 // For some reason we don't understand, 'hide()'
353 // needs to get called first in Windows
356 // But if there's no session open, this can produce
357 // a long gap when nothing appears to be happening.
358 // Let's show the splash image while we're waiting.
359 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
360 if ( ARDOUR_UI::instance() ) {
361 if ( !ARDOUR_UI::instance()->session_loaded ) {
362 ARDOUR_UI::instance()->show_splash();
366 push_state_to_backend (true);
369 push_state_to_backend (true);
373 case RESPONSE_DELETE_EVENT:
376 ev.type = GDK_BUTTON_PRESS;
378 on_delete_event ((GdkEventAny*) &ev);
387 EngineControl::build_notebook ()
390 AttachOptions xopt = AttachOptions (FILL|EXPAND);
392 /* clear the table */
394 Gtkmm2ext::container_clear (basic_vbox);
395 Gtkmm2ext::container_clear (basic_packer);
397 if (control_app_button.get_parent()) {
398 control_app_button.get_parent()->remove (control_app_button);
401 label = manage (left_aligned_label (_("Audio System:")));
402 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
403 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
405 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
406 lm_button_audio.set_name ("generic button");
407 lm_button_audio.set_can_focus(true);
410 build_full_control_notebook ();
412 build_no_control_notebook ();
415 basic_vbox.pack_start (basic_hbox, false, false);
418 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
419 basic_vbox.show_all ();
424 EngineControl::build_full_control_notebook ()
426 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
429 using namespace Notebook_Helpers;
431 vector<string> strings;
432 AttachOptions xopt = AttachOptions (FILL|EXPAND);
433 int row = 1; // row zero == backend combo
435 /* start packing it up */
437 if (backend->requires_driver_selection()) {
438 label = manage (left_aligned_label (_("Driver:")));
439 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
440 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
444 if (backend->use_separate_input_and_output_devices()) {
445 label = manage (left_aligned_label (_("Input Device:")));
446 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
447 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
449 label = manage (left_aligned_label (_("Output Device:")));
450 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
451 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
453 // reset so it isn't used in state comparisons
454 device_combo.set_active_text ("");
456 label = manage (left_aligned_label (_("Device:")));
457 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
458 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
460 // reset these so they don't get used in state comparisons
461 input_device_combo.set_active_text ("");
462 output_device_combo.set_active_text ("");
465 label = manage (left_aligned_label (_("Sample rate:")));
466 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
467 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
471 label = manage (left_aligned_label (_("Buffer size:")));
472 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
473 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
474 buffer_size_duration_label.set_alignment (0.0); /* left-align */
475 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
477 /* button spans 2 rows */
479 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
482 input_channels.set_name ("InputChannels");
483 input_channels.set_flags (Gtk::CAN_FOCUS);
484 input_channels.set_digits (0);
485 input_channels.set_wrap (false);
486 output_channels.set_editable (true);
488 if (!ARDOUR::Profile->get_mixbus()) {
489 label = manage (left_aligned_label (_("Input Channels:")));
490 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
491 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
495 output_channels.set_name ("OutputChannels");
496 output_channels.set_flags (Gtk::CAN_FOCUS);
497 output_channels.set_digits (0);
498 output_channels.set_wrap (false);
499 output_channels.set_editable (true);
501 if (!ARDOUR::Profile->get_mixbus()) {
502 label = manage (left_aligned_label (_("Output Channels:")));
503 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
504 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
508 input_latency.set_name ("InputLatency");
509 input_latency.set_flags (Gtk::CAN_FOCUS);
510 input_latency.set_digits (0);
511 input_latency.set_wrap (false);
512 input_latency.set_editable (true);
514 label = manage (left_aligned_label (_("Hardware input latency:")));
515 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
516 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
517 label = manage (left_aligned_label (_("samples")));
518 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
521 output_latency.set_name ("OutputLatency");
522 output_latency.set_flags (Gtk::CAN_FOCUS);
523 output_latency.set_digits (0);
524 output_latency.set_wrap (false);
525 output_latency.set_editable (true);
527 label = manage (left_aligned_label (_("Hardware output latency:")));
528 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
529 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
530 label = manage (left_aligned_label (_("samples")));
531 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
533 /* button spans 2 rows */
535 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
538 label = manage (left_aligned_label (_("MIDI System:")));
539 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
540 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
541 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
546 EngineControl::build_no_control_notebook ()
548 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
551 using namespace Notebook_Helpers;
553 vector<string> strings;
554 AttachOptions xopt = AttachOptions (FILL|EXPAND);
555 int row = 1; // row zero == backend combo
556 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
558 label = manage (new Label);
559 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
560 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
563 if (backend->can_change_sample_rate_when_running()) {
564 label = manage (left_aligned_label (_("Sample rate:")));
565 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
566 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
570 if (backend->can_change_buffer_size_when_running()) {
571 label = manage (left_aligned_label (_("Buffer size:")));
572 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
573 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
574 buffer_size_duration_label.set_alignment (0.0); /* left-align */
575 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
579 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
583 EngineControl::~EngineControl ()
585 ignore_changes = true;
589 EngineControl::disable_latency_tab ()
591 vector<string> empty;
592 set_popdown_strings (lm_output_channel_combo, empty);
593 set_popdown_strings (lm_input_channel_combo, empty);
594 lm_measure_button.set_sensitive (false);
595 lm_use_button.set_sensitive (false);
599 EngineControl::enable_latency_tab ()
601 vector<string> outputs;
602 vector<string> inputs;
604 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
605 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
606 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
608 if (!ARDOUR::AudioEngine::instance()->running()) {
609 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
610 notebook.set_current_page (0);
614 else if (inputs.empty() || outputs.empty()) {
615 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
616 notebook.set_current_page (0);
621 lm_back_button_signal.disconnect();
623 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
626 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
630 set_popdown_strings (lm_output_channel_combo, outputs);
631 lm_output_channel_combo.set_active_text (outputs.front());
632 lm_output_channel_combo.set_sensitive (true);
634 set_popdown_strings (lm_input_channel_combo, inputs);
635 lm_input_channel_combo.set_active_text (inputs.front());
636 lm_input_channel_combo.set_sensitive (true);
638 lm_measure_button.set_sensitive (true);
642 EngineControl::setup_midi_tab_for_backend ()
644 string backend = backend_combo.get_active_text ();
646 Gtkmm2ext::container_clear (midi_vbox);
648 midi_vbox.set_border_width (12);
649 midi_device_table.set_border_width (12);
651 if (backend == "JACK") {
652 setup_midi_tab_for_jack ();
655 midi_vbox.pack_start (midi_device_table, true, true);
656 midi_vbox.pack_start (midi_back_button, false, false);
657 midi_vbox.show_all ();
661 EngineControl::setup_midi_tab_for_jack ()
666 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
668 device->input_latency = a->get_value();
670 device->output_latency = a->get_value();
675 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
676 b->set_active (!b->get_active());
677 device->enabled = b->get_active();
678 refresh_midi_display(device->name);
682 EngineControl::refresh_midi_display (std::string focus)
684 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
688 AttachOptions xopt = AttachOptions (FILL|EXPAND);
691 Gtkmm2ext::container_clear (midi_device_table);
693 midi_device_table.set_spacings (6);
695 l = manage (new Label);
696 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
697 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
698 l->set_alignment (0.5, 0.5);
702 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
703 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
704 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
705 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
707 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
708 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
709 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
710 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
713 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
718 bool enabled = (*p)->enabled;
720 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
721 m->set_name ("midi device");
722 m->set_can_focus (Gtk::CAN_FOCUS);
723 m->add_events (Gdk::BUTTON_RELEASE_MASK);
724 m->set_active (enabled);
725 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
726 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
727 if ((*p)->name == focus) {
731 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
732 s = manage (new Gtk::SpinButton (*a));
733 a->set_value ((*p)->input_latency);
734 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
735 s->set_sensitive (_can_set_midi_latencies && enabled);
736 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
738 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
739 s = manage (new Gtk::SpinButton (*a));
740 a->set_value ((*p)->output_latency);
741 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
742 s->set_sensitive (_can_set_midi_latencies && enabled);
743 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
745 b = manage (new Button (_("Calibrate")));
746 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
747 b->set_sensitive (_can_set_midi_latencies && enabled);
748 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
755 EngineControl::update_sensitivity ()
760 EngineControl::backend_changed ()
762 string backend_name = backend_combo.get_active_text();
763 boost::shared_ptr<ARDOUR::AudioBackend> backend;
765 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
766 /* eh? setting the backend failed... how ? */
767 /* A: stale config contains a backend that does not exist in current build */
771 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
774 setup_midi_tab_for_backend ();
775 _midi_devices.clear();
777 if (backend->requires_driver_selection()) {
778 vector<string> drivers = backend->enumerate_drivers();
779 driver_combo.set_sensitive (true);
781 if (!drivers.empty()) {
783 string current_driver;
784 current_driver = backend->driver_name ();
786 // driver might not have been set yet
787 if (current_driver == "") {
788 current_driver = driver_combo.get_active_text ();
789 if (current_driver == "")
790 // driver has never been set, make sure it's not blank
791 current_driver = drivers.front ();
794 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
795 set_popdown_strings (driver_combo, drivers);
796 driver_combo.set_active_text (current_driver);
803 driver_combo.set_sensitive (false);
804 /* this will change the device text which will cause a call to
805 * device changed which will set up parameters
810 vector<string> midi_options = backend->enumerate_midi_options();
812 if (midi_options.size() == 1) {
813 /* only contains the "none" option */
814 midi_option_combo.set_sensitive (false);
817 set_popdown_strings (midi_option_combo, midi_options);
818 midi_option_combo.set_active_text (midi_options.front());
819 midi_option_combo.set_sensitive (true);
821 midi_option_combo.set_sensitive (false);
825 connect_disconnect_button.hide();
827 midi_option_changed();
829 started_at_least_once = false;
831 if (!ignore_changes) {
832 maybe_display_saved_state ();
837 EngineControl::print_channel_count (Gtk::SpinButton* sb)
839 if (ARDOUR::Profile->get_mixbus()) {
843 uint32_t cnt = (uint32_t) sb->get_value();
845 sb->set_text (_("all available channels"));
848 snprintf (buf, sizeof (buf), "%d", cnt);
855 EngineControl::set_driver_popdown_strings ()
857 string backend_name = backend_combo.get_active_text();
858 boost::shared_ptr<ARDOUR::AudioBackend> backend;
860 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
861 /* eh? setting the backend failed... how ? */
862 /* A: stale config contains a backend that does not exist in current build */
866 vector<string> drivers = backend->enumerate_drivers();
867 set_popdown_strings (driver_combo, drivers);
871 // @return true if there are devices available
873 EngineControl::set_device_popdown_strings ()
875 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
876 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
878 /* NOTE: Ardour currently does not display the "available" field of the
881 * Doing so would require a different GUI widget than the combo
882 * box/popdown that we currently use, since it has no way to list
883 * items that are not selectable. Something more like a popup menu,
884 * which could have unselectable items, would be appropriate.
887 vector<string> available_devices;
889 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
890 available_devices.push_back (i->name);
894 if (!available_devices.empty()) {
895 update_sensitivity ();
898 string current_device, found_device;
899 current_device = device_combo.get_active_text ();
900 if (current_device == "") {
901 current_device = backend->device_name ();
904 // Make sure that the active text is still relevant for this
905 // device (it might only be relevant to the previous device!!)
906 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
907 if (*i == current_device)
908 found_device = current_device;
910 if (found_device == "")
911 // device has never been set (or was not relevant
912 // for this backend) Let's make sure it's not blank
913 current_device = available_devices.front ();
915 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
916 set_popdown_strings (device_combo, available_devices);
918 device_combo.set_active_text (current_device);
927 // @return true if there are input devices available
929 EngineControl::set_input_device_popdown_strings ()
931 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
932 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
934 vector<string> available_devices;
936 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
937 available_devices.push_back (i->name);
940 if (!available_devices.empty()) {
941 update_sensitivity ();
944 string current_device, found_device;
945 current_device = input_device_combo.get_active_text ();
946 if (current_device == "") {
947 current_device = backend->input_device_name ();
950 // Make sure that the active text is still relevant for this
951 // device (it might only be relevant to the previous device!!)
952 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
953 if (*i == current_device)
954 found_device = current_device;
956 if (found_device == "")
957 // device has never been set (or was not relevant
958 // for this backend) Let's make sure it's not blank
959 current_device = available_devices.front ();
961 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
962 set_popdown_strings (input_device_combo, available_devices);
964 input_device_combo.set_active_text (current_device);
967 input_device_changed ();
974 // @return true if there are output devices available
976 EngineControl::set_output_device_popdown_strings ()
978 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
979 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
981 vector<string> available_devices;
983 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
984 available_devices.push_back (i->name);
987 if (!available_devices.empty()) {
988 update_sensitivity ();
991 string current_device, found_device;
992 current_device = output_device_combo.get_active_text ();
993 if (current_device == "") {
994 current_device = backend->output_device_name ();
997 // Make sure that the active text is still relevant for this
998 // device (it might only be relevant to the previous device!!)
999 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
1000 if (*i == current_device)
1001 found_device = current_device;
1003 if (found_device == "")
1004 // device has never been set (or was not relevant
1005 // for this backend) Let's make sure it's not blank
1006 current_device = available_devices.front ();
1008 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1009 set_popdown_strings (output_device_combo, available_devices);
1011 output_device_combo.set_active_text (current_device);
1014 output_device_changed ();
1022 EngineControl::list_devices ()
1024 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1027 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1029 bool devices_available = false;
1031 if (backend->use_separate_input_and_output_devices ()) {
1032 bool input_devices_available = set_input_device_popdown_strings ();
1033 bool output_devices_available = set_output_device_popdown_strings ();
1034 devices_available = input_devices_available || output_devices_available;
1036 devices_available = set_device_popdown_strings ();
1039 if (devices_available) {
1040 input_latency.set_sensitive (true);
1041 output_latency.set_sensitive (true);
1042 input_channels.set_sensitive (true);
1043 output_channels.set_sensitive (true);
1045 ok_button->set_sensitive (true);
1046 apply_button->set_sensitive (true);
1049 device_combo.clear();
1050 input_device_combo.clear();
1051 output_device_combo.clear();
1052 sample_rate_combo.set_sensitive (false);
1053 buffer_size_combo.set_sensitive (false);
1054 input_latency.set_sensitive (false);
1055 output_latency.set_sensitive (false);
1056 input_channels.set_sensitive (false);
1057 output_channels.set_sensitive (false);
1058 if (_have_control) {
1059 ok_button->set_sensitive (false);
1060 apply_button->set_sensitive (false);
1062 ok_button->set_sensitive (true);
1063 apply_button->set_sensitive (true);
1064 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1065 sample_rate_combo.set_sensitive (true);
1067 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1068 buffer_size_combo.set_sensitive (true);
1076 EngineControl::driver_changed ()
1078 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1081 backend->set_driver (driver_combo.get_active_text());
1084 if (!ignore_changes) {
1085 maybe_display_saved_state ();
1090 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1092 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1097 if (_have_control) {
1098 sr = backend->available_sample_rates (device_name);
1101 sr.push_back (8000.0f);
1102 sr.push_back (16000.0f);
1103 sr.push_back (32000.0f);
1104 sr.push_back (44100.0f);
1105 sr.push_back (48000.0f);
1106 sr.push_back (88200.0f);
1107 sr.push_back (96000.0f);
1108 sr.push_back (192000.0f);
1109 sr.push_back (384000.0f);
1112 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1113 s.push_back (rate_as_string (*x));
1114 if (*x == _desired_sample_rate) {
1120 sample_rate_combo.set_sensitive (true);
1121 set_popdown_strings (sample_rate_combo, s);
1123 if (desired.empty()) {
1124 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1126 sample_rate_combo.set_active_text (desired);
1130 sample_rate_combo.set_sensitive (false);
1135 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1137 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1138 vector<uint32_t> bs;
1141 if (_have_control) {
1142 bs = backend->available_buffer_sizes (device_name);
1143 } else if (backend->can_change_buffer_size_when_running()) {
1151 bs.push_back (1024);
1152 bs.push_back (2048);
1153 bs.push_back (4096);
1154 bs.push_back (8192);
1157 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1158 s.push_back (bufsize_as_string (*x));
1162 buffer_size_combo.set_sensitive (true);
1163 set_popdown_strings (buffer_size_combo, s);
1164 buffer_size_combo.set_active_text (s.front());
1166 uint32_t period = backend->buffer_size();
1168 period = backend->default_buffer_size(device_name);
1170 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1171 show_buffer_duration ();
1173 buffer_size_combo.set_sensitive (false);
1178 EngineControl::device_changed ()
1180 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1183 string device_name_in;
1184 string device_name_out; // only used if backend support separate I/O devices
1186 if (backend->use_separate_input_and_output_devices()) {
1187 device_name_in = get_input_device_name ();
1188 device_name_out = get_output_device_name ();
1190 device_name_in = get_device_name ();
1193 /* we set the backend-device to query various device related intormation.
1194 * This has the side effect that backend->device_name() will match
1195 * the device_name and 'change_device' will never be true.
1196 * so work around this by setting...
1198 if (backend->use_separate_input_and_output_devices()) {
1199 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1200 queue_device_changed = true;
1203 if (device_name_in != backend->device_name()) {
1204 queue_device_changed = true;
1208 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1209 if (backend->use_separate_input_and_output_devices()) {
1210 backend->set_input_device_name (device_name_in);
1211 backend->set_output_device_name (device_name_out);
1213 backend->set_device_name(device_name_in);
1217 /* don't allow programmatic change to combos to cause a
1218 recursive call to this method.
1220 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1222 /* backends that support separate devices, need to ignore
1223 * the device-name - and use the devies set above
1225 set_samplerate_popdown_strings (device_name_in);
1226 set_buffersize_popdown_strings (device_name_in);
1227 /* XXX theoretically need to set min + max channel counts here
1230 manage_control_app_sensitivity ();
1233 /* pick up any saved state for this device */
1235 if (!ignore_changes) {
1236 maybe_display_saved_state ();
1241 EngineControl::input_device_changed ()
1243 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1245 string input_device_name = input_device_combo.get_active_text ();
1247 if (!ignore_changes && input_device_name != backend->input_device_name()) {
1248 queue_device_changed = true;
1251 backend->set_input_device_name(input_device_name);
1254 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1256 set_samplerate_popdown_strings (input_device_name);
1257 set_buffersize_popdown_strings (input_device_name);
1258 /* XXX theoretically need to set min + max channel counts here
1261 manage_control_app_sensitivity ();
1264 /* pick up any saved state for this device */
1266 if (!ignore_changes) {
1267 maybe_display_saved_state ();
1272 EngineControl::output_device_changed ()
1274 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1276 string output_device_name = output_device_combo.get_active_text ();
1278 if (!ignore_changes && output_device_name != backend->output_device_name()) {
1279 queue_device_changed = true;
1282 backend->set_output_device_name(output_device_name);
1285 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1287 set_samplerate_popdown_strings (output_device_name);
1288 set_buffersize_popdown_strings (output_device_name);
1289 /* XXX theoretically need to set min + max channel counts here
1292 manage_control_app_sensitivity ();
1295 /* pick up any saved state for this device */
1297 if (!ignore_changes) {
1298 maybe_display_saved_state ();
1303 EngineControl::bufsize_as_string (uint32_t sz)
1305 /* Translators: "samples" is always plural here, so no
1306 need for plural+singular forms.
1309 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1314 EngineControl::sample_rate_changed ()
1316 /* reset the strings for buffer size to show the correct msec value
1317 (reflecting the new sample rate).
1320 show_buffer_duration ();
1325 EngineControl::buffer_size_changed ()
1327 show_buffer_duration ();
1331 EngineControl::show_buffer_duration ()
1334 /* buffer sizes - convert from just samples to samples + msecs for
1335 * the displayed string
1338 string bs_text = buffer_size_combo.get_active_text ();
1339 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1340 uint32_t rate = get_rate();
1342 /* Developers: note the hard-coding of a double buffered model
1343 in the (2 * samples) computation of latency. we always start
1344 the audiobackend in this configuration.
1346 /* note to jack1 developers: ardour also always starts the engine
1347 * in async mode (no jack2 --sync option) which adds an extra cycle
1348 * of latency with jack2 (and *3 would be correct)
1349 * The value can also be wrong if jackd is started externally..
1351 * At the time of writing the ALSA backend always uses double-buffering *2,
1352 * The Dummy backend *1, and who knows what ASIO really does :)
1354 * So just display the period size, that's also what
1355 * ARDOUR_UI::update_sample_rate() does for the status bar.
1356 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1357 * but still, that's the buffer period, not [round-trip] latency)
1360 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1361 buffer_size_duration_label.set_text (buf);
1365 EngineControl::midi_option_changed ()
1367 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1370 backend->set_midi_option (get_midi_option());
1372 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1374 //_midi_devices.clear(); // TODO merge with state-saved settings..
1375 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1376 std::vector<MidiDeviceSettings> new_devices;
1378 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1379 MidiDeviceSettings mds = find_midi_device (i->name);
1380 if (i->available && !mds) {
1381 uint32_t input_latency = 0;
1382 uint32_t output_latency = 0;
1383 if (_can_set_midi_latencies) {
1384 input_latency = backend->systemic_midi_input_latency (i->name);
1385 output_latency = backend->systemic_midi_output_latency (i->name);
1387 bool enabled = backend->midi_device_enabled (i->name);
1388 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1389 new_devices.push_back (ptr);
1390 } else if (i->available) {
1391 new_devices.push_back (mds);
1394 _midi_devices = new_devices;
1396 if (_midi_devices.empty()) {
1397 midi_devices_button.set_sensitive (false);
1399 midi_devices_button.set_sensitive (true);
1404 EngineControl::parameter_changed ()
1408 EngineControl::State
1409 EngineControl::get_matching_state (
1410 const string& backend,
1411 const string& driver,
1412 const string& device)
1414 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1415 if ((*i)->backend == backend &&
1416 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1424 EngineControl::State
1425 EngineControl::get_matching_state (
1426 const string& backend,
1427 const string& driver,
1428 const string& input_device,
1429 const string& output_device)
1431 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1432 if ((*i)->backend == backend &&
1433 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1441 EngineControl::State
1442 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1444 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1447 if (backend->use_separate_input_and_output_devices ()) {
1448 return get_matching_state (backend_combo.get_active_text(),
1449 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1450 input_device_combo.get_active_text(),
1451 output_device_combo.get_active_text());
1453 return get_matching_state (backend_combo.get_active_text(),
1454 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1455 device_combo.get_active_text());
1459 return get_matching_state (backend_combo.get_active_text(),
1461 device_combo.get_active_text());
1464 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1465 const EngineControl::State& state2)
1467 if (state1->backend == state2->backend &&
1468 state1->driver == state2->driver &&
1469 state1->device == state2->device &&
1470 state1->input_device == state2->input_device &&
1471 state1->output_device == state2->output_device) {
1477 EngineControl::State
1478 EngineControl::save_state ()
1482 if (!_have_control) {
1483 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1487 state.reset(new StateStruct);
1488 state->backend = get_backend ();
1490 state.reset(new StateStruct);
1491 store_state (state);
1494 for (StateList::iterator i = states.begin(); i != states.end();) {
1495 if (equivalent_states (*i, state)) {
1496 i = states.erase(i);
1502 states.push_back (state);
1508 EngineControl::store_state (State state)
1510 state->backend = get_backend ();
1511 state->driver = get_driver ();
1512 state->device = get_device_name ();
1513 state->input_device = get_input_device_name ();
1514 state->output_device = get_output_device_name ();
1515 state->sample_rate = get_rate ();
1516 state->buffer_size = get_buffer_size ();
1517 state->input_latency = get_input_latency ();
1518 state->output_latency = get_output_latency ();
1519 state->input_channels = get_input_channels ();
1520 state->output_channels = get_output_channels ();
1521 state->midi_option = get_midi_option ();
1522 state->midi_devices = _midi_devices;
1526 EngineControl::maybe_display_saved_state ()
1528 if (!_have_control) {
1532 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1535 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1537 if (!_desired_sample_rate) {
1538 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1540 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1541 /* call this explicitly because we're ignoring changes to
1542 the controls at this point.
1544 show_buffer_duration ();
1545 input_latency.set_value (state->input_latency);
1546 output_latency.set_value (state->output_latency);
1548 if (!state->midi_option.empty()) {
1549 midi_option_combo.set_active_text (state->midi_option);
1550 _midi_devices = state->midi_devices;
1556 EngineControl::get_state ()
1558 LocaleGuard lg (X_("C"));
1560 XMLNode* root = new XMLNode ("AudioMIDISetup");
1563 if (!states.empty()) {
1564 XMLNode* state_nodes = new XMLNode ("EngineStates");
1566 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1568 XMLNode* node = new XMLNode ("State");
1570 node->add_property ("backend", (*i)->backend);
1571 node->add_property ("driver", (*i)->driver);
1572 node->add_property ("device", (*i)->device);
1573 node->add_property ("input-device", (*i)->input_device);
1574 node->add_property ("output-device", (*i)->output_device);
1575 node->add_property ("sample-rate", (*i)->sample_rate);
1576 node->add_property ("buffer-size", (*i)->buffer_size);
1577 node->add_property ("input-latency", (*i)->input_latency);
1578 node->add_property ("output-latency", (*i)->output_latency);
1579 node->add_property ("input-channels", (*i)->input_channels);
1580 node->add_property ("output-channels", (*i)->output_channels);
1581 node->add_property ("active", (*i)->active ? "yes" : "no");
1582 node->add_property ("midi-option", (*i)->midi_option);
1584 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1585 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1586 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1587 midi_device_stuff->add_property (X_("name"), (*p)->name);
1588 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1589 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1590 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1591 midi_devices->add_child_nocopy (*midi_device_stuff);
1593 node->add_child_nocopy (*midi_devices);
1595 state_nodes->add_child_nocopy (*node);
1598 root->add_child_nocopy (*state_nodes);
1605 EngineControl::set_state (const XMLNode& root)
1607 XMLNodeList clist, cclist;
1608 XMLNodeConstIterator citer, cciter;
1610 XMLNode* grandchild;
1611 XMLProperty* prop = NULL;
1613 fprintf (stderr, "EngineControl::set_state\n");
1615 if (root.name() != "AudioMIDISetup") {
1619 clist = root.children();
1623 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1627 if (child->name() != "EngineStates") {
1631 cclist = child->children();
1633 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1634 State state (new StateStruct);
1636 grandchild = *cciter;
1638 if (grandchild->name() != "State") {
1642 if ((prop = grandchild->property ("backend")) == 0) {
1645 state->backend = prop->value ();
1647 if ((prop = grandchild->property ("driver")) == 0) {
1650 state->driver = prop->value ();
1652 if ((prop = grandchild->property ("device")) == 0) {
1655 state->device = prop->value ();
1657 if ((prop = grandchild->property ("input-device")) == 0) {
1660 state->input_device = prop->value ();
1662 if ((prop = grandchild->property ("output-device")) == 0) {
1665 state->output_device = prop->value ();
1667 if ((prop = grandchild->property ("sample-rate")) == 0) {
1670 state->sample_rate = atof (prop->value ());
1672 if ((prop = grandchild->property ("buffer-size")) == 0) {
1675 state->buffer_size = atoi (prop->value ());
1677 if ((prop = grandchild->property ("input-latency")) == 0) {
1680 state->input_latency = atoi (prop->value ());
1682 if ((prop = grandchild->property ("output-latency")) == 0) {
1685 state->output_latency = atoi (prop->value ());
1687 if ((prop = grandchild->property ("input-channels")) == 0) {
1690 state->input_channels = atoi (prop->value ());
1692 if ((prop = grandchild->property ("output-channels")) == 0) {
1695 state->output_channels = atoi (prop->value ());
1697 if ((prop = grandchild->property ("active")) == 0) {
1700 state->active = string_is_affirmative (prop->value ());
1702 if ((prop = grandchild->property ("midi-option")) == 0) {
1705 state->midi_option = prop->value ();
1707 state->midi_devices.clear();
1709 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1710 const XMLNodeList mnc = midinode->children();
1711 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1712 if ((*n)->property (X_("name")) == 0
1713 || (*n)->property (X_("enabled")) == 0
1714 || (*n)->property (X_("input-latency")) == 0
1715 || (*n)->property (X_("output-latency")) == 0
1720 MidiDeviceSettings ptr (new MidiDeviceSetting(
1721 (*n)->property (X_("name"))->value (),
1722 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1723 atoi ((*n)->property (X_("input-latency"))->value ()),
1724 atoi ((*n)->property (X_("output-latency"))->value ())
1726 state->midi_devices.push_back (ptr);
1731 /* remove accumulated duplicates (due to bug in ealier version)
1732 * this can be removed again before release
1734 for (StateList::iterator i = states.begin(); i != states.end();) {
1735 if ((*i)->backend == state->backend &&
1736 (*i)->driver == state->driver &&
1737 (*i)->device == state->device) {
1738 i = states.erase(i);
1745 states.push_back (state);
1749 /* now see if there was an active state and switch the setup to it */
1751 // purge states of backend that are not available in this built
1752 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1753 vector<std::string> backend_names;
1755 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1756 backend_names.push_back((*i)->name);
1758 for (StateList::iterator i = states.begin(); i != states.end();) {
1759 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1760 i = states.erase(i);
1766 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1769 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1770 backend_combo.set_active_text ((*i)->backend);
1772 /* The driver popdown strings need to be populated now so that
1773 * set_active_text will actually set a valid entry. Then
1774 * backend_changed() will populate all the other combo's so they
1775 * can also be set to valid entries and the state will be restored
1778 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);