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);
534 if (!ARDOUR::AudioEngine::instance()->running()) {
535 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
536 notebook.set_current_page (0);
540 else 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 notebook.set_current_page (0);
548 lm_preamble.set_markup (_(""));
550 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
553 set_popdown_strings (lm_output_channel_combo, outputs);
554 lm_output_channel_combo.set_active_text (outputs.front());
555 lm_output_channel_combo.set_sensitive (true);
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_measure_button.set_sensitive (true);
565 EngineControl::setup_midi_tab_for_backend ()
567 string backend = backend_combo.get_active_text ();
569 Gtkmm2ext::container_clear (midi_vbox);
571 midi_vbox.set_border_width (12);
572 midi_device_table.set_border_width (12);
574 if (backend == "JACK") {
575 setup_midi_tab_for_jack ();
578 midi_vbox.pack_start (midi_device_table, true, true);
579 midi_vbox.pack_start (midi_back_button, false, false);
580 midi_vbox.show_all ();
584 EngineControl::setup_midi_tab_for_jack ()
589 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
591 device->input_latency = a->get_value();
593 device->output_latency = a->get_value();
598 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
599 b->set_active (!b->get_active());
600 device->enabled = b->get_active();
601 refresh_midi_display(device->name);
605 EngineControl::refresh_midi_display (std::string focus)
607 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
611 AttachOptions xopt = AttachOptions (FILL|EXPAND);
614 Gtkmm2ext::container_clear (midi_device_table);
616 midi_device_table.set_spacings (6);
618 l = manage (new Label);
619 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
620 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
621 l->set_alignment (0.5, 0.5);
625 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
626 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
627 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
628 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
630 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
631 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
632 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
633 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
636 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
641 bool enabled = (*p)->enabled;
643 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
644 m->set_name ("midi device");
645 m->set_can_focus (Gtk::CAN_FOCUS);
646 m->add_events (Gdk::BUTTON_RELEASE_MASK);
647 m->set_active (enabled);
648 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
649 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
650 if ((*p)->name == focus) {
654 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
655 s = manage (new Gtk::SpinButton (*a));
656 a->set_value ((*p)->input_latency);
657 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
658 s->set_sensitive (_can_set_midi_latencies && enabled);
659 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
661 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
662 s = manage (new Gtk::SpinButton (*a));
663 a->set_value ((*p)->output_latency);
664 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
665 s->set_sensitive (_can_set_midi_latencies && enabled);
666 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
668 b = manage (new Button (_("Calibrate")));
669 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
670 b->set_sensitive (_can_set_midi_latencies && enabled);
671 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
678 EngineControl::update_sensitivity ()
683 EngineControl::backend_changed ()
685 string backend_name = backend_combo.get_active_text();
686 boost::shared_ptr<ARDOUR::AudioBackend> backend;
688 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
689 /* eh? setting the backend failed... how ? */
693 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
696 setup_midi_tab_for_backend ();
697 _midi_devices.clear();
699 if (backend->requires_driver_selection()) {
700 vector<string> drivers = backend->enumerate_drivers();
701 driver_combo.set_sensitive (true);
703 if (!drivers.empty()) {
705 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
706 set_popdown_strings (driver_combo, drivers);
707 driver_combo.set_active_text (drivers.front());
714 driver_combo.set_sensitive (false);
715 /* this will change the device text which will cause a call to
716 * device changed which will set up parameters
721 vector<string> midi_options = backend->enumerate_midi_options();
723 if (midi_options.size() == 1) {
724 /* only contains the "none" option */
725 midi_option_combo.set_sensitive (false);
728 set_popdown_strings (midi_option_combo, midi_options);
729 midi_option_combo.set_active_text (midi_options.front());
730 midi_option_combo.set_sensitive (true);
732 midi_option_combo.set_sensitive (false);
736 midi_option_changed();
738 started_at_least_once = false;
740 if (!ignore_changes) {
741 maybe_display_saved_state ();
746 EngineControl::print_channel_count (Gtk::SpinButton* sb)
748 uint32_t cnt = (uint32_t) sb->get_value();
750 sb->set_text (_("all available channels"));
753 snprintf (buf, sizeof (buf), "%d", cnt);
760 EngineControl::list_devices ()
762 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
765 /* now fill out devices, mark sample rates, buffer sizes insensitive */
767 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
769 /* NOTE: Ardour currently does not display the "available" field of the
772 * Doing so would require a different GUI widget than the combo
773 * box/popdown that we currently use, since it has no way to list
774 * items that are not selectable. Something more like a popup menu,
775 * which could have unselectable items, would be appropriate.
778 vector<string> available_devices;
780 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
781 available_devices.push_back (i->name);
784 if (!available_devices.empty()) {
786 update_sensitivity ();
789 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
790 set_popdown_strings (device_combo, available_devices);
791 device_combo.set_active_text (available_devices.front());
796 ok_button->set_sensitive (true);
797 apply_button->set_sensitive (true);
800 device_combo.clear();
801 sample_rate_combo.set_sensitive (false);
802 buffer_size_combo.set_sensitive (false);
803 input_latency.set_sensitive (false);
804 output_latency.set_sensitive (false);
805 input_channels.set_sensitive (false);
806 output_channels.set_sensitive (false);
808 ok_button->set_sensitive (false);
809 apply_button->set_sensitive (false);
811 ok_button->set_sensitive (true);
812 apply_button->set_sensitive (true);
818 EngineControl::driver_changed ()
820 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
823 backend->set_driver (driver_combo.get_active_text());
826 if (!ignore_changes) {
827 maybe_display_saved_state ();
832 EngineControl::device_changed ()
835 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
837 string device_name = device_combo.get_active_text ();
841 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
843 /* don't allow programmatic change to combos to cause a
844 recursive call to this method.
854 sr = backend->available_sample_rates (device_name);
857 sr.push_back (8000.0f);
858 sr.push_back (16000.0f);
859 sr.push_back (32000.0f);
860 sr.push_back (44100.0f);
861 sr.push_back (48000.0f);
862 sr.push_back (88200.0f);
863 sr.push_back (96000.0f);
864 sr.push_back (192000.0f);
865 sr.push_back (384000.0f);
868 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
869 s.push_back (rate_as_string (*x));
870 if (*x == _desired_sample_rate) {
876 sample_rate_combo.set_sensitive (true);
877 set_popdown_strings (sample_rate_combo, s);
879 if (desired.empty()) {
880 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
882 sample_rate_combo.set_active_text (desired);
886 sample_rate_combo.set_sensitive (false);
894 bs = backend->available_buffer_sizes (device_name);
895 } else if (backend->can_change_buffer_size_when_running()) {
909 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
910 s.push_back (bufsize_as_string (*x));
914 buffer_size_combo.set_sensitive (true);
915 set_popdown_strings (buffer_size_combo, s);
917 buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
918 show_buffer_duration ();
920 buffer_size_combo.set_sensitive (false);
923 /* XXX theoretically need to set min + max channel counts here
926 manage_control_app_sensitivity ();
929 /* pick up any saved state for this device */
931 if (!ignore_changes) {
932 maybe_display_saved_state ();
937 EngineControl::bufsize_as_string (uint32_t sz)
939 /* Translators: "samples" is always plural here, so no
940 need for plural+singular forms.
943 snprintf (buf, sizeof (buf), _("%u samples"), sz);
948 EngineControl::sample_rate_changed ()
950 /* reset the strings for buffer size to show the correct msec value
951 (reflecting the new sample rate).
954 show_buffer_duration ();
955 if (!ignore_changes) {
962 EngineControl::buffer_size_changed ()
964 show_buffer_duration ();
965 if (!ignore_changes) {
971 EngineControl::show_buffer_duration ()
974 /* buffer sizes - convert from just samples to samples + msecs for
975 * the displayed string
978 string bs_text = buffer_size_combo.get_active_text ();
979 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
980 uint32_t rate = get_rate();
982 /* Translators: "msecs" is ALWAYS plural here, so we do not
983 need singular form as well.
985 /* Developers: note the hard-coding of a double buffered model
986 in the (2 * samples) computation of latency. we always start
987 the audiobackend in this configuration.
990 snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
991 buffer_size_duration_label.set_text (buf);
995 EngineControl::midi_option_changed ()
997 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1000 backend->set_midi_option (get_midi_option());
1002 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1004 //_midi_devices.clear(); // TODO merge with state-saved settings..
1005 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1006 std::vector<MidiDeviceSettings> new_devices;
1008 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1009 MidiDeviceSettings mds = find_midi_device (i->name);
1010 if (i->available && !mds) {
1011 uint32_t input_latency = 0;
1012 uint32_t output_latency = 0;
1013 if (_can_set_midi_latencies) {
1014 input_latency = backend->systemic_midi_input_latency (i->name);
1015 output_latency = backend->systemic_midi_output_latency (i->name);
1017 bool enabled = backend->midi_device_enabled (i->name);
1018 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1019 new_devices.push_back (ptr);
1020 } else if (i->available) {
1021 new_devices.push_back (mds);
1024 _midi_devices = new_devices;
1026 if (_midi_devices.empty()) {
1027 midi_devices_button.set_sensitive (false);
1029 midi_devices_button.set_sensitive (true);
1032 if (!ignore_changes) {
1038 EngineControl::parameter_changed ()
1040 if (!ignore_changes) {
1045 EngineControl::State
1046 EngineControl::get_matching_state (
1047 const string& backend,
1048 const string& driver,
1049 const string& device)
1051 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1052 if ((*i)->backend == backend &&
1053 (*i)->driver == driver &&
1054 (*i)->device == device) {
1061 EngineControl::State
1062 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1064 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1067 return get_matching_state (backend_combo.get_active_text(),
1068 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1069 device_combo.get_active_text());
1073 return get_matching_state (backend_combo.get_active_text(),
1075 device_combo.get_active_text());
1078 EngineControl::State
1079 EngineControl::save_state ()
1081 if (!_have_control) {
1084 State state (new StateStruct);
1085 store_state (state);
1087 for (StateList::iterator i = states.begin(); i != states.end();) {
1088 if ((*i)->backend == state->backend &&
1089 (*i)->driver == state->driver &&
1090 (*i)->device == state->device) {
1091 i = states.erase(i);
1097 states.push_back (state);
1103 EngineControl::store_state (State state)
1105 state->backend = get_backend ();
1106 state->driver = get_driver ();
1107 state->device = get_device_name ();
1108 state->sample_rate = get_rate ();
1109 state->buffer_size = get_buffer_size ();
1110 state->input_latency = get_input_latency ();
1111 state->output_latency = get_output_latency ();
1112 state->input_channels = get_input_channels ();
1113 state->output_channels = get_output_channels ();
1114 state->midi_option = get_midi_option ();
1115 state->midi_devices = _midi_devices;
1119 EngineControl::maybe_display_saved_state ()
1121 if (!_have_control) {
1125 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1128 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1130 if (!_desired_sample_rate) {
1131 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1133 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1134 /* call this explicitly because we're ignoring changes to
1135 the controls at this point.
1137 show_buffer_duration ();
1138 input_latency.set_value (state->input_latency);
1139 output_latency.set_value (state->output_latency);
1141 if (!state->midi_option.empty()) {
1142 midi_option_combo.set_active_text (state->midi_option);
1143 _midi_devices = state->midi_devices;
1149 EngineControl::get_state ()
1151 XMLNode* root = new XMLNode ("AudioMIDISetup");
1154 if (!states.empty()) {
1155 XMLNode* state_nodes = new XMLNode ("EngineStates");
1157 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1159 XMLNode* node = new XMLNode ("State");
1161 node->add_property ("backend", (*i)->backend);
1162 node->add_property ("driver", (*i)->driver);
1163 node->add_property ("device", (*i)->device);
1164 node->add_property ("sample-rate", (*i)->sample_rate);
1165 node->add_property ("buffer-size", (*i)->buffer_size);
1166 node->add_property ("input-latency", (*i)->input_latency);
1167 node->add_property ("output-latency", (*i)->output_latency);
1168 node->add_property ("input-channels", (*i)->input_channels);
1169 node->add_property ("output-channels", (*i)->output_channels);
1170 node->add_property ("active", (*i)->active ? "yes" : "no");
1171 node->add_property ("midi-option", (*i)->midi_option);
1173 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1174 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1175 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1176 midi_device_stuff->add_property (X_("name"), (*p)->name);
1177 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1178 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1179 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1180 midi_devices->add_child_nocopy (*midi_device_stuff);
1182 node->add_child_nocopy (*midi_devices);
1184 state_nodes->add_child_nocopy (*node);
1187 root->add_child_nocopy (*state_nodes);
1194 EngineControl::set_state (const XMLNode& root)
1196 XMLNodeList clist, cclist;
1197 XMLNodeConstIterator citer, cciter;
1199 XMLNode* grandchild;
1200 XMLProperty* prop = NULL;
1202 if (root.name() != "AudioMIDISetup") {
1206 clist = root.children();
1210 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1214 if (child->name() != "EngineStates") {
1218 cclist = child->children();
1220 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1221 State state (new StateStruct);
1223 grandchild = *cciter;
1225 if (grandchild->name() != "State") {
1229 if ((prop = grandchild->property ("backend")) == 0) {
1232 state->backend = prop->value ();
1234 if ((prop = grandchild->property ("driver")) == 0) {
1237 state->driver = prop->value ();
1239 if ((prop = grandchild->property ("device")) == 0) {
1242 state->device = prop->value ();
1244 if ((prop = grandchild->property ("sample-rate")) == 0) {
1247 state->sample_rate = atof (prop->value ());
1249 if ((prop = grandchild->property ("buffer-size")) == 0) {
1252 state->buffer_size = atoi (prop->value ());
1254 if ((prop = grandchild->property ("input-latency")) == 0) {
1257 state->input_latency = atoi (prop->value ());
1259 if ((prop = grandchild->property ("output-latency")) == 0) {
1262 state->output_latency = atoi (prop->value ());
1264 if ((prop = grandchild->property ("input-channels")) == 0) {
1267 state->input_channels = atoi (prop->value ());
1269 if ((prop = grandchild->property ("output-channels")) == 0) {
1272 state->output_channels = atoi (prop->value ());
1274 if ((prop = grandchild->property ("active")) == 0) {
1277 state->active = string_is_affirmative (prop->value ());
1279 if ((prop = grandchild->property ("midi-option")) == 0) {
1282 state->midi_option = prop->value ();
1284 state->midi_devices.clear();
1286 if ((midinode = find_named_node (*grandchild, "MIDIDevices")) != 0) {
1287 const XMLNodeList mnc = midinode->children();
1288 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1289 if ((*n)->property (X_("name")) == 0
1290 || (*n)->property (X_("enabled")) == 0
1291 || (*n)->property (X_("input-latency")) == 0
1292 || (*n)->property (X_("output-latency")) == 0
1297 MidiDeviceSettings ptr (new MidiDeviceSetting(
1298 (*n)->property (X_("name"))->value (),
1299 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1300 atoi ((*n)->property (X_("input-latency"))->value ()),
1301 atoi ((*n)->property (X_("output-latency"))->value ())
1303 state->midi_devices.push_back (ptr);
1308 /* remove accumulated duplicates (due to bug in ealier version)
1309 * this can be removed again before release
1311 for (StateList::iterator i = states.begin(); i != states.end();) {
1312 if ((*i)->backend == state->backend &&
1313 (*i)->driver == state->driver &&
1314 (*i)->device == state->device) {
1315 i = states.erase(i);
1322 states.push_back (state);
1326 /* now see if there was an active state and switch the setup to it */
1328 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1332 backend_combo.set_active_text ((*i)->backend);
1333 driver_combo.set_active_text ((*i)->driver);
1334 device_combo.set_active_text ((*i)->device);
1335 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1336 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1337 input_latency.set_value ((*i)->input_latency);
1338 output_latency.set_value ((*i)->output_latency);
1339 midi_option_combo.set_active_text ((*i)->midi_option);
1347 EngineControl::push_state_to_backend (bool start)
1349 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1355 /* figure out what is going to change */
1357 bool restart_required = false;
1358 bool was_running = ARDOUR::AudioEngine::instance()->running();
1359 bool change_driver = false;
1360 bool change_device = false;
1361 bool change_rate = false;
1362 bool change_bufsize = false;
1363 bool change_latency = false;
1364 bool change_channels = false;
1365 bool change_midi = false;
1367 uint32_t ochan = get_output_channels ();
1368 uint32_t ichan = get_input_channels ();
1370 if (_have_control) {
1372 if (started_at_least_once) {
1374 /* we can control the backend */
1376 if (backend->requires_driver_selection()) {
1377 if (get_driver() != backend->driver_name()) {
1378 change_driver = true;
1382 if (get_device_name() != backend->device_name()) {
1383 change_device = true;
1386 if (get_rate() != backend->sample_rate()) {
1390 if (get_buffer_size() != backend->buffer_size()) {
1391 change_bufsize = true;
1394 if (get_midi_option() != backend->midi_option()) {
1398 /* zero-requested channels means "all available" */
1401 ichan = backend->input_channels();
1405 ochan = backend->output_channels();
1408 if (ichan != backend->input_channels()) {
1409 change_channels = true;
1412 if (ochan != backend->output_channels()) {
1413 change_channels = true;
1416 if (get_input_latency() != backend->systemic_input_latency() ||
1417 get_output_latency() != backend->systemic_output_latency()) {
1418 change_latency = true;
1421 /* backend never started, so we have to force a group
1424 change_device = true;
1425 if (backend->requires_driver_selection()) {
1426 change_driver = true;
1429 change_bufsize = true;
1430 change_channels = true;
1431 change_latency = true;
1437 /* we have no control over the backend, meaning that we can
1438 * only possibly change sample rate and buffer size.
1442 if (get_rate() != backend->sample_rate()) {
1443 change_bufsize = true;
1446 if (get_buffer_size() != backend->buffer_size()) {
1447 change_bufsize = true;
1451 if (!_have_control) {
1453 /* We do not have control over the backend, so the best we can
1454 * do is try to change the sample rate and/or bufsize and get
1458 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1462 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1467 backend->set_sample_rate (get_rate());
1470 if (change_bufsize) {
1471 backend->set_buffer_size (get_buffer_size());
1475 if (ARDOUR::AudioEngine::instance()->start ()) {
1476 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1486 /* determine if we need to stop the backend before changing parameters */
1488 if (change_driver || change_device || change_channels || change_latency ||
1489 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1491 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1492 restart_required = true;
1494 restart_required = false;
1499 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1500 /* no changes in any parameters that absolutely require a
1501 * restart, so check those that might be changeable without a
1505 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1506 /* can't do this while running ... */
1507 restart_required = true;
1510 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1511 /* can't do this while running ... */
1512 restart_required = true;
1518 if (restart_required) {
1519 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1526 if (change_driver && backend->set_driver (get_driver())) {
1527 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1530 if (change_device && backend->set_device_name (get_device_name())) {
1531 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1534 if (change_rate && backend->set_sample_rate (get_rate())) {
1535 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1538 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1539 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1543 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1544 if (backend->set_input_channels (get_input_channels())) {
1545 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1548 if (backend->set_output_channels (get_output_channels())) {
1549 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1553 if (change_latency) {
1554 if (backend->set_systemic_input_latency (get_input_latency())) {
1555 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1558 if (backend->set_systemic_output_latency (get_output_latency())) {
1559 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1565 backend->set_midi_option (get_midi_option());
1569 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1570 if (_measure_midi) {
1571 if (*p == _measure_midi) {
1572 backend->set_midi_device_enabled ((*p)->name, true);
1574 backend->set_midi_device_enabled ((*p)->name, false);
1578 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1579 if (backend->can_set_systemic_midi_latencies()) {
1580 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1581 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1586 if (start || (was_running && restart_required)) {
1587 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1598 EngineControl::post_push ()
1600 /* get a pointer to the current state object, creating one if
1604 if (_have_control) {
1605 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1608 state = save_state ();
1614 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1615 (*i)->active = false;
1618 /* mark this one active (to be used next time the dialog is
1622 state->active = true;
1624 manage_control_app_sensitivity ();
1627 /* schedule a redisplay of MIDI ports */
1628 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1633 EngineControl::get_rate () const
1635 float r = atof (sample_rate_combo.get_active_text ());
1636 /* the string may have been translated with an abbreviation for
1637 * thousands, so use a crude heuristic to fix this.
1647 EngineControl::get_buffer_size () const
1649 string txt = buffer_size_combo.get_active_text ();
1652 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1660 EngineControl::get_midi_option () const
1662 return midi_option_combo.get_active_text();
1666 EngineControl::get_input_channels() const
1668 return (uint32_t) input_channels_adjustment.get_value();
1672 EngineControl::get_output_channels() const
1674 return (uint32_t) output_channels_adjustment.get_value();
1678 EngineControl::get_input_latency() const
1680 return (uint32_t) input_latency_adjustment.get_value();
1684 EngineControl::get_output_latency() const
1686 return (uint32_t) output_latency_adjustment.get_value();
1690 EngineControl::get_backend () const
1692 return backend_combo.get_active_text ();
1696 EngineControl::get_driver () const
1698 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1699 return driver_combo.get_active_text ();
1706 EngineControl::get_device_name () const
1708 return device_combo.get_active_text ();
1712 EngineControl::control_app_button_clicked ()
1714 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1720 backend->launch_control_app ();
1724 EngineControl::manage_control_app_sensitivity ()
1726 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1732 string appname = backend->control_app_name();
1734 if (appname.empty()) {
1735 control_app_button.set_sensitive (false);
1737 control_app_button.set_sensitive (true);
1742 EngineControl::set_desired_sample_rate (uint32_t sr)
1744 _desired_sample_rate = sr;
1749 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1751 if (page_num == 0) {
1752 cancel_button->set_sensitive (true);
1753 ok_button->set_sensitive (true);
1754 apply_button->set_sensitive (true);
1755 _measure_midi.reset();
1757 cancel_button->set_sensitive (false);
1758 ok_button->set_sensitive (false);
1759 apply_button->set_sensitive (false);
1762 if (page_num == midi_tab) {
1764 refresh_midi_display ();
1767 if (page_num == latency_tab) {
1770 if (ARDOUR::AudioEngine::instance()->running()) {
1771 // TODO - mark as 'stopped for latency
1772 ARDOUR_UI::instance()->disconnect_from_engine ();
1776 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1778 /* save any existing latency values */
1780 uint32_t il = (uint32_t) input_latency.get_value ();
1781 uint32_t ol = (uint32_t) input_latency.get_value ();
1783 /* reset to zero so that our new test instance
1784 will be clean of any existing latency measures.
1786 NB. this should really be done by the backend
1787 when stated for latency measurement.
1790 input_latency.set_value (0);
1791 output_latency.set_value (0);
1793 push_state_to_backend (false);
1797 input_latency.set_value (il);
1798 output_latency.set_value (ol);
1801 // This should be done in push_state_to_backend()
1802 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1803 disable_latency_tab ();
1806 enable_latency_tab ();
1810 end_latency_detection ();
1811 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1816 /* latency measurement */
1819 EngineControl::check_audio_latency_measurement ()
1821 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1823 if (mtdm->resolve () < 0) {
1824 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1828 if (mtdm->err () > 0.3) {
1834 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1836 if (sample_rate == 0) {
1837 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1838 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1842 int frames_total = mtdm->del();
1843 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1845 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1846 _("Detected roundtrip latency: "),
1847 frames_total, frames_total * 1000.0f/sample_rate,
1848 _("Systemic latency: "),
1849 extra, extra * 1000.0f/sample_rate);
1853 if (mtdm->err () > 0.2) {
1855 strcat (buf, _("(signal detection error)"));
1861 strcat (buf, _("(inverted - bad wiring)"));
1866 have_lm_results = true;
1867 end_latency_detection ();
1868 lm_use_button.set_sensitive (true);
1872 lm_results.set_markup (string_compose (results_markup, buf));
1878 EngineControl::check_midi_latency_measurement ()
1880 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1882 if (!mididm->have_signal () || mididm->latency () == 0) {
1883 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1888 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1890 if (sample_rate == 0) {
1891 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1892 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1896 ARDOUR::framecnt_t frames_total = mididm->latency();
1897 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1898 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1899 _("Detected roundtrip latency: "),
1900 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1901 _("Systemic latency: "),
1902 extra, extra * 1000.0f / sample_rate);
1906 if (!mididm->ok ()) {
1908 strcat (buf, _("(averaging)"));
1912 if (mididm->deviation () > 50.0) {
1914 strcat (buf, _("(too large jitter)"));
1916 } else if (mididm->deviation () > 10.0) {
1918 strcat (buf, _("(large jitter)"));
1922 have_lm_results = true;
1923 end_latency_detection ();
1924 lm_use_button.set_sensitive (true);
1926 } else if (mididm->processed () > 400) {
1927 have_lm_results = false;
1928 end_latency_detection ();
1929 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
1933 lm_results.set_markup (string_compose (results_markup, buf));
1939 EngineControl::start_latency_detection ()
1941 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1942 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1944 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1945 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1946 if (_measure_midi) {
1947 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1949 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1951 lm_measure_label.set_text (_("Cancel"));
1952 have_lm_results = false;
1953 lm_use_button.set_sensitive (false);
1954 lm_input_channel_combo.set_sensitive (false);
1955 lm_output_channel_combo.set_sensitive (false);
1959 lm_back_button_signal.disconnect();
1960 if (_measure_midi) {
1961 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1963 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1968 EngineControl::end_latency_detection ()
1970 latency_timeout.disconnect ();
1971 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1972 lm_measure_label.set_text (_("Measure"));
1973 if (!have_lm_results) {
1974 lm_use_button.set_sensitive (false);
1976 lm_input_channel_combo.set_sensitive (true);
1977 lm_output_channel_combo.set_sensitive (true);
1982 EngineControl::latency_button_clicked ()
1985 start_latency_detection ();
1987 end_latency_detection ();
1992 EngineControl::use_latency_button_clicked ()
1994 if (_measure_midi) {
1995 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1999 ARDOUR::framecnt_t frames_total = mididm->latency();
2000 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2001 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2002 _measure_midi->input_latency = one_way;
2003 _measure_midi->output_latency = one_way;
2004 notebook.set_current_page (midi_tab);
2006 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2012 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2013 one_way = std::max (0., one_way);
2015 input_latency_adjustment.set_value (one_way);
2016 output_latency_adjustment.set_value (one_way);
2018 /* back to settings page */
2019 notebook.set_current_page (0);
2025 EngineControl::on_delete_event (GdkEventAny* ev)
2027 if (notebook.get_current_page() == 2) {
2028 /* currently on latency tab - be sure to clean up */
2029 end_latency_detection ();
2031 return ArdourDialog::on_delete_event (ev);
2035 EngineControl::engine_running ()
2037 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2040 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2041 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2043 buffer_size_combo.set_sensitive (true);
2044 sample_rate_combo.set_sensitive (true);
2046 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2048 started_at_least_once = true;
2052 EngineControl::engine_stopped ()
2054 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2057 buffer_size_combo.set_sensitive (false);
2058 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2060 sample_rate_combo.set_sensitive (true);
2061 buffer_size_combo.set_sensitive (true);
2065 EngineControl::connect_disconnect_click()
2067 if (ARDOUR::AudioEngine::instance()->running()) {
2068 ARDOUR_UI::instance()->disconnect_from_engine ();
2070 ARDOUR_UI::instance()->reconnect_to_engine ();
2075 EngineControl::calibrate_audio_latency ()
2077 _measure_midi.reset ();
2078 have_lm_results = false;
2079 lm_use_button.set_sensitive (false);
2080 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2081 notebook.set_current_page (latency_tab);
2085 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2088 have_lm_results = false;
2089 lm_use_button.set_sensitive (false);
2090 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2091 notebook.set_current_page (latency_tab);
2095 EngineControl::configure_midi_devices ()
2097 notebook.set_current_page (midi_tab);