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 (_("%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);
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 LocaleGuard lg (X_("C"));
1542 XMLNode* root = new XMLNode ("AudioMIDISetup");
1545 if (!states.empty()) {
1546 XMLNode* state_nodes = new XMLNode ("EngineStates");
1548 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1550 XMLNode* node = new XMLNode ("State");
1552 node->add_property ("backend", (*i)->backend);
1553 node->add_property ("driver", (*i)->driver);
1554 node->add_property ("device", (*i)->device);
1555 node->add_property ("input-device", (*i)->input_device);
1556 node->add_property ("output-device", (*i)->output_device);
1557 node->add_property ("sample-rate", (*i)->sample_rate);
1558 node->add_property ("buffer-size", (*i)->buffer_size);
1559 node->add_property ("input-latency", (*i)->input_latency);
1560 node->add_property ("output-latency", (*i)->output_latency);
1561 node->add_property ("input-channels", (*i)->input_channels);
1562 node->add_property ("output-channels", (*i)->output_channels);
1563 node->add_property ("active", (*i)->active ? "yes" : "no");
1564 node->add_property ("midi-option", (*i)->midi_option);
1566 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1567 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1568 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1569 midi_device_stuff->add_property (X_("name"), (*p)->name);
1570 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1571 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1572 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1573 midi_devices->add_child_nocopy (*midi_device_stuff);
1575 node->add_child_nocopy (*midi_devices);
1577 state_nodes->add_child_nocopy (*node);
1580 root->add_child_nocopy (*state_nodes);
1587 EngineControl::set_state (const XMLNode& root)
1589 XMLNodeList clist, cclist;
1590 XMLNodeConstIterator citer, cciter;
1592 XMLNode* grandchild;
1593 XMLProperty* prop = NULL;
1595 fprintf (stderr, "EngineControl::set_state\n");
1597 if (root.name() != "AudioMIDISetup") {
1601 clist = root.children();
1605 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1609 if (child->name() != "EngineStates") {
1613 cclist = child->children();
1615 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1616 State state (new StateStruct);
1618 grandchild = *cciter;
1620 if (grandchild->name() != "State") {
1624 if ((prop = grandchild->property ("backend")) == 0) {
1627 state->backend = prop->value ();
1629 if ((prop = grandchild->property ("driver")) == 0) {
1632 state->driver = prop->value ();
1634 if ((prop = grandchild->property ("device")) == 0) {
1637 state->device = prop->value ();
1639 if ((prop = grandchild->property ("input-device")) == 0) {
1642 state->input_device = prop->value ();
1644 if ((prop = grandchild->property ("output-device")) == 0) {
1647 state->output_device = prop->value ();
1649 if ((prop = grandchild->property ("sample-rate")) == 0) {
1652 state->sample_rate = atof (prop->value ());
1654 if ((prop = grandchild->property ("buffer-size")) == 0) {
1657 state->buffer_size = atoi (prop->value ());
1659 if ((prop = grandchild->property ("input-latency")) == 0) {
1662 state->input_latency = atoi (prop->value ());
1664 if ((prop = grandchild->property ("output-latency")) == 0) {
1667 state->output_latency = atoi (prop->value ());
1669 if ((prop = grandchild->property ("input-channels")) == 0) {
1672 state->input_channels = atoi (prop->value ());
1674 if ((prop = grandchild->property ("output-channels")) == 0) {
1677 state->output_channels = atoi (prop->value ());
1679 if ((prop = grandchild->property ("active")) == 0) {
1682 state->active = string_is_affirmative (prop->value ());
1684 if ((prop = grandchild->property ("midi-option")) == 0) {
1687 state->midi_option = prop->value ();
1689 state->midi_devices.clear();
1691 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1692 const XMLNodeList mnc = midinode->children();
1693 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1694 if ((*n)->property (X_("name")) == 0
1695 || (*n)->property (X_("enabled")) == 0
1696 || (*n)->property (X_("input-latency")) == 0
1697 || (*n)->property (X_("output-latency")) == 0
1702 MidiDeviceSettings ptr (new MidiDeviceSetting(
1703 (*n)->property (X_("name"))->value (),
1704 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1705 atoi ((*n)->property (X_("input-latency"))->value ()),
1706 atoi ((*n)->property (X_("output-latency"))->value ())
1708 state->midi_devices.push_back (ptr);
1713 /* remove accumulated duplicates (due to bug in ealier version)
1714 * this can be removed again before release
1716 for (StateList::iterator i = states.begin(); i != states.end();) {
1717 if ((*i)->backend == state->backend &&
1718 (*i)->driver == state->driver &&
1719 (*i)->device == state->device) {
1720 i = states.erase(i);
1727 states.push_back (state);
1731 /* now see if there was an active state and switch the setup to it */
1733 // purge states of backend that are not available in this built
1734 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1735 vector<std::string> backend_names;
1737 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1738 backend_names.push_back((*i)->name);
1740 for (StateList::iterator i = states.begin(); i != states.end();) {
1741 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1742 i = states.erase(i);
1748 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1751 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1752 backend_combo.set_active_text ((*i)->backend);
1753 driver_combo.set_active_text ((*i)->driver);
1754 device_combo.set_active_text ((*i)->device);
1755 fprintf (stderr, "setting input device to: %s ", (*i)->input_device.c_str());
1756 input_device_combo.set_active_text ((*i)->input_device);
1757 fprintf (stderr, "setting output device to: %s ", (*i)->output_device.c_str());
1758 output_device_combo.set_active_text ((*i)->output_device);
1759 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1760 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1761 input_latency.set_value ((*i)->input_latency);
1762 output_latency.set_value ((*i)->output_latency);
1763 midi_option_combo.set_active_text ((*i)->midi_option);
1770 EngineControl::push_state_to_backend (bool start)
1772 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1778 /* figure out what is going to change */
1780 bool restart_required = false;
1781 bool was_running = ARDOUR::AudioEngine::instance()->running();
1782 bool change_driver = false;
1783 bool change_device = false;
1784 bool change_rate = false;
1785 bool change_bufsize = false;
1786 bool change_latency = false;
1787 bool change_channels = false;
1788 bool change_midi = false;
1790 uint32_t ochan = get_output_channels ();
1791 uint32_t ichan = get_input_channels ();
1793 if (_have_control) {
1795 if (started_at_least_once) {
1797 /* we can control the backend */
1799 if (backend->requires_driver_selection()) {
1800 if (get_driver() != backend->driver_name()) {
1801 change_driver = true;
1805 if (backend->use_separate_input_and_output_devices()) {
1806 if (get_input_device_name() != backend->input_device_name()) {
1807 change_device = true;
1809 if (get_output_device_name() != backend->output_device_name()) {
1810 change_device = true;
1813 if (get_device_name() != backend->device_name()) {
1814 change_device = true;
1818 if (queue_device_changed) {
1819 change_device = true;
1822 if (get_rate() != backend->sample_rate()) {
1826 if (get_buffer_size() != backend->buffer_size()) {
1827 change_bufsize = true;
1830 if (get_midi_option() != backend->midi_option()) {
1834 /* zero-requested channels means "all available" */
1837 ichan = backend->input_channels();
1841 ochan = backend->output_channels();
1844 if (ichan != backend->input_channels()) {
1845 change_channels = true;
1848 if (ochan != backend->output_channels()) {
1849 change_channels = true;
1852 if (get_input_latency() != backend->systemic_input_latency() ||
1853 get_output_latency() != backend->systemic_output_latency()) {
1854 change_latency = true;
1857 /* backend never started, so we have to force a group
1860 change_device = true;
1861 if (backend->requires_driver_selection()) {
1862 change_driver = true;
1865 change_bufsize = true;
1866 change_channels = true;
1867 change_latency = true;
1873 /* we have no control over the backend, meaning that we can
1874 * only possibly change sample rate and buffer size.
1878 if (get_rate() != backend->sample_rate()) {
1879 change_bufsize = true;
1882 if (get_buffer_size() != backend->buffer_size()) {
1883 change_bufsize = true;
1887 queue_device_changed = false;
1889 if (!_have_control) {
1891 /* We do not have control over the backend, so the best we can
1892 * do is try to change the sample rate and/or bufsize and get
1896 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1900 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1905 backend->set_sample_rate (get_rate());
1908 if (change_bufsize) {
1909 backend->set_buffer_size (get_buffer_size());
1913 if (ARDOUR::AudioEngine::instance()->start ()) {
1914 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1924 /* determine if we need to stop the backend before changing parameters */
1926 if (change_driver || change_device || change_channels || change_latency ||
1927 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1929 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1930 restart_required = true;
1932 restart_required = false;
1937 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1938 /* no changes in any parameters that absolutely require a
1939 * restart, so check those that might be changeable without a
1943 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1944 /* can't do this while running ... */
1945 restart_required = true;
1948 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1949 /* can't do this while running ... */
1950 restart_required = true;
1956 if (restart_required) {
1957 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1964 if (change_driver && backend->set_driver (get_driver())) {
1965 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1968 if (backend->use_separate_input_and_output_devices()) {
1969 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1970 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1973 if (change_device && backend->set_output_device_name (get_output_device_name())) {
1974 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
1978 if (change_device && backend->set_device_name (get_device_name())) {
1979 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1983 if (change_rate && backend->set_sample_rate (get_rate())) {
1984 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1987 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1988 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1992 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1993 if (backend->set_input_channels (get_input_channels())) {
1994 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1997 if (backend->set_output_channels (get_output_channels())) {
1998 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2002 if (change_latency) {
2003 if (backend->set_systemic_input_latency (get_input_latency())) {
2004 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2007 if (backend->set_systemic_output_latency (get_output_latency())) {
2008 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2014 backend->set_midi_option (get_midi_option());
2018 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2019 if (_measure_midi) {
2020 if (*p == _measure_midi) {
2021 backend->set_midi_device_enabled ((*p)->name, true);
2023 backend->set_midi_device_enabled ((*p)->name, false);
2027 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2028 if (backend->can_set_systemic_midi_latencies()) {
2029 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2030 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2035 if (start || (was_running && restart_required)) {
2036 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2047 EngineControl::post_push ()
2049 /* get a pointer to the current state object, creating one if
2053 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2056 state = save_state ();
2064 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2065 (*i)->active = false;
2068 /* mark this one active (to be used next time the dialog is
2072 state->active = true;
2074 if (_have_control) { // XXX
2075 manage_control_app_sensitivity ();
2078 /* schedule a redisplay of MIDI ports */
2079 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2084 EngineControl::get_rate () const
2086 float r = atof (sample_rate_combo.get_active_text ());
2087 /* the string may have been translated with an abbreviation for
2088 * thousands, so use a crude heuristic to fix this.
2098 EngineControl::get_buffer_size () const
2100 string txt = buffer_size_combo.get_active_text ();
2103 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2104 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2105 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2113 EngineControl::get_midi_option () const
2115 return midi_option_combo.get_active_text();
2119 EngineControl::get_input_channels() const
2121 if (ARDOUR::Profile->get_mixbus()) {
2122 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2123 if (!backend) return 0;
2124 return backend->input_channels();
2126 return (uint32_t) input_channels_adjustment.get_value();
2130 EngineControl::get_output_channels() const
2132 if (ARDOUR::Profile->get_mixbus()) {
2133 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2134 if (!backend) return 0;
2135 return backend->input_channels();
2137 return (uint32_t) output_channels_adjustment.get_value();
2141 EngineControl::get_input_latency() const
2143 return (uint32_t) input_latency_adjustment.get_value();
2147 EngineControl::get_output_latency() const
2149 return (uint32_t) output_latency_adjustment.get_value();
2153 EngineControl::get_backend () const
2155 return backend_combo.get_active_text ();
2159 EngineControl::get_driver () const
2161 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2162 return driver_combo.get_active_text ();
2169 EngineControl::get_device_name () const
2171 return device_combo.get_active_text ();
2175 EngineControl::get_input_device_name () const
2177 return input_device_combo.get_active_text ();
2181 EngineControl::get_output_device_name () const
2183 return output_device_combo.get_active_text ();
2187 EngineControl::control_app_button_clicked ()
2189 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2195 backend->launch_control_app ();
2199 EngineControl::manage_control_app_sensitivity ()
2201 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2207 string appname = backend->control_app_name();
2209 if (appname.empty()) {
2210 control_app_button.set_sensitive (false);
2212 control_app_button.set_sensitive (true);
2217 EngineControl::set_desired_sample_rate (uint32_t sr)
2219 _desired_sample_rate = sr;
2221 input_device_changed ();
2222 output_device_changed ();
2226 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2228 if (page_num == 0) {
2229 cancel_button->set_sensitive (true);
2230 ok_button->set_sensitive (true);
2231 apply_button->set_sensitive (true);
2232 _measure_midi.reset();
2234 cancel_button->set_sensitive (false);
2235 ok_button->set_sensitive (false);
2236 apply_button->set_sensitive (false);
2239 if (page_num == midi_tab) {
2241 refresh_midi_display ();
2244 if (page_num == latency_tab) {
2247 if (ARDOUR::AudioEngine::instance()->running()) {
2248 // TODO - mark as 'stopped for latency
2249 ARDOUR_UI::instance()->disconnect_from_engine ();
2253 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2255 /* save any existing latency values */
2257 uint32_t il = (uint32_t) input_latency.get_value ();
2258 uint32_t ol = (uint32_t) input_latency.get_value ();
2260 /* reset to zero so that our new test instance
2261 will be clean of any existing latency measures.
2263 NB. this should really be done by the backend
2264 when stated for latency measurement.
2267 input_latency.set_value (0);
2268 output_latency.set_value (0);
2270 push_state_to_backend (false);
2274 input_latency.set_value (il);
2275 output_latency.set_value (ol);
2278 // This should be done in push_state_to_backend()
2279 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2280 disable_latency_tab ();
2283 enable_latency_tab ();
2287 end_latency_detection ();
2288 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2293 /* latency measurement */
2296 EngineControl::check_audio_latency_measurement ()
2298 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2300 if (mtdm->resolve () < 0) {
2301 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2305 if (mtdm->err () > 0.3) {
2311 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2313 if (sample_rate == 0) {
2314 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2315 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2319 int frames_total = mtdm->del();
2320 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2322 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2323 _("Detected roundtrip latency: "),
2324 frames_total, frames_total * 1000.0f/sample_rate,
2325 _("Systemic latency: "),
2326 extra, extra * 1000.0f/sample_rate);
2330 if (mtdm->err () > 0.2) {
2332 strcat (buf, _("(signal detection error)"));
2338 strcat (buf, _("(inverted - bad wiring)"));
2342 lm_results.set_markup (string_compose (results_markup, buf));
2345 have_lm_results = true;
2346 end_latency_detection ();
2347 lm_use_button.set_sensitive (true);
2355 EngineControl::check_midi_latency_measurement ()
2357 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2359 if (!mididm->have_signal () || mididm->latency () == 0) {
2360 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2365 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2367 if (sample_rate == 0) {
2368 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2369 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2373 ARDOUR::framecnt_t frames_total = mididm->latency();
2374 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2375 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2376 _("Detected roundtrip latency: "),
2377 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2378 _("Systemic latency: "),
2379 extra, extra * 1000.0f / sample_rate);
2383 if (!mididm->ok ()) {
2385 strcat (buf, _("(averaging)"));
2389 if (mididm->deviation () > 50.0) {
2391 strcat (buf, _("(too large jitter)"));
2393 } else if (mididm->deviation () > 10.0) {
2395 strcat (buf, _("(large jitter)"));
2399 have_lm_results = true;
2400 end_latency_detection ();
2401 lm_use_button.set_sensitive (true);
2402 lm_results.set_markup (string_compose (results_markup, buf));
2404 } else if (mididm->processed () > 400) {
2405 have_lm_results = false;
2406 end_latency_detection ();
2407 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2411 lm_results.set_markup (string_compose (results_markup, buf));
2417 EngineControl::start_latency_detection ()
2419 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2420 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2422 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2423 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2424 if (_measure_midi) {
2425 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2427 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2429 lm_measure_label.set_text (_("Cancel"));
2430 have_lm_results = false;
2431 lm_use_button.set_sensitive (false);
2432 lm_input_channel_combo.set_sensitive (false);
2433 lm_output_channel_combo.set_sensitive (false);
2439 EngineControl::end_latency_detection ()
2441 latency_timeout.disconnect ();
2442 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2443 lm_measure_label.set_text (_("Measure"));
2444 if (!have_lm_results) {
2445 lm_use_button.set_sensitive (false);
2447 lm_input_channel_combo.set_sensitive (true);
2448 lm_output_channel_combo.set_sensitive (true);
2453 EngineControl::latency_button_clicked ()
2456 start_latency_detection ();
2458 end_latency_detection ();
2463 EngineControl::use_latency_button_clicked ()
2465 if (_measure_midi) {
2466 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2470 ARDOUR::framecnt_t frames_total = mididm->latency();
2471 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2472 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2473 _measure_midi->input_latency = one_way;
2474 _measure_midi->output_latency = one_way;
2475 notebook.set_current_page (midi_tab);
2477 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2483 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2484 one_way = std::max (0., one_way);
2486 input_latency_adjustment.set_value (one_way);
2487 output_latency_adjustment.set_value (one_way);
2489 /* back to settings page */
2490 notebook.set_current_page (0);
2496 EngineControl::on_delete_event (GdkEventAny* ev)
2498 if (notebook.get_current_page() == 2) {
2499 /* currently on latency tab - be sure to clean up */
2500 end_latency_detection ();
2502 return ArdourDialog::on_delete_event (ev);
2506 EngineControl::engine_running ()
2508 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2511 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2512 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2514 buffer_size_combo.set_sensitive (true);
2515 sample_rate_combo.set_sensitive (true);
2517 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2518 connect_disconnect_button.show();
2520 started_at_least_once = true;
2521 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2525 EngineControl::engine_stopped ()
2527 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2530 buffer_size_combo.set_sensitive (false);
2531 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2532 connect_disconnect_button.show();
2534 sample_rate_combo.set_sensitive (true);
2535 buffer_size_combo.set_sensitive (true);
2536 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2540 EngineControl::device_list_changed ()
2542 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2544 midi_option_changed();
2548 EngineControl::connect_disconnect_click()
2550 if (ARDOUR::AudioEngine::instance()->running()) {
2551 ARDOUR_UI::instance()->disconnect_from_engine ();
2553 ARDOUR_UI::instance()->reconnect_to_engine ();
2558 EngineControl::calibrate_audio_latency ()
2560 _measure_midi.reset ();
2561 have_lm_results = false;
2562 lm_use_button.set_sensitive (false);
2563 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2564 notebook.set_current_page (latency_tab);
2568 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2571 have_lm_results = false;
2572 lm_use_button.set_sensitive (false);
2573 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2574 notebook.set_current_page (latency_tab);
2578 EngineControl::configure_midi_devices ()
2580 notebook.set_current_page (midi_tab);