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);
1165 uint32_t period = backend->buffer_size();
1167 period = backend->default_buffer_size(device_name);
1169 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1170 show_buffer_duration ();
1172 buffer_size_combo.set_sensitive (false);
1177 EngineControl::device_changed ()
1179 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1182 string device_name_in;
1183 string device_name_out; // only used if backend support separate I/O devices
1185 if (backend->use_separate_input_and_output_devices()) {
1186 device_name_in = get_input_device_name ();
1187 device_name_out = get_output_device_name ();
1189 device_name_in = get_device_name ();
1192 /* we set the backend-device to query various device related intormation.
1193 * This has the side effect that backend->device_name() will match
1194 * the device_name and 'change_device' will never be true.
1195 * so work around this by setting...
1197 if (backend->use_separate_input_and_output_devices()) {
1198 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1199 queue_device_changed = true;
1202 if (device_name_in != backend->device_name()) {
1203 queue_device_changed = true;
1207 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1208 if (backend->use_separate_input_and_output_devices()) {
1209 backend->set_input_device_name (device_name_in);
1210 backend->set_output_device_name (device_name_out);
1212 backend->set_device_name(device_name_in);
1216 /* don't allow programmatic change to combos to cause a
1217 recursive call to this method.
1219 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1221 /* backends that support separate devices, need to ignore
1222 * the device-name - and use the devies set above
1224 set_samplerate_popdown_strings (device_name_in);
1225 set_buffersize_popdown_strings (device_name_in);
1226 /* XXX theoretically need to set min + max channel counts here
1229 manage_control_app_sensitivity ();
1232 /* pick up any saved state for this device */
1234 if (!ignore_changes) {
1235 maybe_display_saved_state ();
1240 EngineControl::input_device_changed ()
1242 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1244 string input_device_name = input_device_combo.get_active_text ();
1246 if (!ignore_changes && input_device_name != backend->input_device_name()) {
1247 queue_device_changed = true;
1250 backend->set_input_device_name(input_device_name);
1253 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1255 set_samplerate_popdown_strings (input_device_name);
1256 set_buffersize_popdown_strings (input_device_name);
1257 /* XXX theoretically need to set min + max channel counts here
1260 manage_control_app_sensitivity ();
1263 /* pick up any saved state for this device */
1265 if (!ignore_changes) {
1266 maybe_display_saved_state ();
1271 EngineControl::output_device_changed ()
1273 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1275 string output_device_name = output_device_combo.get_active_text ();
1277 if (!ignore_changes && output_device_name != backend->output_device_name()) {
1278 queue_device_changed = true;
1281 backend->set_output_device_name(output_device_name);
1284 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1286 set_samplerate_popdown_strings (output_device_name);
1287 set_buffersize_popdown_strings (output_device_name);
1288 /* XXX theoretically need to set min + max channel counts here
1291 manage_control_app_sensitivity ();
1294 /* pick up any saved state for this device */
1296 if (!ignore_changes) {
1297 maybe_display_saved_state ();
1302 EngineControl::bufsize_as_string (uint32_t sz)
1304 /* Translators: "samples" is always plural here, so no
1305 need for plural+singular forms.
1308 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1313 EngineControl::sample_rate_changed ()
1315 /* reset the strings for buffer size to show the correct msec value
1316 (reflecting the new sample rate).
1319 show_buffer_duration ();
1324 EngineControl::buffer_size_changed ()
1326 show_buffer_duration ();
1330 EngineControl::show_buffer_duration ()
1333 /* buffer sizes - convert from just samples to samples + msecs for
1334 * the displayed string
1337 string bs_text = buffer_size_combo.get_active_text ();
1338 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1339 uint32_t rate = get_rate();
1341 /* Developers: note the hard-coding of a double buffered model
1342 in the (2 * samples) computation of latency. we always start
1343 the audiobackend in this configuration.
1345 /* note to jack1 developers: ardour also always starts the engine
1346 * in async mode (no jack2 --sync option) which adds an extra cycle
1347 * of latency with jack2 (and *3 would be correct)
1348 * The value can also be wrong if jackd is started externally..
1350 * At the time of writing the ALSA backend always uses double-buffering *2,
1351 * The Dummy backend *1, and who knows what ASIO really does :)
1353 * So just display the period size, that's also what
1354 * ARDOUR_UI::update_sample_rate() does for the status bar.
1355 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1356 * but still, that's the buffer period, not [round-trip] latency)
1359 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1360 buffer_size_duration_label.set_text (buf);
1364 EngineControl::midi_option_changed ()
1366 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1369 backend->set_midi_option (get_midi_option());
1371 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1373 //_midi_devices.clear(); // TODO merge with state-saved settings..
1374 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1375 std::vector<MidiDeviceSettings> new_devices;
1377 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1378 MidiDeviceSettings mds = find_midi_device (i->name);
1379 if (i->available && !mds) {
1380 uint32_t input_latency = 0;
1381 uint32_t output_latency = 0;
1382 if (_can_set_midi_latencies) {
1383 input_latency = backend->systemic_midi_input_latency (i->name);
1384 output_latency = backend->systemic_midi_output_latency (i->name);
1386 bool enabled = backend->midi_device_enabled (i->name);
1387 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1388 new_devices.push_back (ptr);
1389 } else if (i->available) {
1390 new_devices.push_back (mds);
1393 _midi_devices = new_devices;
1395 if (_midi_devices.empty()) {
1396 midi_devices_button.set_sensitive (false);
1398 midi_devices_button.set_sensitive (true);
1403 EngineControl::parameter_changed ()
1407 EngineControl::State
1408 EngineControl::get_matching_state (
1409 const string& backend,
1410 const string& driver,
1411 const string& device)
1413 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1414 if ((*i)->backend == backend &&
1415 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1423 EngineControl::State
1424 EngineControl::get_matching_state (
1425 const string& backend,
1426 const string& driver,
1427 const string& input_device,
1428 const string& output_device)
1430 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1431 if ((*i)->backend == backend &&
1432 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1440 EngineControl::State
1441 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1443 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1446 if (backend->use_separate_input_and_output_devices ()) {
1447 return get_matching_state (backend_combo.get_active_text(),
1448 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1449 input_device_combo.get_active_text(),
1450 output_device_combo.get_active_text());
1452 return get_matching_state (backend_combo.get_active_text(),
1453 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1454 device_combo.get_active_text());
1458 return get_matching_state (backend_combo.get_active_text(),
1460 device_combo.get_active_text());
1463 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1464 const EngineControl::State& state2)
1466 if (state1->backend == state2->backend &&
1467 state1->driver == state2->driver &&
1468 state1->device == state2->device &&
1469 state1->input_device == state2->input_device &&
1470 state1->output_device == state2->output_device) {
1476 EngineControl::State
1477 EngineControl::save_state ()
1481 if (!_have_control) {
1482 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1486 state.reset(new StateStruct);
1487 state->backend = get_backend ();
1489 state.reset(new StateStruct);
1490 store_state (state);
1493 for (StateList::iterator i = states.begin(); i != states.end();) {
1494 if (equivalent_states (*i, state)) {
1495 i = states.erase(i);
1501 states.push_back (state);
1507 EngineControl::store_state (State state)
1509 state->backend = get_backend ();
1510 state->driver = get_driver ();
1511 state->device = get_device_name ();
1512 state->input_device = get_input_device_name ();
1513 state->output_device = get_output_device_name ();
1514 state->sample_rate = get_rate ();
1515 state->buffer_size = get_buffer_size ();
1516 state->input_latency = get_input_latency ();
1517 state->output_latency = get_output_latency ();
1518 state->input_channels = get_input_channels ();
1519 state->output_channels = get_output_channels ();
1520 state->midi_option = get_midi_option ();
1521 state->midi_devices = _midi_devices;
1525 EngineControl::maybe_display_saved_state ()
1527 if (!_have_control) {
1531 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1534 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1536 if (!_desired_sample_rate) {
1537 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1539 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1540 /* call this explicitly because we're ignoring changes to
1541 the controls at this point.
1543 show_buffer_duration ();
1544 input_latency.set_value (state->input_latency);
1545 output_latency.set_value (state->output_latency);
1547 if (!state->midi_option.empty()) {
1548 midi_option_combo.set_active_text (state->midi_option);
1549 _midi_devices = state->midi_devices;
1555 EngineControl::get_state ()
1557 LocaleGuard lg (X_("C"));
1559 XMLNode* root = new XMLNode ("AudioMIDISetup");
1562 if (!states.empty()) {
1563 XMLNode* state_nodes = new XMLNode ("EngineStates");
1565 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1567 XMLNode* node = new XMLNode ("State");
1569 node->add_property ("backend", (*i)->backend);
1570 node->add_property ("driver", (*i)->driver);
1571 node->add_property ("device", (*i)->device);
1572 node->add_property ("input-device", (*i)->input_device);
1573 node->add_property ("output-device", (*i)->output_device);
1574 node->add_property ("sample-rate", (*i)->sample_rate);
1575 node->add_property ("buffer-size", (*i)->buffer_size);
1576 node->add_property ("input-latency", (*i)->input_latency);
1577 node->add_property ("output-latency", (*i)->output_latency);
1578 node->add_property ("input-channels", (*i)->input_channels);
1579 node->add_property ("output-channels", (*i)->output_channels);
1580 node->add_property ("active", (*i)->active ? "yes" : "no");
1581 node->add_property ("midi-option", (*i)->midi_option);
1583 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1584 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1585 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1586 midi_device_stuff->add_property (X_("name"), (*p)->name);
1587 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1588 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1589 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1590 midi_devices->add_child_nocopy (*midi_device_stuff);
1592 node->add_child_nocopy (*midi_devices);
1594 state_nodes->add_child_nocopy (*node);
1597 root->add_child_nocopy (*state_nodes);
1604 EngineControl::set_state (const XMLNode& root)
1606 XMLNodeList clist, cclist;
1607 XMLNodeConstIterator citer, cciter;
1609 XMLNode* grandchild;
1610 XMLProperty* prop = NULL;
1612 fprintf (stderr, "EngineControl::set_state\n");
1614 if (root.name() != "AudioMIDISetup") {
1618 clist = root.children();
1622 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1626 if (child->name() != "EngineStates") {
1630 cclist = child->children();
1632 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1633 State state (new StateStruct);
1635 grandchild = *cciter;
1637 if (grandchild->name() != "State") {
1641 if ((prop = grandchild->property ("backend")) == 0) {
1644 state->backend = prop->value ();
1646 if ((prop = grandchild->property ("driver")) == 0) {
1649 state->driver = prop->value ();
1651 if ((prop = grandchild->property ("device")) == 0) {
1654 state->device = prop->value ();
1656 if ((prop = grandchild->property ("input-device")) == 0) {
1659 state->input_device = prop->value ();
1661 if ((prop = grandchild->property ("output-device")) == 0) {
1664 state->output_device = prop->value ();
1666 if ((prop = grandchild->property ("sample-rate")) == 0) {
1669 state->sample_rate = atof (prop->value ());
1671 if ((prop = grandchild->property ("buffer-size")) == 0) {
1674 state->buffer_size = atoi (prop->value ());
1676 if ((prop = grandchild->property ("input-latency")) == 0) {
1679 state->input_latency = atoi (prop->value ());
1681 if ((prop = grandchild->property ("output-latency")) == 0) {
1684 state->output_latency = atoi (prop->value ());
1686 if ((prop = grandchild->property ("input-channels")) == 0) {
1689 state->input_channels = atoi (prop->value ());
1691 if ((prop = grandchild->property ("output-channels")) == 0) {
1694 state->output_channels = atoi (prop->value ());
1696 if ((prop = grandchild->property ("active")) == 0) {
1699 state->active = string_is_affirmative (prop->value ());
1701 if ((prop = grandchild->property ("midi-option")) == 0) {
1704 state->midi_option = prop->value ();
1706 state->midi_devices.clear();
1708 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1709 const XMLNodeList mnc = midinode->children();
1710 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1711 if ((*n)->property (X_("name")) == 0
1712 || (*n)->property (X_("enabled")) == 0
1713 || (*n)->property (X_("input-latency")) == 0
1714 || (*n)->property (X_("output-latency")) == 0
1719 MidiDeviceSettings ptr (new MidiDeviceSetting(
1720 (*n)->property (X_("name"))->value (),
1721 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1722 atoi ((*n)->property (X_("input-latency"))->value ()),
1723 atoi ((*n)->property (X_("output-latency"))->value ())
1725 state->midi_devices.push_back (ptr);
1730 /* remove accumulated duplicates (due to bug in ealier version)
1731 * this can be removed again before release
1733 for (StateList::iterator i = states.begin(); i != states.end();) {
1734 if ((*i)->backend == state->backend &&
1735 (*i)->driver == state->driver &&
1736 (*i)->device == state->device) {
1737 i = states.erase(i);
1744 states.push_back (state);
1748 /* now see if there was an active state and switch the setup to it */
1750 // purge states of backend that are not available in this built
1751 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1752 vector<std::string> backend_names;
1754 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1755 backend_names.push_back((*i)->name);
1757 for (StateList::iterator i = states.begin(); i != states.end();) {
1758 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1759 i = states.erase(i);
1765 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1768 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1769 backend_combo.set_active_text ((*i)->backend);
1771 /* The driver popdown strings need to be populated now so that
1772 * set_active_text will actually set a valid entry. Then
1773 * backend_changed() will populate all the other combo's so they
1774 * can also be set to valid entries and the state will be restored
1777 set_driver_popdown_strings ();
1778 driver_combo.set_active_text ((*i)->driver);
1781 device_combo.set_active_text ((*i)->device);
1782 input_device_combo.set_active_text ((*i)->input_device);
1783 output_device_combo.set_active_text ((*i)->output_device);
1784 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1785 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1786 input_latency.set_value ((*i)->input_latency);
1787 output_latency.set_value ((*i)->output_latency);
1788 midi_option_combo.set_active_text ((*i)->midi_option);
1795 EngineControl::push_state_to_backend (bool start)
1797 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1803 /* figure out what is going to change */
1805 bool restart_required = false;
1806 bool was_running = ARDOUR::AudioEngine::instance()->running();
1807 bool change_driver = false;
1808 bool change_device = false;
1809 bool change_rate = false;
1810 bool change_bufsize = false;
1811 bool change_latency = false;
1812 bool change_channels = false;
1813 bool change_midi = false;
1815 uint32_t ochan = get_output_channels ();
1816 uint32_t ichan = get_input_channels ();
1818 if (_have_control) {
1820 if (started_at_least_once) {
1822 /* we can control the backend */
1824 if (backend->requires_driver_selection()) {
1825 if (get_driver() != backend->driver_name()) {
1826 change_driver = true;
1830 if (backend->use_separate_input_and_output_devices()) {
1831 if (get_input_device_name() != backend->input_device_name()) {
1832 change_device = true;
1834 if (get_output_device_name() != backend->output_device_name()) {
1835 change_device = true;
1838 if (get_device_name() != backend->device_name()) {
1839 change_device = true;
1843 if (queue_device_changed) {
1844 change_device = true;
1847 if (get_rate() != backend->sample_rate()) {
1851 if (get_buffer_size() != backend->buffer_size()) {
1852 change_bufsize = true;
1855 if (get_midi_option() != backend->midi_option()) {
1859 /* zero-requested channels means "all available" */
1862 ichan = backend->input_channels();
1866 ochan = backend->output_channels();
1869 if (ichan != backend->input_channels()) {
1870 change_channels = true;
1873 if (ochan != backend->output_channels()) {
1874 change_channels = true;
1877 if (get_input_latency() != backend->systemic_input_latency() ||
1878 get_output_latency() != backend->systemic_output_latency()) {
1879 change_latency = true;
1882 /* backend never started, so we have to force a group
1885 change_device = true;
1886 if (backend->requires_driver_selection()) {
1887 change_driver = true;
1890 change_bufsize = true;
1891 change_channels = true;
1892 change_latency = true;
1898 /* we have no control over the backend, meaning that we can
1899 * only possibly change sample rate and buffer size.
1903 if (get_rate() != backend->sample_rate()) {
1904 change_bufsize = true;
1907 if (get_buffer_size() != backend->buffer_size()) {
1908 change_bufsize = true;
1912 queue_device_changed = false;
1914 if (!_have_control) {
1916 /* We do not have control over the backend, so the best we can
1917 * do is try to change the sample rate and/or bufsize and get
1921 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1925 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1930 backend->set_sample_rate (get_rate());
1933 if (change_bufsize) {
1934 backend->set_buffer_size (get_buffer_size());
1938 if (ARDOUR::AudioEngine::instance()->start ()) {
1939 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1949 /* determine if we need to stop the backend before changing parameters */
1951 if (change_driver || change_device || change_channels || change_latency ||
1952 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1954 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1955 restart_required = true;
1957 restart_required = false;
1962 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1963 /* no changes in any parameters that absolutely require a
1964 * restart, so check those that might be changeable without a
1968 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1969 /* can't do this while running ... */
1970 restart_required = true;
1973 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1974 /* can't do this while running ... */
1975 restart_required = true;
1981 if (restart_required) {
1982 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1989 if (change_driver && backend->set_driver (get_driver())) {
1990 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1993 if (backend->use_separate_input_and_output_devices()) {
1994 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1995 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1998 if (change_device && backend->set_output_device_name (get_output_device_name())) {
1999 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2003 if (change_device && backend->set_device_name (get_device_name())) {
2004 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2008 if (change_rate && backend->set_sample_rate (get_rate())) {
2009 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2012 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2013 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2017 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2018 if (backend->set_input_channels (get_input_channels())) {
2019 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2022 if (backend->set_output_channels (get_output_channels())) {
2023 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2027 if (change_latency) {
2028 if (backend->set_systemic_input_latency (get_input_latency())) {
2029 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2032 if (backend->set_systemic_output_latency (get_output_latency())) {
2033 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2039 backend->set_midi_option (get_midi_option());
2043 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2044 if (_measure_midi) {
2045 if (*p == _measure_midi) {
2046 backend->set_midi_device_enabled ((*p)->name, true);
2048 backend->set_midi_device_enabled ((*p)->name, false);
2052 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2053 if (backend->can_set_systemic_midi_latencies()) {
2054 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2055 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2060 if (start || (was_running && restart_required)) {
2061 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2072 EngineControl::post_push ()
2074 /* get a pointer to the current state object, creating one if
2078 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2081 state = save_state ();
2089 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2090 (*i)->active = false;
2093 /* mark this one active (to be used next time the dialog is
2097 state->active = true;
2099 if (_have_control) { // XXX
2100 manage_control_app_sensitivity ();
2103 /* schedule a redisplay of MIDI ports */
2104 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2109 EngineControl::get_rate () const
2111 float r = atof (sample_rate_combo.get_active_text ());
2112 /* the string may have been translated with an abbreviation for
2113 * thousands, so use a crude heuristic to fix this.
2123 EngineControl::get_buffer_size () const
2125 string txt = buffer_size_combo.get_active_text ();
2128 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2129 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2130 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2138 EngineControl::get_midi_option () const
2140 return midi_option_combo.get_active_text();
2144 EngineControl::get_input_channels() const
2146 if (ARDOUR::Profile->get_mixbus()) {
2147 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2148 if (!backend) return 0;
2149 return backend->input_channels();
2151 return (uint32_t) input_channels_adjustment.get_value();
2155 EngineControl::get_output_channels() const
2157 if (ARDOUR::Profile->get_mixbus()) {
2158 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2159 if (!backend) return 0;
2160 return backend->input_channels();
2162 return (uint32_t) output_channels_adjustment.get_value();
2166 EngineControl::get_input_latency() const
2168 return (uint32_t) input_latency_adjustment.get_value();
2172 EngineControl::get_output_latency() const
2174 return (uint32_t) output_latency_adjustment.get_value();
2178 EngineControl::get_backend () const
2180 return backend_combo.get_active_text ();
2184 EngineControl::get_driver () const
2186 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2187 return driver_combo.get_active_text ();
2194 EngineControl::get_device_name () const
2196 return device_combo.get_active_text ();
2200 EngineControl::get_input_device_name () const
2202 return input_device_combo.get_active_text ();
2206 EngineControl::get_output_device_name () const
2208 return output_device_combo.get_active_text ();
2212 EngineControl::control_app_button_clicked ()
2214 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2220 backend->launch_control_app ();
2224 EngineControl::manage_control_app_sensitivity ()
2226 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2232 string appname = backend->control_app_name();
2234 if (appname.empty()) {
2235 control_app_button.set_sensitive (false);
2237 control_app_button.set_sensitive (true);
2242 EngineControl::set_desired_sample_rate (uint32_t sr)
2244 _desired_sample_rate = sr;
2246 input_device_changed ();
2247 output_device_changed ();
2251 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2253 if (page_num == 0) {
2254 cancel_button->set_sensitive (true);
2255 ok_button->set_sensitive (true);
2256 apply_button->set_sensitive (true);
2257 _measure_midi.reset();
2259 cancel_button->set_sensitive (false);
2260 ok_button->set_sensitive (false);
2261 apply_button->set_sensitive (false);
2264 if (page_num == midi_tab) {
2266 refresh_midi_display ();
2269 if (page_num == latency_tab) {
2272 if (ARDOUR::AudioEngine::instance()->running()) {
2273 // TODO - mark as 'stopped for latency
2274 ARDOUR_UI::instance()->disconnect_from_engine ();
2278 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2280 /* save any existing latency values */
2282 uint32_t il = (uint32_t) input_latency.get_value ();
2283 uint32_t ol = (uint32_t) input_latency.get_value ();
2285 /* reset to zero so that our new test instance
2286 will be clean of any existing latency measures.
2288 NB. this should really be done by the backend
2289 when stated for latency measurement.
2292 input_latency.set_value (0);
2293 output_latency.set_value (0);
2295 push_state_to_backend (false);
2299 input_latency.set_value (il);
2300 output_latency.set_value (ol);
2303 // This should be done in push_state_to_backend()
2304 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2305 disable_latency_tab ();
2308 enable_latency_tab ();
2312 end_latency_detection ();
2313 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2318 /* latency measurement */
2321 EngineControl::check_audio_latency_measurement ()
2323 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2325 if (mtdm->resolve () < 0) {
2326 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2330 if (mtdm->err () > 0.3) {
2336 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2338 if (sample_rate == 0) {
2339 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2340 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2344 int frames_total = mtdm->del();
2345 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2347 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2348 _("Detected roundtrip latency: "),
2349 frames_total, frames_total * 1000.0f/sample_rate,
2350 _("Systemic latency: "),
2351 extra, extra * 1000.0f/sample_rate);
2355 if (mtdm->err () > 0.2) {
2357 strcat (buf, _("(signal detection error)"));
2363 strcat (buf, _("(inverted - bad wiring)"));
2367 lm_results.set_markup (string_compose (results_markup, buf));
2370 have_lm_results = true;
2371 end_latency_detection ();
2372 lm_use_button.set_sensitive (true);
2380 EngineControl::check_midi_latency_measurement ()
2382 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2384 if (!mididm->have_signal () || mididm->latency () == 0) {
2385 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2390 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2392 if (sample_rate == 0) {
2393 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2394 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2398 ARDOUR::framecnt_t frames_total = mididm->latency();
2399 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2400 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2401 _("Detected roundtrip latency: "),
2402 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2403 _("Systemic latency: "),
2404 extra, extra * 1000.0f / sample_rate);
2408 if (!mididm->ok ()) {
2410 strcat (buf, _("(averaging)"));
2414 if (mididm->deviation () > 50.0) {
2416 strcat (buf, _("(too large jitter)"));
2418 } else if (mididm->deviation () > 10.0) {
2420 strcat (buf, _("(large jitter)"));
2424 have_lm_results = true;
2425 end_latency_detection ();
2426 lm_use_button.set_sensitive (true);
2427 lm_results.set_markup (string_compose (results_markup, buf));
2429 } else if (mididm->processed () > 400) {
2430 have_lm_results = false;
2431 end_latency_detection ();
2432 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2436 lm_results.set_markup (string_compose (results_markup, buf));
2442 EngineControl::start_latency_detection ()
2444 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2445 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2447 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2448 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2449 if (_measure_midi) {
2450 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2452 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2454 lm_measure_label.set_text (_("Cancel"));
2455 have_lm_results = false;
2456 lm_use_button.set_sensitive (false);
2457 lm_input_channel_combo.set_sensitive (false);
2458 lm_output_channel_combo.set_sensitive (false);
2464 EngineControl::end_latency_detection ()
2466 latency_timeout.disconnect ();
2467 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2468 lm_measure_label.set_text (_("Measure"));
2469 if (!have_lm_results) {
2470 lm_use_button.set_sensitive (false);
2472 lm_input_channel_combo.set_sensitive (true);
2473 lm_output_channel_combo.set_sensitive (true);
2478 EngineControl::latency_button_clicked ()
2481 start_latency_detection ();
2483 end_latency_detection ();
2488 EngineControl::use_latency_button_clicked ()
2490 if (_measure_midi) {
2491 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2495 ARDOUR::framecnt_t frames_total = mididm->latency();
2496 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2497 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2498 _measure_midi->input_latency = one_way;
2499 _measure_midi->output_latency = one_way;
2500 notebook.set_current_page (midi_tab);
2502 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2508 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2509 one_way = std::max (0., one_way);
2511 input_latency_adjustment.set_value (one_way);
2512 output_latency_adjustment.set_value (one_way);
2514 /* back to settings page */
2515 notebook.set_current_page (0);
2521 EngineControl::on_delete_event (GdkEventAny* ev)
2523 if (notebook.get_current_page() == 2) {
2524 /* currently on latency tab - be sure to clean up */
2525 end_latency_detection ();
2527 return ArdourDialog::on_delete_event (ev);
2531 EngineControl::engine_running ()
2533 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2536 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2537 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2539 buffer_size_combo.set_sensitive (true);
2540 sample_rate_combo.set_sensitive (true);
2542 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2543 connect_disconnect_button.show();
2545 started_at_least_once = true;
2546 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2550 EngineControl::engine_stopped ()
2552 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2555 buffer_size_combo.set_sensitive (false);
2556 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2557 connect_disconnect_button.show();
2559 sample_rate_combo.set_sensitive (true);
2560 buffer_size_combo.set_sensitive (true);
2561 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2565 EngineControl::device_list_changed ()
2567 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2569 midi_option_changed();
2573 EngineControl::connect_disconnect_click()
2575 if (ARDOUR::AudioEngine::instance()->running()) {
2576 ARDOUR_UI::instance()->disconnect_from_engine ();
2578 ARDOUR_UI::instance()->reconnect_to_engine ();
2583 EngineControl::calibrate_audio_latency ()
2585 _measure_midi.reset ();
2586 have_lm_results = false;
2587 lm_use_button.set_sensitive (false);
2588 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2589 notebook.set_current_page (latency_tab);
2593 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2596 have_lm_results = false;
2597 lm_use_button.set_sensitive (false);
2598 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2599 notebook.set_current_page (latency_tab);
2603 EngineControl::configure_midi_devices ()
2605 notebook.set_current_page (midi_tab);