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 if (!(*i)->driver.empty()) {
1779 set_driver_popdown_strings ();
1781 driver_combo.set_active_text ((*i)->driver);
1784 device_combo.set_active_text ((*i)->device);
1785 input_device_combo.set_active_text ((*i)->input_device);
1786 output_device_combo.set_active_text ((*i)->output_device);
1787 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1788 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1789 input_latency.set_value ((*i)->input_latency);
1790 output_latency.set_value ((*i)->output_latency);
1791 midi_option_combo.set_active_text ((*i)->midi_option);
1798 EngineControl::push_state_to_backend (bool start)
1800 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1806 /* figure out what is going to change */
1808 bool restart_required = false;
1809 bool was_running = ARDOUR::AudioEngine::instance()->running();
1810 bool change_driver = false;
1811 bool change_device = false;
1812 bool change_rate = false;
1813 bool change_bufsize = false;
1814 bool change_latency = false;
1815 bool change_channels = false;
1816 bool change_midi = false;
1818 uint32_t ochan = get_output_channels ();
1819 uint32_t ichan = get_input_channels ();
1821 if (_have_control) {
1823 if (started_at_least_once) {
1825 /* we can control the backend */
1827 if (backend->requires_driver_selection()) {
1828 if (get_driver() != backend->driver_name()) {
1829 change_driver = true;
1833 if (backend->use_separate_input_and_output_devices()) {
1834 if (get_input_device_name() != backend->input_device_name()) {
1835 change_device = true;
1837 if (get_output_device_name() != backend->output_device_name()) {
1838 change_device = true;
1841 if (get_device_name() != backend->device_name()) {
1842 change_device = true;
1846 if (queue_device_changed) {
1847 change_device = true;
1850 if (get_rate() != backend->sample_rate()) {
1854 if (get_buffer_size() != backend->buffer_size()) {
1855 change_bufsize = true;
1858 if (get_midi_option() != backend->midi_option()) {
1862 /* zero-requested channels means "all available" */
1865 ichan = backend->input_channels();
1869 ochan = backend->output_channels();
1872 if (ichan != backend->input_channels()) {
1873 change_channels = true;
1876 if (ochan != backend->output_channels()) {
1877 change_channels = true;
1880 if (get_input_latency() != backend->systemic_input_latency() ||
1881 get_output_latency() != backend->systemic_output_latency()) {
1882 change_latency = true;
1885 /* backend never started, so we have to force a group
1888 change_device = true;
1889 if (backend->requires_driver_selection()) {
1890 change_driver = true;
1893 change_bufsize = true;
1894 change_channels = true;
1895 change_latency = true;
1901 /* we have no control over the backend, meaning that we can
1902 * only possibly change sample rate and buffer size.
1906 if (get_rate() != backend->sample_rate()) {
1907 change_bufsize = true;
1910 if (get_buffer_size() != backend->buffer_size()) {
1911 change_bufsize = true;
1915 queue_device_changed = false;
1917 if (!_have_control) {
1919 /* We do not have control over the backend, so the best we can
1920 * do is try to change the sample rate and/or bufsize and get
1924 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1928 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1933 backend->set_sample_rate (get_rate());
1936 if (change_bufsize) {
1937 backend->set_buffer_size (get_buffer_size());
1941 if (ARDOUR::AudioEngine::instance()->start ()) {
1942 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1952 /* determine if we need to stop the backend before changing parameters */
1954 if (change_driver || change_device || change_channels || change_latency ||
1955 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1957 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1958 restart_required = true;
1960 restart_required = false;
1965 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1966 /* no changes in any parameters that absolutely require a
1967 * restart, so check those that might be changeable without a
1971 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1972 /* can't do this while running ... */
1973 restart_required = true;
1976 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1977 /* can't do this while running ... */
1978 restart_required = true;
1984 if (restart_required) {
1985 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1992 if (change_driver && backend->set_driver (get_driver())) {
1993 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1996 if (backend->use_separate_input_and_output_devices()) {
1997 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1998 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2001 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2002 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2006 if (change_device && backend->set_device_name (get_device_name())) {
2007 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2011 if (change_rate && backend->set_sample_rate (get_rate())) {
2012 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2015 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2016 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2020 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2021 if (backend->set_input_channels (get_input_channels())) {
2022 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2025 if (backend->set_output_channels (get_output_channels())) {
2026 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2030 if (change_latency) {
2031 if (backend->set_systemic_input_latency (get_input_latency())) {
2032 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2035 if (backend->set_systemic_output_latency (get_output_latency())) {
2036 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2042 backend->set_midi_option (get_midi_option());
2046 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2047 if (_measure_midi) {
2048 if (*p == _measure_midi) {
2049 backend->set_midi_device_enabled ((*p)->name, true);
2051 backend->set_midi_device_enabled ((*p)->name, false);
2055 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2056 if (backend->can_set_systemic_midi_latencies()) {
2057 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2058 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2063 if (start || (was_running && restart_required)) {
2064 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2075 EngineControl::post_push ()
2077 /* get a pointer to the current state object, creating one if
2081 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2084 state = save_state ();
2092 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2093 (*i)->active = false;
2096 /* mark this one active (to be used next time the dialog is
2100 state->active = true;
2102 if (_have_control) { // XXX
2103 manage_control_app_sensitivity ();
2106 /* schedule a redisplay of MIDI ports */
2107 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2112 EngineControl::get_rate () const
2114 float r = atof (sample_rate_combo.get_active_text ());
2115 /* the string may have been translated with an abbreviation for
2116 * thousands, so use a crude heuristic to fix this.
2126 EngineControl::get_buffer_size () const
2128 string txt = buffer_size_combo.get_active_text ();
2131 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2132 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2133 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2141 EngineControl::get_midi_option () const
2143 return midi_option_combo.get_active_text();
2147 EngineControl::get_input_channels() const
2149 if (ARDOUR::Profile->get_mixbus()) {
2150 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2151 if (!backend) return 0;
2152 return backend->input_channels();
2154 return (uint32_t) input_channels_adjustment.get_value();
2158 EngineControl::get_output_channels() const
2160 if (ARDOUR::Profile->get_mixbus()) {
2161 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2162 if (!backend) return 0;
2163 return backend->input_channels();
2165 return (uint32_t) output_channels_adjustment.get_value();
2169 EngineControl::get_input_latency() const
2171 return (uint32_t) input_latency_adjustment.get_value();
2175 EngineControl::get_output_latency() const
2177 return (uint32_t) output_latency_adjustment.get_value();
2181 EngineControl::get_backend () const
2183 return backend_combo.get_active_text ();
2187 EngineControl::get_driver () const
2189 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2190 return driver_combo.get_active_text ();
2197 EngineControl::get_device_name () const
2199 return device_combo.get_active_text ();
2203 EngineControl::get_input_device_name () const
2205 return input_device_combo.get_active_text ();
2209 EngineControl::get_output_device_name () const
2211 return output_device_combo.get_active_text ();
2215 EngineControl::control_app_button_clicked ()
2217 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2223 backend->launch_control_app ();
2227 EngineControl::manage_control_app_sensitivity ()
2229 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2235 string appname = backend->control_app_name();
2237 if (appname.empty()) {
2238 control_app_button.set_sensitive (false);
2240 control_app_button.set_sensitive (true);
2245 EngineControl::set_desired_sample_rate (uint32_t sr)
2247 _desired_sample_rate = sr;
2249 input_device_changed ();
2250 output_device_changed ();
2254 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2256 if (page_num == 0) {
2257 cancel_button->set_sensitive (true);
2258 ok_button->set_sensitive (true);
2259 apply_button->set_sensitive (true);
2260 _measure_midi.reset();
2262 cancel_button->set_sensitive (false);
2263 ok_button->set_sensitive (false);
2264 apply_button->set_sensitive (false);
2267 if (page_num == midi_tab) {
2269 refresh_midi_display ();
2272 if (page_num == latency_tab) {
2275 if (ARDOUR::AudioEngine::instance()->running()) {
2276 // TODO - mark as 'stopped for latency
2277 ARDOUR_UI::instance()->disconnect_from_engine ();
2281 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2283 /* save any existing latency values */
2285 uint32_t il = (uint32_t) input_latency.get_value ();
2286 uint32_t ol = (uint32_t) input_latency.get_value ();
2288 /* reset to zero so that our new test instance
2289 will be clean of any existing latency measures.
2291 NB. this should really be done by the backend
2292 when stated for latency measurement.
2295 input_latency.set_value (0);
2296 output_latency.set_value (0);
2298 push_state_to_backend (false);
2302 input_latency.set_value (il);
2303 output_latency.set_value (ol);
2306 // This should be done in push_state_to_backend()
2307 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2308 disable_latency_tab ();
2311 enable_latency_tab ();
2315 end_latency_detection ();
2316 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2321 /* latency measurement */
2324 EngineControl::check_audio_latency_measurement ()
2326 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2328 if (mtdm->resolve () < 0) {
2329 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2333 if (mtdm->err () > 0.3) {
2339 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2341 if (sample_rate == 0) {
2342 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2343 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2347 int frames_total = mtdm->del();
2348 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2350 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2351 _("Detected roundtrip latency: "),
2352 frames_total, frames_total * 1000.0f/sample_rate,
2353 _("Systemic latency: "),
2354 extra, extra * 1000.0f/sample_rate);
2358 if (mtdm->err () > 0.2) {
2360 strcat (buf, _("(signal detection error)"));
2366 strcat (buf, _("(inverted - bad wiring)"));
2370 lm_results.set_markup (string_compose (results_markup, buf));
2373 have_lm_results = true;
2374 end_latency_detection ();
2375 lm_use_button.set_sensitive (true);
2383 EngineControl::check_midi_latency_measurement ()
2385 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2387 if (!mididm->have_signal () || mididm->latency () == 0) {
2388 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2393 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2395 if (sample_rate == 0) {
2396 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2397 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2401 ARDOUR::framecnt_t frames_total = mididm->latency();
2402 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2403 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2404 _("Detected roundtrip latency: "),
2405 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2406 _("Systemic latency: "),
2407 extra, extra * 1000.0f / sample_rate);
2411 if (!mididm->ok ()) {
2413 strcat (buf, _("(averaging)"));
2417 if (mididm->deviation () > 50.0) {
2419 strcat (buf, _("(too large jitter)"));
2421 } else if (mididm->deviation () > 10.0) {
2423 strcat (buf, _("(large jitter)"));
2427 have_lm_results = true;
2428 end_latency_detection ();
2429 lm_use_button.set_sensitive (true);
2430 lm_results.set_markup (string_compose (results_markup, buf));
2432 } else if (mididm->processed () > 400) {
2433 have_lm_results = false;
2434 end_latency_detection ();
2435 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2439 lm_results.set_markup (string_compose (results_markup, buf));
2445 EngineControl::start_latency_detection ()
2447 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2448 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2450 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2451 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2452 if (_measure_midi) {
2453 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2455 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2457 lm_measure_label.set_text (_("Cancel"));
2458 have_lm_results = false;
2459 lm_use_button.set_sensitive (false);
2460 lm_input_channel_combo.set_sensitive (false);
2461 lm_output_channel_combo.set_sensitive (false);
2467 EngineControl::end_latency_detection ()
2469 latency_timeout.disconnect ();
2470 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2471 lm_measure_label.set_text (_("Measure"));
2472 if (!have_lm_results) {
2473 lm_use_button.set_sensitive (false);
2475 lm_input_channel_combo.set_sensitive (true);
2476 lm_output_channel_combo.set_sensitive (true);
2481 EngineControl::latency_button_clicked ()
2484 start_latency_detection ();
2486 end_latency_detection ();
2491 EngineControl::use_latency_button_clicked ()
2493 if (_measure_midi) {
2494 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2498 ARDOUR::framecnt_t frames_total = mididm->latency();
2499 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2500 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2501 _measure_midi->input_latency = one_way;
2502 _measure_midi->output_latency = one_way;
2503 notebook.set_current_page (midi_tab);
2505 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2511 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2512 one_way = std::max (0., one_way);
2514 input_latency_adjustment.set_value (one_way);
2515 output_latency_adjustment.set_value (one_way);
2517 /* back to settings page */
2518 notebook.set_current_page (0);
2524 EngineControl::on_delete_event (GdkEventAny* ev)
2526 if (notebook.get_current_page() == 2) {
2527 /* currently on latency tab - be sure to clean up */
2528 end_latency_detection ();
2530 return ArdourDialog::on_delete_event (ev);
2534 EngineControl::engine_running ()
2536 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2539 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2540 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2542 buffer_size_combo.set_sensitive (true);
2543 sample_rate_combo.set_sensitive (true);
2545 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2546 connect_disconnect_button.show();
2548 started_at_least_once = true;
2549 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2553 EngineControl::engine_stopped ()
2555 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2558 buffer_size_combo.set_sensitive (false);
2559 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2560 connect_disconnect_button.show();
2562 sample_rate_combo.set_sensitive (true);
2563 buffer_size_combo.set_sensitive (true);
2564 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2568 EngineControl::device_list_changed ()
2570 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2572 midi_option_changed();
2576 EngineControl::connect_disconnect_click()
2578 if (ARDOUR::AudioEngine::instance()->running()) {
2579 ARDOUR_UI::instance()->disconnect_from_engine ();
2581 ARDOUR_UI::instance()->reconnect_to_engine ();
2586 EngineControl::calibrate_audio_latency ()
2588 _measure_midi.reset ();
2589 have_lm_results = false;
2590 lm_use_button.set_sensitive (false);
2591 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2592 notebook.set_current_page (latency_tab);
2596 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2599 have_lm_results = false;
2600 lm_use_button.set_sensitive (false);
2601 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2602 notebook.set_current_page (latency_tab);
2606 EngineControl::configure_midi_devices ()
2608 notebook.set_current_page (midi_tab);