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"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
50 #include "ardour_ui.h"
51 #include "engine_dialog.h"
52 #include "gui_thread.h"
58 using namespace Gtkmm2ext;
62 static const unsigned int midi_tab = 2;
63 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
65 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
67 EngineControl::EngineControl ()
68 : ArdourDialog (_("Audio/MIDI Setup"))
70 , input_latency_adjustment (0, 0, 99999, 1)
71 , input_latency (input_latency_adjustment)
72 , output_latency_adjustment (0, 0, 99999, 1)
73 , output_latency (output_latency_adjustment)
74 , input_channels_adjustment (0, 0, 256, 1)
75 , input_channels (input_channels_adjustment)
76 , output_channels_adjustment (0, 0, 256, 1)
77 , output_channels (output_channels_adjustment)
78 , ports_adjustment (128, 8, 1024, 1, 16)
79 , ports_spinner (ports_adjustment)
80 , control_app_button (_("Device Control Panel"))
81 , midi_devices_button (_("Midi Device Setup"))
82 , lm_measure_label (_("Measure"))
83 , lm_use_button (_("Use results"))
84 , lm_back_button (_("Back to settings ... (ignore results)"))
85 , lm_button_audio (_("Calibrate Audio"))
87 , have_lm_results (false)
89 , midi_back_button (_("Back to settings"))
91 , _desired_sample_rate (0)
92 , started_at_least_once (false)
94 using namespace Notebook_Helpers;
95 vector<string> strings;
97 AttachOptions xopt = AttachOptions (FILL|EXPAND);
100 set_name (X_("AudioMIDISetup"));
102 /* the backend combo is the one thing that is ALWAYS visible */
104 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
106 if (backends.empty()) {
107 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));
109 throw failed_constructor ();
112 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
113 strings.push_back ((*b)->name);
116 set_popdown_strings (backend_combo, strings);
117 backend_combo.set_active_text (strings.front());
118 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
120 /* setup basic packing characteristics for the table used on the main
121 * tab of the notebook
124 basic_packer.set_spacings (6);
125 basic_packer.set_border_width (12);
126 basic_packer.set_homogeneous (false);
130 basic_hbox.pack_start (basic_packer, false, false);
132 /* latency measurement tab */
134 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
137 lm_table.set_row_spacings (12);
138 lm_table.set_col_spacings (6);
139 lm_table.set_homogeneous (false);
141 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
144 lm_preamble.set_width_chars (60);
145 lm_preamble.set_line_wrap (true);
146 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
148 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
151 Gtk::Label* preamble;
152 preamble = manage (new Label);
153 preamble->set_width_chars (60);
154 preamble->set_line_wrap (true);
155 preamble->set_markup (_("Select two channels below and connect them using a cable."));
157 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
160 label = manage (new Label (_("Output channel")));
161 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
163 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
164 misc_align->add (lm_output_channel_combo);
165 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
168 label = manage (new Label (_("Input channel")));
169 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
171 misc_align = manage (new Alignment (0.0, 0.5));
172 misc_align->add (lm_input_channel_combo);
173 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
176 xopt = AttachOptions(0);
178 lm_measure_label.set_padding (10, 10);
179 lm_measure_button.add (lm_measure_label);
180 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
181 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
182 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
184 lm_use_button.set_sensitive (false);
186 /* Increase the default spacing around the labels of these three
192 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
193 l->set_padding (10, 10);
196 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
197 l->set_padding (10, 10);
200 preamble = manage (new Label);
201 preamble->set_width_chars (60);
202 preamble->set_line_wrap (true);
203 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
204 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
207 preamble = manage (new Label);
208 preamble->set_width_chars (60);
209 preamble->set_line_wrap (true);
210 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
211 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
213 ++row; // skip a row in the table
214 ++row; // skip a row in the table
216 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
218 ++row; // skip a row in the table
219 ++row; // skip a row in the table
221 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
227 lm_vbox.set_border_width (12);
228 lm_vbox.pack_start (lm_table, false, false);
230 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
234 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
235 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
236 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
237 notebook.set_border_width (12);
239 notebook.set_show_tabs (false);
240 notebook.show_all ();
242 notebook.set_name ("SettingsNotebook");
244 /* packup the notebook */
246 get_vbox()->set_border_width (12);
247 get_vbox()->pack_start (notebook);
249 /* need a special function to print "all available channels" when the
250 * channel counts hit zero.
253 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
254 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
256 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
257 midi_devices_button.set_sensitive (false);
258 midi_devices_button.set_name ("generic button");
259 midi_devices_button.set_can_focus(true);
261 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
262 manage_control_app_sensitivity ();
264 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
265 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
266 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
268 /* Pick up any existing audio setup configuration, if appropriate */
270 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
272 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
273 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
274 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
278 set_state (*audio_setup);
281 /* ignore: don't save state */
282 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
286 /* Connect to signals */
288 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
289 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
290 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
291 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
292 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
294 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
295 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
296 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
297 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
299 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
303 EngineControl::on_response (int response_id)
305 ArdourDialog::on_response (response_id);
307 switch (response_id) {
309 push_state_to_backend (true);
312 push_state_to_backend (true);
315 case RESPONSE_DELETE_EVENT:
318 ev.type = GDK_BUTTON_PRESS;
320 on_delete_event ((GdkEventAny*) &ev);
329 EngineControl::build_notebook ()
332 AttachOptions xopt = AttachOptions (FILL|EXPAND);
334 /* clear the table */
336 Gtkmm2ext::container_clear (basic_vbox);
337 Gtkmm2ext::container_clear (basic_packer);
339 if (control_app_button.get_parent()) {
340 control_app_button.get_parent()->remove (control_app_button);
343 label = manage (left_aligned_label (_("Audio System:")));
344 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
345 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
347 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
348 lm_button_audio.set_name ("generic button");
349 lm_button_audio.set_can_focus(true);
352 build_full_control_notebook ();
354 build_no_control_notebook ();
357 basic_vbox.pack_start (basic_hbox, false, false);
360 Gtk::HBox* hpacker = manage (new HBox);
361 hpacker->set_border_width (12);
362 hpacker->pack_start (control_app_button, false, false);
364 control_app_button.show();
365 basic_vbox.pack_start (*hpacker);
368 basic_vbox.show_all ();
372 EngineControl::build_full_control_notebook ()
374 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
377 using namespace Notebook_Helpers;
379 vector<string> strings;
380 AttachOptions xopt = AttachOptions (FILL|EXPAND);
381 int row = 1; // row zero == backend combo
383 /* start packing it up */
385 if (backend->requires_driver_selection()) {
386 label = manage (left_aligned_label (_("Driver:")));
387 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
388 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
392 label = manage (left_aligned_label (_("Device:")));
393 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
394 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
397 label = manage (left_aligned_label (_("Sample rate:")));
398 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
399 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
403 label = manage (left_aligned_label (_("Buffer size:")));
404 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
405 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
406 buffer_size_duration_label.set_alignment (0.0); /* left-align */
407 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
410 input_channels.set_name ("InputChannels");
411 input_channels.set_flags (Gtk::CAN_FOCUS);
412 input_channels.set_digits (0);
413 input_channels.set_wrap (false);
414 output_channels.set_editable (true);
416 label = manage (left_aligned_label (_("Input Channels:")));
417 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
418 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
421 output_channels.set_name ("OutputChannels");
422 output_channels.set_flags (Gtk::CAN_FOCUS);
423 output_channels.set_digits (0);
424 output_channels.set_wrap (false);
425 output_channels.set_editable (true);
427 label = manage (left_aligned_label (_("Output Channels:")));
428 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
429 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
432 input_latency.set_name ("InputLatency");
433 input_latency.set_flags (Gtk::CAN_FOCUS);
434 input_latency.set_digits (0);
435 input_latency.set_wrap (false);
436 input_latency.set_editable (true);
438 label = manage (left_aligned_label (_("Hardware input latency:")));
439 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
440 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
441 label = manage (left_aligned_label (_("samples")));
442 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
445 output_latency.set_name ("OutputLatency");
446 output_latency.set_flags (Gtk::CAN_FOCUS);
447 output_latency.set_digits (0);
448 output_latency.set_wrap (false);
449 output_latency.set_editable (true);
451 label = manage (left_aligned_label (_("Hardware output latency:")));
452 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
453 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
454 label = manage (left_aligned_label (_("samples")));
455 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
457 /* button spans 2 rows */
459 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
462 label = manage (left_aligned_label (_("MIDI System")));
463 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
464 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
465 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
470 EngineControl::build_no_control_notebook ()
472 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
475 using namespace Notebook_Helpers;
477 vector<string> strings;
478 AttachOptions xopt = AttachOptions (FILL|EXPAND);
479 int row = 1; // row zero == backend combo
480 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
482 label = manage (new Label);
483 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
484 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
487 if (backend->can_change_sample_rate_when_running()) {
488 label = manage (left_aligned_label (_("Sample rate:")));
489 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
490 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
494 if (backend->can_change_buffer_size_when_running()) {
495 label = manage (left_aligned_label (_("Buffer size:")));
496 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
497 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
498 buffer_size_duration_label.set_alignment (0.0); /* left-align */
499 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
503 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
505 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
509 EngineControl::~EngineControl ()
511 ignore_changes = true;
515 EngineControl::disable_latency_tab ()
517 vector<string> empty;
518 set_popdown_strings (lm_output_channel_combo, empty);
519 set_popdown_strings (lm_input_channel_combo, empty);
520 lm_measure_button.set_sensitive (false);
521 lm_use_button.set_sensitive (false);
525 EngineControl::enable_latency_tab ()
527 vector<string> outputs;
528 vector<string> inputs;
530 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
531 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
532 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
535 lm_preamble.set_markup (_(""));
537 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
540 if (inputs.empty() || outputs.empty()) {
541 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
542 lm_measure_button.set_sensitive (false);
543 notebook.set_current_page (0);
548 if (!outputs.empty()) {
549 set_popdown_strings (lm_output_channel_combo, outputs);
550 lm_output_channel_combo.set_active_text (outputs.front());
551 lm_output_channel_combo.set_sensitive (true);
553 lm_output_channel_combo.set_sensitive (false);
556 if (!inputs.empty()) {
557 set_popdown_strings (lm_input_channel_combo, inputs);
558 lm_input_channel_combo.set_active_text (inputs.front());
559 lm_input_channel_combo.set_sensitive (true);
561 lm_input_channel_combo.set_sensitive (false);
564 lm_measure_button.set_sensitive (true);
568 EngineControl::setup_midi_tab_for_backend ()
570 string backend = backend_combo.get_active_text ();
572 Gtkmm2ext::container_clear (midi_vbox);
574 midi_vbox.set_border_width (12);
575 midi_device_table.set_border_width (12);
577 if (backend == "JACK") {
578 setup_midi_tab_for_jack ();
581 midi_vbox.pack_start (midi_device_table, true, true);
582 midi_vbox.pack_start (midi_back_button, false, false);
583 midi_vbox.show_all ();
587 EngineControl::setup_midi_tab_for_jack ()
592 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
594 device->input_latency = a->get_value();
596 device->output_latency = a->get_value();
601 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
602 b->set_active (!b->get_active());
603 device->enabled = b->get_active();
604 refresh_midi_display(device->name);
608 EngineControl::refresh_midi_display (std::string focus)
610 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
614 AttachOptions xopt = AttachOptions (FILL|EXPAND);
617 Gtkmm2ext::container_clear (midi_device_table);
619 midi_device_table.set_spacings (6);
621 l = manage (new Label);
622 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
623 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
624 l->set_alignment (0.5, 0.5);
628 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
629 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
630 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
631 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
633 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
634 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
635 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
636 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
639 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
644 bool enabled = (*p)->enabled;
646 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
647 m->set_name ("midi device");
648 m->set_can_focus (Gtk::CAN_FOCUS);
649 m->add_events (Gdk::BUTTON_RELEASE_MASK);
650 m->set_active (enabled);
651 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
652 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
653 if ((*p)->name == focus) {
657 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
658 s = manage (new Gtk::SpinButton (*a));
659 a->set_value ((*p)->input_latency);
660 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
661 s->set_sensitive (_can_set_midi_latencies && enabled);
662 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
664 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
665 s = manage (new Gtk::SpinButton (*a));
666 a->set_value ((*p)->output_latency);
667 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
668 s->set_sensitive (_can_set_midi_latencies && enabled);
669 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
671 b = manage (new Button (_("Calibrate")));
672 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
673 b->set_sensitive (_can_set_midi_latencies && enabled);
674 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
681 EngineControl::update_sensitivity ()
686 EngineControl::backend_changed ()
688 string backend_name = backend_combo.get_active_text();
689 boost::shared_ptr<ARDOUR::AudioBackend> backend;
691 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
692 /* eh? setting the backend failed... how ? */
696 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
699 setup_midi_tab_for_backend ();
700 _midi_devices.clear();
702 if (backend->requires_driver_selection()) {
703 vector<string> drivers = backend->enumerate_drivers();
704 driver_combo.set_sensitive (true);
706 if (!drivers.empty()) {
708 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
709 set_popdown_strings (driver_combo, drivers);
710 driver_combo.set_active_text (drivers.front());
717 driver_combo.set_sensitive (false);
718 /* this will change the device text which will cause a call to
719 * device changed which will set up parameters
724 vector<string> midi_options = backend->enumerate_midi_options();
726 if (midi_options.size() == 1) {
727 /* only contains the "none" option */
728 midi_option_combo.set_sensitive (false);
731 set_popdown_strings (midi_option_combo, midi_options);
732 midi_option_combo.set_active_text (midi_options.front());
733 midi_option_combo.set_sensitive (true);
735 midi_option_combo.set_sensitive (false);
739 midi_option_changed();
741 started_at_least_once = false;
743 if (!ignore_changes) {
744 maybe_display_saved_state ();
749 EngineControl::print_channel_count (Gtk::SpinButton* sb)
751 uint32_t cnt = (uint32_t) sb->get_value();
753 sb->set_text (_("all available channels"));
756 snprintf (buf, sizeof (buf), "%d", cnt);
763 EngineControl::list_devices ()
765 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
768 /* now fill out devices, mark sample rates, buffer sizes insensitive */
770 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
772 /* NOTE: Ardour currently does not display the "available" field of the
775 * Doing so would require a different GUI widget than the combo
776 * box/popdown that we currently use, since it has no way to list
777 * items that are not selectable. Something more like a popup menu,
778 * which could have unselectable items, would be appropriate.
781 vector<string> available_devices;
783 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
784 available_devices.push_back (i->name);
787 if (!available_devices.empty()) {
789 update_sensitivity ();
792 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
793 set_popdown_strings (device_combo, available_devices);
794 device_combo.set_active_text (available_devices.front());
799 ok_button->set_sensitive (true);
800 apply_button->set_sensitive (true);
803 device_combo.clear();
804 sample_rate_combo.set_sensitive (false);
805 buffer_size_combo.set_sensitive (false);
806 input_latency.set_sensitive (false);
807 output_latency.set_sensitive (false);
808 input_channels.set_sensitive (false);
809 output_channels.set_sensitive (false);
811 ok_button->set_sensitive (false);
812 apply_button->set_sensitive (false);
814 ok_button->set_sensitive (true);
815 apply_button->set_sensitive (true);
821 EngineControl::driver_changed ()
823 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
826 backend->set_driver (driver_combo.get_active_text());
829 if (!ignore_changes) {
830 maybe_display_saved_state ();
835 EngineControl::device_changed ()
838 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
840 string device_name = device_combo.get_active_text ();
844 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
846 /* don't allow programmatic change to combos to cause a
847 recursive call to this method.
857 sr = backend->available_sample_rates (device_name);
860 sr.push_back (8000.0f);
861 sr.push_back (16000.0f);
862 sr.push_back (32000.0f);
863 sr.push_back (44100.0f);
864 sr.push_back (48000.0f);
865 sr.push_back (88200.0f);
866 sr.push_back (96000.0f);
867 sr.push_back (192000.0f);
868 sr.push_back (384000.0f);
871 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
872 s.push_back (rate_as_string (*x));
873 if (*x == _desired_sample_rate) {
879 sample_rate_combo.set_sensitive (true);
880 set_popdown_strings (sample_rate_combo, s);
882 if (desired.empty()) {
883 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
885 sample_rate_combo.set_active_text (desired);
889 sample_rate_combo.set_sensitive (false);
897 bs = backend->available_buffer_sizes (device_name);
898 } else if (backend->can_change_buffer_size_when_running()) {
912 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
913 s.push_back (bufsize_as_string (*x));
917 buffer_size_combo.set_sensitive (true);
918 set_popdown_strings (buffer_size_combo, s);
920 buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
921 show_buffer_duration ();
923 buffer_size_combo.set_sensitive (false);
926 /* XXX theoretically need to set min + max channel counts here
929 manage_control_app_sensitivity ();
932 /* pick up any saved state for this device */
934 if (!ignore_changes) {
935 maybe_display_saved_state ();
940 EngineControl::bufsize_as_string (uint32_t sz)
942 /* Translators: "samples" is always plural here, so no
943 need for plural+singular forms.
946 snprintf (buf, sizeof (buf), _("%u samples"), sz);
951 EngineControl::sample_rate_changed ()
953 /* reset the strings for buffer size to show the correct msec value
954 (reflecting the new sample rate).
957 show_buffer_duration ();
958 if (!ignore_changes) {
965 EngineControl::buffer_size_changed ()
967 show_buffer_duration ();
968 if (!ignore_changes) {
974 EngineControl::show_buffer_duration ()
977 /* buffer sizes - convert from just samples to samples + msecs for
978 * the displayed string
981 string bs_text = buffer_size_combo.get_active_text ();
982 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
983 uint32_t rate = get_rate();
985 /* Translators: "msecs" is ALWAYS plural here, so we do not
986 need singular form as well.
988 /* Developers: note the hard-coding of a double buffered model
989 in the (2 * samples) computation of latency. we always start
990 the audiobackend in this configuration.
993 snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
994 buffer_size_duration_label.set_text (buf);
998 EngineControl::midi_option_changed ()
1000 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1003 backend->set_midi_option (get_midi_option());
1005 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1007 //_midi_devices.clear(); // TODO merge with state-saved settings..
1008 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1009 std::vector<MidiDeviceSettings> new_devices;
1011 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1012 MidiDeviceSettings mds = find_midi_device (i->name);
1013 if (i->available && !mds) {
1014 uint32_t input_latency = 0;
1015 uint32_t output_latency = 0;
1016 if (_can_set_midi_latencies) {
1017 input_latency = backend->systemic_midi_input_latency (i->name);
1018 output_latency = backend->systemic_midi_output_latency (i->name);
1020 bool enabled = backend->midi_device_enabled (i->name);
1021 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1022 new_devices.push_back (ptr);
1023 } else if (i->available) {
1024 new_devices.push_back (mds);
1027 _midi_devices = new_devices;
1029 if (_midi_devices.empty()) {
1030 midi_devices_button.set_sensitive (false);
1032 midi_devices_button.set_sensitive (true);
1035 if (!ignore_changes) {
1041 EngineControl::parameter_changed ()
1043 if (!ignore_changes) {
1048 EngineControl::State
1049 EngineControl::get_matching_state (
1050 const string& backend,
1051 const string& driver,
1052 const string& device)
1054 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1055 if ((*i)->backend == backend &&
1056 (*i)->driver == driver &&
1057 (*i)->device == device) {
1064 EngineControl::State
1065 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1067 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1070 return get_matching_state (backend_combo.get_active_text(),
1071 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1072 device_combo.get_active_text());
1076 return get_matching_state (backend_combo.get_active_text(),
1078 device_combo.get_active_text());
1081 EngineControl::State
1082 EngineControl::save_state ()
1084 if (!_have_control) {
1087 State state (new StateStruct);
1088 store_state (state);
1090 for (StateList::iterator i = states.begin(); i != states.end();) {
1091 if ((*i)->backend == state->backend &&
1092 (*i)->driver == state->driver &&
1093 (*i)->device == state->device) {
1094 i = states.erase(i);
1100 states.push_back (state);
1106 EngineControl::store_state (State state)
1108 state->backend = get_backend ();
1109 state->driver = get_driver ();
1110 state->device = get_device_name ();
1111 state->sample_rate = get_rate ();
1112 state->buffer_size = get_buffer_size ();
1113 state->input_latency = get_input_latency ();
1114 state->output_latency = get_output_latency ();
1115 state->input_channels = get_input_channels ();
1116 state->output_channels = get_output_channels ();
1117 state->midi_option = get_midi_option ();
1118 state->midi_devices = _midi_devices;
1122 EngineControl::maybe_display_saved_state ()
1124 if (!_have_control) {
1128 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1131 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1133 if (!_desired_sample_rate) {
1134 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1136 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1137 /* call this explicitly because we're ignoring changes to
1138 the controls at this point.
1140 show_buffer_duration ();
1141 input_latency.set_value (state->input_latency);
1142 output_latency.set_value (state->output_latency);
1144 if (!state->midi_option.empty()) {
1145 midi_option_combo.set_active_text (state->midi_option);
1146 _midi_devices = state->midi_devices;
1152 EngineControl::get_state ()
1154 XMLNode* root = new XMLNode ("AudioMIDISetup");
1157 if (!states.empty()) {
1158 XMLNode* state_nodes = new XMLNode ("EngineStates");
1160 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1162 XMLNode* node = new XMLNode ("State");
1164 node->add_property ("backend", (*i)->backend);
1165 node->add_property ("driver", (*i)->driver);
1166 node->add_property ("device", (*i)->device);
1167 node->add_property ("sample-rate", (*i)->sample_rate);
1168 node->add_property ("buffer-size", (*i)->buffer_size);
1169 node->add_property ("input-latency", (*i)->input_latency);
1170 node->add_property ("output-latency", (*i)->output_latency);
1171 node->add_property ("input-channels", (*i)->input_channels);
1172 node->add_property ("output-channels", (*i)->output_channels);
1173 node->add_property ("active", (*i)->active ? "yes" : "no");
1174 node->add_property ("midi-option", (*i)->midi_option);
1176 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1177 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1178 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1179 midi_device_stuff->add_property (X_("name"), (*p)->name);
1180 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1181 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1182 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1183 midi_devices->add_child_nocopy (*midi_device_stuff);
1185 node->add_child_nocopy (*midi_devices);
1187 state_nodes->add_child_nocopy (*node);
1190 root->add_child_nocopy (*state_nodes);
1197 EngineControl::set_state (const XMLNode& root)
1199 XMLNodeList clist, cclist;
1200 XMLNodeConstIterator citer, cciter;
1202 XMLNode* grandchild;
1203 XMLProperty* prop = NULL;
1205 if (root.name() != "AudioMIDISetup") {
1209 clist = root.children();
1213 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1217 if (child->name() != "EngineStates") {
1221 cclist = child->children();
1223 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1224 State state (new StateStruct);
1226 grandchild = *cciter;
1228 if (grandchild->name() != "State") {
1232 if ((prop = grandchild->property ("backend")) == 0) {
1235 state->backend = prop->value ();
1237 if ((prop = grandchild->property ("driver")) == 0) {
1240 state->driver = prop->value ();
1242 if ((prop = grandchild->property ("device")) == 0) {
1245 state->device = prop->value ();
1247 if ((prop = grandchild->property ("sample-rate")) == 0) {
1250 state->sample_rate = atof (prop->value ());
1252 if ((prop = grandchild->property ("buffer-size")) == 0) {
1255 state->buffer_size = atoi (prop->value ());
1257 if ((prop = grandchild->property ("input-latency")) == 0) {
1260 state->input_latency = atoi (prop->value ());
1262 if ((prop = grandchild->property ("output-latency")) == 0) {
1265 state->output_latency = atoi (prop->value ());
1267 if ((prop = grandchild->property ("input-channels")) == 0) {
1270 state->input_channels = atoi (prop->value ());
1272 if ((prop = grandchild->property ("output-channels")) == 0) {
1275 state->output_channels = atoi (prop->value ());
1277 if ((prop = grandchild->property ("active")) == 0) {
1280 state->active = string_is_affirmative (prop->value ());
1282 if ((prop = grandchild->property ("midi-option")) == 0) {
1285 state->midi_option = prop->value ();
1287 state->midi_devices.clear();
1289 if ((midinode = find_named_node (*grandchild, "MIDIDevices")) != 0) {
1290 const XMLNodeList mnc = midinode->children();
1291 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1292 if ((*n)->property (X_("name")) == 0
1293 || (*n)->property (X_("enabled")) == 0
1294 || (*n)->property (X_("input-latency")) == 0
1295 || (*n)->property (X_("output-latency")) == 0
1300 MidiDeviceSettings ptr (new MidiDeviceSetting(
1301 (*n)->property (X_("name"))->value (),
1302 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1303 atoi ((*n)->property (X_("input-latency"))->value ()),
1304 atoi ((*n)->property (X_("output-latency"))->value ())
1306 state->midi_devices.push_back (ptr);
1311 /* remove accumulated duplicates (due to bug in ealier version)
1312 * this can be removed again before release
1314 for (StateList::iterator i = states.begin(); i != states.end();) {
1315 if ((*i)->backend == state->backend &&
1316 (*i)->driver == state->driver &&
1317 (*i)->device == state->device) {
1318 i = states.erase(i);
1325 states.push_back (state);
1329 /* now see if there was an active state and switch the setup to it */
1331 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1335 backend_combo.set_active_text ((*i)->backend);
1336 driver_combo.set_active_text ((*i)->driver);
1337 device_combo.set_active_text ((*i)->device);
1338 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1339 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1340 input_latency.set_value ((*i)->input_latency);
1341 output_latency.set_value ((*i)->output_latency);
1342 midi_option_combo.set_active_text ((*i)->midi_option);
1350 EngineControl::push_state_to_backend (bool start)
1352 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1358 /* figure out what is going to change */
1360 bool restart_required = false;
1361 bool was_running = ARDOUR::AudioEngine::instance()->running();
1362 bool change_driver = false;
1363 bool change_device = false;
1364 bool change_rate = false;
1365 bool change_bufsize = false;
1366 bool change_latency = false;
1367 bool change_channels = false;
1368 bool change_midi = false;
1370 uint32_t ochan = get_output_channels ();
1371 uint32_t ichan = get_input_channels ();
1373 if (_have_control) {
1375 if (started_at_least_once) {
1377 /* we can control the backend */
1379 if (backend->requires_driver_selection()) {
1380 if (get_driver() != backend->driver_name()) {
1381 change_driver = true;
1385 if (get_device_name() != backend->device_name()) {
1386 change_device = true;
1389 if (get_rate() != backend->sample_rate()) {
1393 if (get_buffer_size() != backend->buffer_size()) {
1394 change_bufsize = true;
1397 if (get_midi_option() != backend->midi_option()) {
1401 /* zero-requested channels means "all available" */
1404 ichan = backend->input_channels();
1408 ochan = backend->output_channels();
1411 if (ichan != backend->input_channels()) {
1412 change_channels = true;
1415 if (ochan != backend->output_channels()) {
1416 change_channels = true;
1419 if (get_input_latency() != backend->systemic_input_latency() ||
1420 get_output_latency() != backend->systemic_output_latency()) {
1421 change_latency = true;
1424 /* backend never started, so we have to force a group
1427 change_device = true;
1428 if (backend->requires_driver_selection()) {
1429 change_driver = true;
1432 change_bufsize = true;
1433 change_channels = true;
1434 change_latency = true;
1440 /* we have no control over the backend, meaning that we can
1441 * only possibly change sample rate and buffer size.
1445 if (get_rate() != backend->sample_rate()) {
1446 change_bufsize = true;
1449 if (get_buffer_size() != backend->buffer_size()) {
1450 change_bufsize = true;
1454 if (!_have_control) {
1456 /* We do not have control over the backend, so the best we can
1457 * do is try to change the sample rate and/or bufsize and get
1461 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1465 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1470 backend->set_sample_rate (get_rate());
1473 if (change_bufsize) {
1474 backend->set_buffer_size (get_buffer_size());
1478 if (ARDOUR::AudioEngine::instance()->start ()) {
1479 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1489 /* determine if we need to stop the backend before changing parameters */
1491 if (change_driver || change_device || change_channels || change_latency ||
1492 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1494 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1495 restart_required = true;
1497 restart_required = false;
1502 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1503 /* no changes in any parameters that absolutely require a
1504 * restart, so check those that might be changeable without a
1508 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1509 /* can't do this while running ... */
1510 restart_required = true;
1513 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1514 /* can't do this while running ... */
1515 restart_required = true;
1521 if (restart_required) {
1522 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1529 if (change_driver && backend->set_driver (get_driver())) {
1530 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1533 if (change_device && backend->set_device_name (get_device_name())) {
1534 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1537 if (change_rate && backend->set_sample_rate (get_rate())) {
1538 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1541 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1542 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1546 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1547 if (backend->set_input_channels (get_input_channels())) {
1548 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1551 if (backend->set_output_channels (get_output_channels())) {
1552 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1556 if (change_latency) {
1557 if (backend->set_systemic_input_latency (get_input_latency())) {
1558 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1561 if (backend->set_systemic_output_latency (get_output_latency())) {
1562 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1568 backend->set_midi_option (get_midi_option());
1572 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1573 if (_measure_midi) {
1574 if (*p == _measure_midi) {
1575 backend->set_midi_device_enabled ((*p)->name, true);
1577 backend->set_midi_device_enabled ((*p)->name, false);
1581 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1582 if (backend->can_set_systemic_midi_latencies()) {
1583 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1584 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1589 if (start || (was_running && restart_required)) {
1590 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1601 EngineControl::post_push ()
1603 /* get a pointer to the current state object, creating one if
1607 if (_have_control) {
1608 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1611 state = save_state ();
1617 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1618 (*i)->active = false;
1621 /* mark this one active (to be used next time the dialog is
1625 state->active = true;
1627 manage_control_app_sensitivity ();
1630 /* schedule a redisplay of MIDI ports */
1631 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1636 EngineControl::get_rate () const
1638 float r = atof (sample_rate_combo.get_active_text ());
1639 /* the string may have been translated with an abbreviation for
1640 * thousands, so use a crude heuristic to fix this.
1650 EngineControl::get_buffer_size () const
1652 string txt = buffer_size_combo.get_active_text ();
1655 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1663 EngineControl::get_midi_option () const
1665 return midi_option_combo.get_active_text();
1669 EngineControl::get_input_channels() const
1671 return (uint32_t) input_channels_adjustment.get_value();
1675 EngineControl::get_output_channels() const
1677 return (uint32_t) output_channels_adjustment.get_value();
1681 EngineControl::get_input_latency() const
1683 return (uint32_t) input_latency_adjustment.get_value();
1687 EngineControl::get_output_latency() const
1689 return (uint32_t) output_latency_adjustment.get_value();
1693 EngineControl::get_backend () const
1695 return backend_combo.get_active_text ();
1699 EngineControl::get_driver () const
1701 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1702 return driver_combo.get_active_text ();
1709 EngineControl::get_device_name () const
1711 return device_combo.get_active_text ();
1715 EngineControl::control_app_button_clicked ()
1717 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1723 backend->launch_control_app ();
1727 EngineControl::manage_control_app_sensitivity ()
1729 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1735 string appname = backend->control_app_name();
1737 if (appname.empty()) {
1738 control_app_button.set_sensitive (false);
1740 control_app_button.set_sensitive (true);
1745 EngineControl::set_desired_sample_rate (uint32_t sr)
1747 _desired_sample_rate = sr;
1752 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1754 if (page_num == 0) {
1755 cancel_button->set_sensitive (true);
1756 ok_button->set_sensitive (true);
1757 apply_button->set_sensitive (true);
1758 _measure_midi.reset();
1760 cancel_button->set_sensitive (false);
1761 ok_button->set_sensitive (false);
1762 apply_button->set_sensitive (false);
1765 if (page_num == midi_tab) {
1767 refresh_midi_display ();
1770 if (page_num == latency_tab) {
1773 if (ARDOUR::AudioEngine::instance()->running()) {
1774 // TODO - mark as 'stopped for latency
1775 ARDOUR_UI::instance()->disconnect_from_engine ();
1779 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1781 /* save any existing latency values */
1783 uint32_t il = (uint32_t) input_latency.get_value ();
1784 uint32_t ol = (uint32_t) input_latency.get_value ();
1786 /* reset to zero so that our new test instance
1787 will be clean of any existing latency measures.
1789 NB. this should really be done by the backend
1790 when stated for latency measurement.
1793 input_latency.set_value (0);
1794 output_latency.set_value (0);
1796 push_state_to_backend (false);
1800 input_latency.set_value (il);
1801 output_latency.set_value (ol);
1804 // This should be done in push_state_to_backend()
1805 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1806 disable_latency_tab ();
1809 enable_latency_tab ();
1813 end_latency_detection ();
1814 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1819 /* latency measurement */
1822 EngineControl::check_audio_latency_measurement ()
1824 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1826 if (mtdm->resolve () < 0) {
1827 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1831 if (mtdm->err () > 0.3) {
1837 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1839 if (sample_rate == 0) {
1840 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1841 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1845 int frames_total = mtdm->del();
1846 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1848 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1849 _("Detected roundtrip latency: "),
1850 frames_total, frames_total * 1000.0f/sample_rate,
1851 _("Systemic latency: "),
1852 extra, extra * 1000.0f/sample_rate);
1856 if (mtdm->err () > 0.2) {
1858 strcat (buf, _("(signal detection error)"));
1864 strcat (buf, _("(inverted - bad wiring)"));
1869 end_latency_detection ();
1870 lm_use_button.set_sensitive (true);
1871 have_lm_results = true;
1874 lm_results.set_markup (string_compose (results_markup, buf));
1880 EngineControl::check_midi_latency_measurement ()
1882 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1884 if (!mididm->have_signal () || mididm->latency () == 0) {
1885 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1890 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1892 if (sample_rate == 0) {
1893 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1894 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1898 ARDOUR::framecnt_t frames_total = mididm->latency();
1899 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1900 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1901 _("Detected roundtrip latency: "),
1902 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1903 _("Systemic latency: "),
1904 extra, extra * 1000.0f / sample_rate);
1908 if (!mididm->ok ()) {
1910 strcat (buf, _("(averaging)"));
1914 if (mididm->deviation () > 50.0) {
1916 strcat (buf, _("(too large jitter)"));
1918 } else if (mididm->deviation () > 10.0) {
1920 strcat (buf, _("(large jitter)"));
1924 end_latency_detection ();
1925 lm_use_button.set_sensitive (true);
1926 have_lm_results = true;
1928 } else if (mididm->processed () > 400) {
1929 have_lm_results = false;
1930 end_latency_detection ();
1931 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
1935 lm_results.set_markup (string_compose (results_markup, buf));
1941 EngineControl::start_latency_detection ()
1943 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1944 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1946 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1947 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1948 if (_measure_midi) {
1949 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1951 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1953 lm_measure_label.set_text (_("Cancel"));
1954 have_lm_results = false;
1955 lm_use_button.set_sensitive (false);
1956 lm_input_channel_combo.set_sensitive (false);
1957 lm_output_channel_combo.set_sensitive (false);
1961 lm_back_button_signal.disconnect();
1962 if (_measure_midi) {
1963 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1965 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1970 EngineControl::end_latency_detection ()
1972 latency_timeout.disconnect ();
1973 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1974 lm_measure_label.set_text (_("Measure"));
1975 if (!have_lm_results) {
1976 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1978 lm_use_button.set_sensitive (false);
1980 lm_input_channel_combo.set_sensitive (true);
1981 lm_output_channel_combo.set_sensitive (true);
1986 EngineControl::latency_button_clicked ()
1989 start_latency_detection ();
1991 end_latency_detection ();
1996 EngineControl::use_latency_button_clicked ()
1998 if (_measure_midi) {
1999 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2003 ARDOUR::framecnt_t frames_total = mididm->latency();
2004 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2005 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2006 _measure_midi->input_latency = one_way;
2007 _measure_midi->output_latency = one_way;
2008 notebook.set_current_page (midi_tab);
2010 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2016 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2017 one_way = std::max (0., one_way);
2019 input_latency_adjustment.set_value (one_way);
2020 output_latency_adjustment.set_value (one_way);
2022 /* back to settings page */
2023 notebook.set_current_page (0);
2029 EngineControl::on_delete_event (GdkEventAny* ev)
2031 if (notebook.get_current_page() == 2) {
2032 /* currently on latency tab - be sure to clean up */
2033 end_latency_detection ();
2035 return ArdourDialog::on_delete_event (ev);
2039 EngineControl::engine_running ()
2041 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2044 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2045 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2047 buffer_size_combo.set_sensitive (true);
2048 sample_rate_combo.set_sensitive (true);
2050 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2052 started_at_least_once = true;
2056 EngineControl::engine_stopped ()
2058 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2061 buffer_size_combo.set_sensitive (false);
2062 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2064 sample_rate_combo.set_sensitive (true);
2065 buffer_size_combo.set_sensitive (true);
2069 EngineControl::connect_disconnect_click()
2071 if (ARDOUR::AudioEngine::instance()->running()) {
2072 ARDOUR_UI::instance()->disconnect_from_engine ();
2074 ARDOUR_UI::instance()->reconnect_to_engine ();
2079 EngineControl::calibrate_audio_latency ()
2081 _measure_midi.reset ();
2082 have_lm_results = false;
2083 lm_use_button.set_sensitive (false);
2084 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2085 notebook.set_current_page (latency_tab);
2089 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2092 have_lm_results = false;
2093 lm_use_button.set_sensitive (false);
2094 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2095 notebook.set_current_page (latency_tab);
2099 EngineControl::configure_midi_devices ()
2101 notebook.set_current_page (midi_tab);