2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 static const unsigned int midi_tab = 2;
66 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
68 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
70 EngineControl::EngineControl ()
71 : ArdourDialog (_("Audio/MIDI Setup"))
74 , input_latency_adjustment (0, 0, 99999, 1)
75 , input_latency (input_latency_adjustment)
76 , output_latency_adjustment (0, 0, 99999, 1)
77 , output_latency (output_latency_adjustment)
78 , input_channels_adjustment (0, 0, 256, 1)
79 , input_channels (input_channels_adjustment)
80 , output_channels_adjustment (0, 0, 256, 1)
81 , output_channels (output_channels_adjustment)
82 , ports_adjustment (128, 8, 1024, 1, 16)
83 , ports_spinner (ports_adjustment)
84 , control_app_button (_("Device Control Panel"))
85 , midi_devices_button (_("Midi Device Setup"))
86 , lm_measure_label (_("Measure"))
87 , lm_use_button (_("Use results"))
88 , lm_back_button (_("Back to settings ... (ignore results)"))
89 , lm_button_audio (_("Calibrate Audio"))
91 , have_lm_results (false)
93 , midi_back_button (_("Back to settings"))
95 , _desired_sample_rate (0)
96 , started_at_least_once (false)
97 , queue_device_changed (false)
99 using namespace Notebook_Helpers;
100 vector<string> backend_names;
102 AttachOptions xopt = AttachOptions (FILL|EXPAND);
105 set_name (X_("AudioMIDISetup"));
107 /* the backend combo is the one thing that is ALWAYS visible */
109 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
111 if (backends.empty()) {
112 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
114 throw failed_constructor ();
117 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
118 backend_names.push_back ((*b)->name);
121 set_popdown_strings (backend_combo, backend_names);
122 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
124 /* setup basic packing characteristics for the table used on the main
125 * tab of the notebook
128 basic_packer.set_spacings (6);
129 basic_packer.set_border_width (12);
130 basic_packer.set_homogeneous (false);
134 basic_hbox.pack_start (basic_packer, false, false);
136 /* latency measurement tab */
138 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
141 lm_table.set_row_spacings (12);
142 lm_table.set_col_spacings (6);
143 lm_table.set_homogeneous (false);
145 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
148 lm_preamble.set_width_chars (60);
149 lm_preamble.set_line_wrap (true);
150 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
152 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
155 Gtk::Label* preamble;
156 preamble = manage (new Label);
157 preamble->set_width_chars (60);
158 preamble->set_line_wrap (true);
159 preamble->set_markup (_("Select two channels below and connect them using a cable."));
161 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
164 label = manage (new Label (_("Output channel")));
165 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
167 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
168 misc_align->add (lm_output_channel_combo);
169 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
172 label = manage (new Label (_("Input channel")));
173 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
175 misc_align = manage (new Alignment (0.0, 0.5));
176 misc_align->add (lm_input_channel_combo);
177 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
180 xopt = AttachOptions(0);
182 lm_measure_label.set_padding (10, 10);
183 lm_measure_button.add (lm_measure_label);
184 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
185 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
186 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
188 lm_use_button.set_sensitive (false);
190 /* Increase the default spacing around the labels of these three
196 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
197 l->set_padding (10, 10);
200 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
201 l->set_padding (10, 10);
204 preamble = manage (new Label);
205 preamble->set_width_chars (60);
206 preamble->set_line_wrap (true);
207 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
208 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
211 preamble = manage (new Label);
212 preamble->set_width_chars (60);
213 preamble->set_line_wrap (true);
214 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
215 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
217 ++row; // skip a row in the table
218 ++row; // skip a row in the table
220 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222 ++row; // skip a row in the table
223 ++row; // skip a row in the table
225 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
229 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
231 lm_vbox.set_border_width (12);
232 lm_vbox.pack_start (lm_table, false, false);
234 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
238 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
239 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
240 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
241 notebook.set_border_width (12);
243 notebook.set_show_tabs (false);
244 notebook.show_all ();
246 notebook.set_name ("SettingsNotebook");
248 /* packup the notebook */
250 get_vbox()->set_border_width (12);
251 get_vbox()->pack_start (notebook);
253 get_action_area()->pack_start (engine_status);
254 engine_status.show();
256 /* need a special function to print "all available channels" when the
257 * channel counts hit zero.
260 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
261 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
263 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
264 midi_devices_button.set_sensitive (false);
265 midi_devices_button.set_name ("generic button");
266 midi_devices_button.set_can_focus(true);
268 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
269 manage_control_app_sensitivity ();
271 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
272 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
273 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
275 /* Pick up any existing audio setup configuration, if appropriate */
277 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
279 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
280 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
281 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
282 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
285 set_state (*audio_setup);
288 if (backend_combo.get_active_text().empty()) {
289 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
290 backend_combo.set_active_text (backend_names.front());
295 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
296 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
297 backend_combo.set_active_text (backend_names.back());
298 /* ignore: don't save state */
299 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
304 /* Connect to signals */
306 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
307 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
308 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
309 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
310 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
312 input_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 (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->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);
854 // @return true if there are devices available
856 EngineControl::set_device_popdown_strings ()
858 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
859 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
861 /* NOTE: Ardour currently does not display the "available" field of the
864 * Doing so would require a different GUI widget than the combo
865 * box/popdown that we currently use, since it has no way to list
866 * items that are not selectable. Something more like a popup menu,
867 * which could have unselectable items, would be appropriate.
870 vector<string> available_devices;
872 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
873 available_devices.push_back (i->name);
877 if (!available_devices.empty()) {
878 update_sensitivity ();
881 string current_device, found_device;
882 current_device = device_combo.get_active_text ();
883 if (current_device == "") {
884 current_device = backend->device_name ();
887 // Make sure that the active text is still relevant for this
888 // device (it might only be relevant to the previous device!!)
889 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
890 if (*i == current_device)
891 found_device = current_device;
893 if (found_device == "")
894 // device has never been set (or was not relevant
895 // for this backend) Let's make sure it's not blank
896 current_device = available_devices.front ();
898 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
899 set_popdown_strings (device_combo, available_devices);
901 device_combo.set_active_text (current_device);
910 // @return true if there are input devices available
912 EngineControl::set_input_device_popdown_strings ()
914 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
915 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
917 vector<string> available_devices;
919 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
920 available_devices.push_back (i->name);
923 if (!available_devices.empty()) {
924 update_sensitivity ();
927 string current_device, found_device;
928 current_device = input_device_combo.get_active_text ();
929 if (current_device == "") {
930 current_device = backend->input_device_name ();
933 // Make sure that the active text is still relevant for this
934 // device (it might only be relevant to the previous device!!)
935 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
936 if (*i == current_device)
937 found_device = current_device;
939 if (found_device == "")
940 // device has never been set (or was not relevant
941 // for this backend) Let's make sure it's not blank
942 current_device = available_devices.front ();
944 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
945 set_popdown_strings (input_device_combo, available_devices);
947 input_device_combo.set_active_text (current_device);
950 input_device_changed ();
957 // @return true if there are output devices available
959 EngineControl::set_output_device_popdown_strings ()
961 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
962 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
964 vector<string> available_devices;
966 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
967 available_devices.push_back (i->name);
970 if (!available_devices.empty()) {
971 update_sensitivity ();
974 string current_device, found_device;
975 current_device = output_device_combo.get_active_text ();
976 if (current_device == "") {
977 current_device = backend->output_device_name ();
980 // Make sure that the active text is still relevant for this
981 // device (it might only be relevant to the previous device!!)
982 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
983 if (*i == current_device)
984 found_device = current_device;
986 if (found_device == "")
987 // device has never been set (or was not relevant
988 // for this backend) Let's make sure it's not blank
989 current_device = available_devices.front ();
991 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
992 set_popdown_strings (output_device_combo, available_devices);
994 output_device_combo.set_active_text (current_device);
997 output_device_changed ();
1005 EngineControl::list_devices ()
1007 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1010 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1012 bool devices_available = false;
1014 if (backend->use_separate_input_and_output_devices ()) {
1015 bool input_devices_available = set_input_device_popdown_strings ();
1016 bool output_devices_available = set_output_device_popdown_strings ();
1017 devices_available = input_devices_available || output_devices_available;
1019 devices_available = set_device_popdown_strings ();
1022 if (devices_available) {
1023 input_latency.set_sensitive (true);
1024 output_latency.set_sensitive (true);
1025 input_channels.set_sensitive (true);
1026 output_channels.set_sensitive (true);
1028 ok_button->set_sensitive (true);
1029 apply_button->set_sensitive (true);
1032 device_combo.clear();
1033 input_device_combo.clear();
1034 output_device_combo.clear();
1035 sample_rate_combo.set_sensitive (false);
1036 buffer_size_combo.set_sensitive (false);
1037 input_latency.set_sensitive (false);
1038 output_latency.set_sensitive (false);
1039 input_channels.set_sensitive (false);
1040 output_channels.set_sensitive (false);
1041 if (_have_control) {
1042 ok_button->set_sensitive (false);
1043 apply_button->set_sensitive (false);
1045 ok_button->set_sensitive (true);
1046 apply_button->set_sensitive (true);
1047 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1048 sample_rate_combo.set_sensitive (true);
1050 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1051 buffer_size_combo.set_sensitive (true);
1059 EngineControl::driver_changed ()
1061 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1064 backend->set_driver (driver_combo.get_active_text());
1067 if (!ignore_changes) {
1068 maybe_display_saved_state ();
1073 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1075 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1080 if (_have_control) {
1081 sr = backend->available_sample_rates (device_name);
1084 sr.push_back (8000.0f);
1085 sr.push_back (16000.0f);
1086 sr.push_back (32000.0f);
1087 sr.push_back (44100.0f);
1088 sr.push_back (48000.0f);
1089 sr.push_back (88200.0f);
1090 sr.push_back (96000.0f);
1091 sr.push_back (192000.0f);
1092 sr.push_back (384000.0f);
1095 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1096 s.push_back (rate_as_string (*x));
1097 if (*x == _desired_sample_rate) {
1103 sample_rate_combo.set_sensitive (true);
1104 set_popdown_strings (sample_rate_combo, s);
1106 if (desired.empty()) {
1107 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1109 sample_rate_combo.set_active_text (desired);
1113 sample_rate_combo.set_sensitive (false);
1118 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1120 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1121 vector<uint32_t> bs;
1124 if (_have_control) {
1125 bs = backend->available_buffer_sizes (device_name);
1126 } else if (backend->can_change_buffer_size_when_running()) {
1134 bs.push_back (1024);
1135 bs.push_back (2048);
1136 bs.push_back (4096);
1137 bs.push_back (8192);
1140 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1141 s.push_back (bufsize_as_string (*x));
1145 buffer_size_combo.set_sensitive (true);
1146 set_popdown_strings (buffer_size_combo, s);
1148 uint32_t period = backend->buffer_size();
1150 period = backend->default_buffer_size(device_name);
1152 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1153 show_buffer_duration ();
1155 buffer_size_combo.set_sensitive (false);
1160 EngineControl::device_changed ()
1162 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1165 string device_name_in;
1166 string device_name_out; // only used if backend support separate I/O devices
1168 if (backend->use_separate_input_and_output_devices()) {
1169 device_name_in = get_input_device_name ();
1170 device_name_out = get_output_device_name ();
1172 device_name_in = get_device_name ();
1175 /* we set the backend-device to query various device related intormation.
1176 * This has the side effect that backend->device_name() will match
1177 * the device_name and 'change_device' will never be true.
1178 * so work around this by setting...
1180 if (backend->use_separate_input_and_output_devices()) {
1181 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1182 queue_device_changed = true;
1185 if (device_name_in != backend->device_name()) {
1186 queue_device_changed = true;
1190 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1191 if (backend->use_separate_input_and_output_devices()) {
1192 backend->set_input_device_name (device_name_in);
1193 backend->set_output_device_name (device_name_out);
1195 backend->set_device_name(device_name_in);
1199 /* don't allow programmatic change to combos to cause a
1200 recursive call to this method.
1202 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1204 /* backends that support separate devices, need to ignore
1205 * the device-name - and use the devies set above
1207 set_samplerate_popdown_strings (device_name_in);
1208 set_buffersize_popdown_strings (device_name_in);
1209 /* XXX theoretically need to set min + max channel counts here
1212 manage_control_app_sensitivity ();
1215 /* pick up any saved state for this device */
1217 if (!ignore_changes) {
1218 maybe_display_saved_state ();
1223 EngineControl::input_device_changed ()
1225 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1227 string input_device_name = input_device_combo.get_active_text ();
1229 if (!ignore_changes && input_device_name != backend->input_device_name()) {
1230 queue_device_changed = true;
1233 backend->set_input_device_name(input_device_name);
1236 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1238 set_samplerate_popdown_strings (input_device_name);
1239 set_buffersize_popdown_strings (input_device_name);
1240 /* XXX theoretically need to set min + max channel counts here
1243 manage_control_app_sensitivity ();
1246 /* pick up any saved state for this device */
1248 if (!ignore_changes) {
1249 maybe_display_saved_state ();
1254 EngineControl::output_device_changed ()
1256 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1258 string output_device_name = output_device_combo.get_active_text ();
1260 if (!ignore_changes && output_device_name != backend->output_device_name()) {
1261 queue_device_changed = true;
1264 backend->set_output_device_name(output_device_name);
1267 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1269 set_samplerate_popdown_strings (output_device_name);
1270 set_buffersize_popdown_strings (output_device_name);
1271 /* XXX theoretically need to set min + max channel counts here
1274 manage_control_app_sensitivity ();
1277 /* pick up any saved state for this device */
1279 if (!ignore_changes) {
1280 maybe_display_saved_state ();
1285 EngineControl::bufsize_as_string (uint32_t sz)
1287 /* Translators: "samples" is always plural here, so no
1288 need for plural+singular forms.
1291 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1296 EngineControl::sample_rate_changed ()
1298 /* reset the strings for buffer size to show the correct msec value
1299 (reflecting the new sample rate).
1302 show_buffer_duration ();
1307 EngineControl::buffer_size_changed ()
1309 show_buffer_duration ();
1313 EngineControl::show_buffer_duration ()
1316 /* buffer sizes - convert from just samples to samples + msecs for
1317 * the displayed string
1320 string bs_text = buffer_size_combo.get_active_text ();
1321 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1322 uint32_t rate = get_rate();
1324 /* Developers: note the hard-coding of a double buffered model
1325 in the (2 * samples) computation of latency. we always start
1326 the audiobackend in this configuration.
1328 /* note to jack1 developers: ardour also always starts the engine
1329 * in async mode (no jack2 --sync option) which adds an extra cycle
1330 * of latency with jack2 (and *3 would be correct)
1331 * The value can also be wrong if jackd is started externally..
1333 * At the time of writing the ALSA backend always uses double-buffering *2,
1334 * The Dummy backend *1, and who knows what ASIO really does :)
1336 * So just display the period size, that's also what
1337 * ARDOUR_UI::update_sample_rate() does for the status bar.
1338 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1339 * but still, that's the buffer period, not [round-trip] latency)
1342 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1343 buffer_size_duration_label.set_text (buf);
1347 EngineControl::midi_option_changed ()
1349 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1352 backend->set_midi_option (get_midi_option());
1354 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1356 //_midi_devices.clear(); // TODO merge with state-saved settings..
1357 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1358 std::vector<MidiDeviceSettings> new_devices;
1360 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1361 MidiDeviceSettings mds = find_midi_device (i->name);
1362 if (i->available && !mds) {
1363 uint32_t input_latency = 0;
1364 uint32_t output_latency = 0;
1365 if (_can_set_midi_latencies) {
1366 input_latency = backend->systemic_midi_input_latency (i->name);
1367 output_latency = backend->systemic_midi_output_latency (i->name);
1369 bool enabled = backend->midi_device_enabled (i->name);
1370 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1371 new_devices.push_back (ptr);
1372 } else if (i->available) {
1373 new_devices.push_back (mds);
1376 _midi_devices = new_devices;
1378 if (_midi_devices.empty()) {
1379 midi_devices_button.set_sensitive (false);
1381 midi_devices_button.set_sensitive (true);
1386 EngineControl::parameter_changed ()
1390 EngineControl::State
1391 EngineControl::get_matching_state (
1392 const string& backend,
1393 const string& driver,
1394 const string& device)
1396 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1397 if ((*i)->backend == backend &&
1398 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1406 EngineControl::State
1407 EngineControl::get_matching_state (
1408 const string& backend,
1409 const string& driver,
1410 const string& input_device,
1411 const string& output_device)
1413 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1414 if ((*i)->backend == backend &&
1415 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1423 EngineControl::State
1424 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1426 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1429 if (backend->use_separate_input_and_output_devices ()) {
1430 return get_matching_state (backend_combo.get_active_text(),
1431 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1432 input_device_combo.get_active_text(),
1433 output_device_combo.get_active_text());
1435 return get_matching_state (backend_combo.get_active_text(),
1436 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1437 device_combo.get_active_text());
1441 return get_matching_state (backend_combo.get_active_text(),
1443 device_combo.get_active_text());
1446 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1447 const EngineControl::State& state2)
1449 if (state1->backend == state2->backend &&
1450 state1->driver == state2->driver &&
1451 state1->device == state2->device &&
1452 state1->input_device == state2->input_device &&
1453 state1->output_device == state2->output_device) {
1459 EngineControl::State
1460 EngineControl::save_state ()
1464 if (!_have_control) {
1465 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1469 state.reset(new StateStruct);
1470 state->backend = get_backend ();
1472 state.reset(new StateStruct);
1473 store_state (state);
1476 for (StateList::iterator i = states.begin(); i != states.end();) {
1477 if (equivalent_states (*i, state)) {
1478 i = states.erase(i);
1484 states.push_back (state);
1490 EngineControl::store_state (State state)
1492 state->backend = get_backend ();
1493 state->driver = get_driver ();
1494 state->device = get_device_name ();
1495 state->input_device = get_input_device_name ();
1496 state->output_device = get_output_device_name ();
1497 state->sample_rate = get_rate ();
1498 state->buffer_size = get_buffer_size ();
1499 state->input_latency = get_input_latency ();
1500 state->output_latency = get_output_latency ();
1501 state->input_channels = get_input_channels ();
1502 state->output_channels = get_output_channels ();
1503 state->midi_option = get_midi_option ();
1504 state->midi_devices = _midi_devices;
1508 EngineControl::maybe_display_saved_state ()
1510 if (!_have_control) {
1514 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1517 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1519 if (!_desired_sample_rate) {
1520 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1522 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1523 /* call this explicitly because we're ignoring changes to
1524 the controls at this point.
1526 show_buffer_duration ();
1527 input_latency.set_value (state->input_latency);
1528 output_latency.set_value (state->output_latency);
1530 if (!state->midi_option.empty()) {
1531 midi_option_combo.set_active_text (state->midi_option);
1532 _midi_devices = state->midi_devices;
1538 EngineControl::get_state ()
1540 XMLNode* root = new XMLNode ("AudioMIDISetup");
1543 if (!states.empty()) {
1544 XMLNode* state_nodes = new XMLNode ("EngineStates");
1546 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1548 XMLNode* node = new XMLNode ("State");
1550 node->add_property ("backend", (*i)->backend);
1551 node->add_property ("driver", (*i)->driver);
1552 node->add_property ("device", (*i)->device);
1553 node->add_property ("input-device", (*i)->input_device);
1554 node->add_property ("output-device", (*i)->output_device);
1555 node->add_property ("sample-rate", (*i)->sample_rate);
1556 node->add_property ("buffer-size", (*i)->buffer_size);
1557 node->add_property ("input-latency", (*i)->input_latency);
1558 node->add_property ("output-latency", (*i)->output_latency);
1559 node->add_property ("input-channels", (*i)->input_channels);
1560 node->add_property ("output-channels", (*i)->output_channels);
1561 node->add_property ("active", (*i)->active ? "yes" : "no");
1562 node->add_property ("midi-option", (*i)->midi_option);
1564 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1565 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1566 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1567 midi_device_stuff->add_property (X_("name"), (*p)->name);
1568 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1569 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1570 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1571 midi_devices->add_child_nocopy (*midi_device_stuff);
1573 node->add_child_nocopy (*midi_devices);
1575 state_nodes->add_child_nocopy (*node);
1578 root->add_child_nocopy (*state_nodes);
1585 EngineControl::set_state (const XMLNode& root)
1587 XMLNodeList clist, cclist;
1588 XMLNodeConstIterator citer, cciter;
1590 XMLNode* grandchild;
1591 XMLProperty* prop = NULL;
1593 fprintf (stderr, "EngineControl::set_state\n");
1595 if (root.name() != "AudioMIDISetup") {
1599 clist = root.children();
1603 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1607 if (child->name() != "EngineStates") {
1611 cclist = child->children();
1613 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1614 State state (new StateStruct);
1616 grandchild = *cciter;
1618 if (grandchild->name() != "State") {
1622 if ((prop = grandchild->property ("backend")) == 0) {
1625 state->backend = prop->value ();
1627 if ((prop = grandchild->property ("driver")) == 0) {
1630 state->driver = prop->value ();
1632 if ((prop = grandchild->property ("device")) == 0) {
1635 state->device = prop->value ();
1637 if ((prop = grandchild->property ("input-device")) == 0) {
1640 state->input_device = prop->value ();
1642 if ((prop = grandchild->property ("output-device")) == 0) {
1645 state->output_device = prop->value ();
1647 if ((prop = grandchild->property ("sample-rate")) == 0) {
1650 state->sample_rate = atof (prop->value ());
1652 if ((prop = grandchild->property ("buffer-size")) == 0) {
1655 state->buffer_size = atoi (prop->value ());
1657 if ((prop = grandchild->property ("input-latency")) == 0) {
1660 state->input_latency = atoi (prop->value ());
1662 if ((prop = grandchild->property ("output-latency")) == 0) {
1665 state->output_latency = atoi (prop->value ());
1667 if ((prop = grandchild->property ("input-channels")) == 0) {
1670 state->input_channels = atoi (prop->value ());
1672 if ((prop = grandchild->property ("output-channels")) == 0) {
1675 state->output_channels = atoi (prop->value ());
1677 if ((prop = grandchild->property ("active")) == 0) {
1680 state->active = string_is_affirmative (prop->value ());
1682 if ((prop = grandchild->property ("midi-option")) == 0) {
1685 state->midi_option = prop->value ();
1687 state->midi_devices.clear();
1689 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1690 const XMLNodeList mnc = midinode->children();
1691 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1692 if ((*n)->property (X_("name")) == 0
1693 || (*n)->property (X_("enabled")) == 0
1694 || (*n)->property (X_("input-latency")) == 0
1695 || (*n)->property (X_("output-latency")) == 0
1700 MidiDeviceSettings ptr (new MidiDeviceSetting(
1701 (*n)->property (X_("name"))->value (),
1702 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1703 atoi ((*n)->property (X_("input-latency"))->value ()),
1704 atoi ((*n)->property (X_("output-latency"))->value ())
1706 state->midi_devices.push_back (ptr);
1711 /* remove accumulated duplicates (due to bug in ealier version)
1712 * this can be removed again before release
1714 for (StateList::iterator i = states.begin(); i != states.end();) {
1715 if ((*i)->backend == state->backend &&
1716 (*i)->driver == state->driver &&
1717 (*i)->device == state->device) {
1718 i = states.erase(i);
1725 states.push_back (state);
1729 /* now see if there was an active state and switch the setup to it */
1731 // purge states of backend that are not available in this built
1732 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1733 vector<std::string> backend_names;
1735 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1736 backend_names.push_back((*i)->name);
1738 for (StateList::iterator i = states.begin(); i != states.end();) {
1739 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1740 i = states.erase(i);
1746 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1749 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1750 backend_combo.set_active_text ((*i)->backend);
1751 driver_combo.set_active_text ((*i)->driver);
1752 device_combo.set_active_text ((*i)->device);
1753 fprintf (stderr, "setting input device to: %s ", (*i)->input_device.c_str());
1754 input_device_combo.set_active_text ((*i)->input_device);
1755 fprintf (stderr, "setting output device to: %s ", (*i)->output_device.c_str());
1756 output_device_combo.set_active_text ((*i)->output_device);
1757 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1758 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1759 input_latency.set_value ((*i)->input_latency);
1760 output_latency.set_value ((*i)->output_latency);
1761 midi_option_combo.set_active_text ((*i)->midi_option);
1768 EngineControl::push_state_to_backend (bool start)
1770 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1776 /* figure out what is going to change */
1778 bool restart_required = false;
1779 bool was_running = ARDOUR::AudioEngine::instance()->running();
1780 bool change_driver = false;
1781 bool change_device = false;
1782 bool change_rate = false;
1783 bool change_bufsize = false;
1784 bool change_latency = false;
1785 bool change_channels = false;
1786 bool change_midi = false;
1788 uint32_t ochan = get_output_channels ();
1789 uint32_t ichan = get_input_channels ();
1791 if (_have_control) {
1793 if (started_at_least_once) {
1795 /* we can control the backend */
1797 if (backend->requires_driver_selection()) {
1798 if (get_driver() != backend->driver_name()) {
1799 change_driver = true;
1803 if (backend->use_separate_input_and_output_devices()) {
1804 if (get_input_device_name() != backend->input_device_name()) {
1805 change_device = true;
1807 if (get_output_device_name() != backend->output_device_name()) {
1808 change_device = true;
1811 if (get_device_name() != backend->device_name()) {
1812 change_device = true;
1816 if (queue_device_changed) {
1817 change_device = true;
1820 if (get_rate() != backend->sample_rate()) {
1824 if (get_buffer_size() != backend->buffer_size()) {
1825 change_bufsize = true;
1828 if (get_midi_option() != backend->midi_option()) {
1832 /* zero-requested channels means "all available" */
1835 ichan = backend->input_channels();
1839 ochan = backend->output_channels();
1842 if (ichan != backend->input_channels()) {
1843 change_channels = true;
1846 if (ochan != backend->output_channels()) {
1847 change_channels = true;
1850 if (get_input_latency() != backend->systemic_input_latency() ||
1851 get_output_latency() != backend->systemic_output_latency()) {
1852 change_latency = true;
1855 /* backend never started, so we have to force a group
1858 change_device = true;
1859 if (backend->requires_driver_selection()) {
1860 change_driver = true;
1863 change_bufsize = true;
1864 change_channels = true;
1865 change_latency = true;
1871 /* we have no control over the backend, meaning that we can
1872 * only possibly change sample rate and buffer size.
1876 if (get_rate() != backend->sample_rate()) {
1877 change_bufsize = true;
1880 if (get_buffer_size() != backend->buffer_size()) {
1881 change_bufsize = true;
1885 queue_device_changed = false;
1887 if (!_have_control) {
1889 /* We do not have control over the backend, so the best we can
1890 * do is try to change the sample rate and/or bufsize and get
1894 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1898 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1903 backend->set_sample_rate (get_rate());
1906 if (change_bufsize) {
1907 backend->set_buffer_size (get_buffer_size());
1911 if (ARDOUR::AudioEngine::instance()->start ()) {
1912 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1922 /* determine if we need to stop the backend before changing parameters */
1924 if (change_driver || change_device || change_channels || change_latency ||
1925 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1927 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1928 restart_required = true;
1930 restart_required = false;
1935 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1936 /* no changes in any parameters that absolutely require a
1937 * restart, so check those that might be changeable without a
1941 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1942 /* can't do this while running ... */
1943 restart_required = true;
1946 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1947 /* can't do this while running ... */
1948 restart_required = true;
1954 if (restart_required) {
1955 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1962 if (change_driver && backend->set_driver (get_driver())) {
1963 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1966 if (backend->use_separate_input_and_output_devices()) {
1967 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1968 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1971 if (change_device && backend->set_output_device_name (get_output_device_name())) {
1972 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
1976 if (change_device && backend->set_device_name (get_device_name())) {
1977 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1981 if (change_rate && backend->set_sample_rate (get_rate())) {
1982 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1985 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1986 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1990 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1991 if (backend->set_input_channels (get_input_channels())) {
1992 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1995 if (backend->set_output_channels (get_output_channels())) {
1996 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2000 if (change_latency) {
2001 if (backend->set_systemic_input_latency (get_input_latency())) {
2002 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2005 if (backend->set_systemic_output_latency (get_output_latency())) {
2006 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2012 backend->set_midi_option (get_midi_option());
2016 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2017 if (_measure_midi) {
2018 if (*p == _measure_midi) {
2019 backend->set_midi_device_enabled ((*p)->name, true);
2021 backend->set_midi_device_enabled ((*p)->name, false);
2025 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2026 if (backend->can_set_systemic_midi_latencies()) {
2027 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2028 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2033 if (start || (was_running && restart_required)) {
2034 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2045 EngineControl::post_push ()
2047 /* get a pointer to the current state object, creating one if
2051 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2054 state = save_state ();
2062 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2063 (*i)->active = false;
2066 /* mark this one active (to be used next time the dialog is
2070 state->active = true;
2072 if (_have_control) { // XXX
2073 manage_control_app_sensitivity ();
2076 /* schedule a redisplay of MIDI ports */
2077 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2082 EngineControl::get_rate () const
2084 float r = atof (sample_rate_combo.get_active_text ());
2085 /* the string may have been translated with an abbreviation for
2086 * thousands, so use a crude heuristic to fix this.
2096 EngineControl::get_buffer_size () const
2098 string txt = buffer_size_combo.get_active_text ();
2101 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2102 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2103 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2111 EngineControl::get_midi_option () const
2113 return midi_option_combo.get_active_text();
2117 EngineControl::get_input_channels() const
2119 if (ARDOUR::Profile->get_mixbus()) {
2120 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2121 if (!backend) return 0;
2122 return backend->input_channels();
2124 return (uint32_t) input_channels_adjustment.get_value();
2128 EngineControl::get_output_channels() const
2130 if (ARDOUR::Profile->get_mixbus()) {
2131 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2132 if (!backend) return 0;
2133 return backend->input_channels();
2135 return (uint32_t) output_channels_adjustment.get_value();
2139 EngineControl::get_input_latency() const
2141 return (uint32_t) input_latency_adjustment.get_value();
2145 EngineControl::get_output_latency() const
2147 return (uint32_t) output_latency_adjustment.get_value();
2151 EngineControl::get_backend () const
2153 return backend_combo.get_active_text ();
2157 EngineControl::get_driver () const
2159 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2160 return driver_combo.get_active_text ();
2167 EngineControl::get_device_name () const
2169 return device_combo.get_active_text ();
2173 EngineControl::get_input_device_name () const
2175 return input_device_combo.get_active_text ();
2179 EngineControl::get_output_device_name () const
2181 return output_device_combo.get_active_text ();
2185 EngineControl::control_app_button_clicked ()
2187 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2193 backend->launch_control_app ();
2197 EngineControl::manage_control_app_sensitivity ()
2199 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2205 string appname = backend->control_app_name();
2207 if (appname.empty()) {
2208 control_app_button.set_sensitive (false);
2210 control_app_button.set_sensitive (true);
2215 EngineControl::set_desired_sample_rate (uint32_t sr)
2217 _desired_sample_rate = sr;
2219 input_device_changed ();
2220 output_device_changed ();
2224 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2226 if (page_num == 0) {
2227 cancel_button->set_sensitive (true);
2228 ok_button->set_sensitive (true);
2229 apply_button->set_sensitive (true);
2230 _measure_midi.reset();
2232 cancel_button->set_sensitive (false);
2233 ok_button->set_sensitive (false);
2234 apply_button->set_sensitive (false);
2237 if (page_num == midi_tab) {
2239 refresh_midi_display ();
2242 if (page_num == latency_tab) {
2245 if (ARDOUR::AudioEngine::instance()->running()) {
2246 // TODO - mark as 'stopped for latency
2247 ARDOUR_UI::instance()->disconnect_from_engine ();
2251 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2253 /* save any existing latency values */
2255 uint32_t il = (uint32_t) input_latency.get_value ();
2256 uint32_t ol = (uint32_t) input_latency.get_value ();
2258 /* reset to zero so that our new test instance
2259 will be clean of any existing latency measures.
2261 NB. this should really be done by the backend
2262 when stated for latency measurement.
2265 input_latency.set_value (0);
2266 output_latency.set_value (0);
2268 push_state_to_backend (false);
2272 input_latency.set_value (il);
2273 output_latency.set_value (ol);
2276 // This should be done in push_state_to_backend()
2277 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2278 disable_latency_tab ();
2281 enable_latency_tab ();
2285 end_latency_detection ();
2286 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2291 /* latency measurement */
2294 EngineControl::check_audio_latency_measurement ()
2296 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2298 if (mtdm->resolve () < 0) {
2299 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2303 if (mtdm->err () > 0.3) {
2309 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2311 if (sample_rate == 0) {
2312 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2313 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2317 int frames_total = mtdm->del();
2318 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2320 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2321 _("Detected roundtrip latency: "),
2322 frames_total, frames_total * 1000.0f/sample_rate,
2323 _("Systemic latency: "),
2324 extra, extra * 1000.0f/sample_rate);
2328 if (mtdm->err () > 0.2) {
2330 strcat (buf, _("(signal detection error)"));
2336 strcat (buf, _("(inverted - bad wiring)"));
2340 lm_results.set_markup (string_compose (results_markup, buf));
2343 have_lm_results = true;
2344 end_latency_detection ();
2345 lm_use_button.set_sensitive (true);
2353 EngineControl::check_midi_latency_measurement ()
2355 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2357 if (!mididm->have_signal () || mididm->latency () == 0) {
2358 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2363 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2365 if (sample_rate == 0) {
2366 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2367 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2371 ARDOUR::framecnt_t frames_total = mididm->latency();
2372 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2373 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2374 _("Detected roundtrip latency: "),
2375 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2376 _("Systemic latency: "),
2377 extra, extra * 1000.0f / sample_rate);
2381 if (!mididm->ok ()) {
2383 strcat (buf, _("(averaging)"));
2387 if (mididm->deviation () > 50.0) {
2389 strcat (buf, _("(too large jitter)"));
2391 } else if (mididm->deviation () > 10.0) {
2393 strcat (buf, _("(large jitter)"));
2397 have_lm_results = true;
2398 end_latency_detection ();
2399 lm_use_button.set_sensitive (true);
2400 lm_results.set_markup (string_compose (results_markup, buf));
2402 } else if (mididm->processed () > 400) {
2403 have_lm_results = false;
2404 end_latency_detection ();
2405 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2409 lm_results.set_markup (string_compose (results_markup, buf));
2415 EngineControl::start_latency_detection ()
2417 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2418 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2420 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2421 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2422 if (_measure_midi) {
2423 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2425 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2427 lm_measure_label.set_text (_("Cancel"));
2428 have_lm_results = false;
2429 lm_use_button.set_sensitive (false);
2430 lm_input_channel_combo.set_sensitive (false);
2431 lm_output_channel_combo.set_sensitive (false);
2437 EngineControl::end_latency_detection ()
2439 latency_timeout.disconnect ();
2440 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2441 lm_measure_label.set_text (_("Measure"));
2442 if (!have_lm_results) {
2443 lm_use_button.set_sensitive (false);
2445 lm_input_channel_combo.set_sensitive (true);
2446 lm_output_channel_combo.set_sensitive (true);
2451 EngineControl::latency_button_clicked ()
2454 start_latency_detection ();
2456 end_latency_detection ();
2461 EngineControl::use_latency_button_clicked ()
2463 if (_measure_midi) {
2464 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2468 ARDOUR::framecnt_t frames_total = mididm->latency();
2469 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2470 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2471 _measure_midi->input_latency = one_way;
2472 _measure_midi->output_latency = one_way;
2473 notebook.set_current_page (midi_tab);
2475 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2481 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2482 one_way = std::max (0., one_way);
2484 input_latency_adjustment.set_value (one_way);
2485 output_latency_adjustment.set_value (one_way);
2487 /* back to settings page */
2488 notebook.set_current_page (0);
2494 EngineControl::on_delete_event (GdkEventAny* ev)
2496 if (notebook.get_current_page() == 2) {
2497 /* currently on latency tab - be sure to clean up */
2498 end_latency_detection ();
2500 return ArdourDialog::on_delete_event (ev);
2504 EngineControl::engine_running ()
2506 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2509 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2510 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2512 buffer_size_combo.set_sensitive (true);
2513 sample_rate_combo.set_sensitive (true);
2515 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2516 connect_disconnect_button.show();
2518 started_at_least_once = true;
2519 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2523 EngineControl::engine_stopped ()
2525 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2528 buffer_size_combo.set_sensitive (false);
2529 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2530 connect_disconnect_button.show();
2532 sample_rate_combo.set_sensitive (true);
2533 buffer_size_combo.set_sensitive (true);
2534 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2538 EngineControl::device_list_changed ()
2540 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2542 midi_option_changed();
2546 EngineControl::connect_disconnect_click()
2548 if (ARDOUR::AudioEngine::instance()->running()) {
2549 ARDOUR_UI::instance()->disconnect_from_engine ();
2551 ARDOUR_UI::instance()->reconnect_to_engine ();
2556 EngineControl::calibrate_audio_latency ()
2558 _measure_midi.reset ();
2559 have_lm_results = false;
2560 lm_use_button.set_sensitive (false);
2561 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2562 notebook.set_current_page (latency_tab);
2566 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2569 have_lm_results = false;
2570 lm_use_button.set_sensitive (false);
2571 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2572 notebook.set_current_page (latency_tab);
2576 EngineControl::configure_midi_devices ()
2578 notebook.set_current_page (midi_tab);