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 foreground=\"red\" style=\"italic\" 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 Gtk::Label* preamble;
146 preamble = manage (new Label);
147 preamble->set_width_chars (60);
148 preamble->set_line_wrap (true);
149 preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
151 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
154 preamble = manage (new Label);
155 preamble->set_width_chars (60);
156 preamble->set_line_wrap (true);
157 preamble->set_markup (_("Select two channels below and connect them using a cable."));
159 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162 label = manage (new Label (_("Output channel")));
163 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
165 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
166 misc_align->add (lm_output_channel_combo);
167 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
170 label = manage (new Label (_("Input channel")));
171 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
173 misc_align = manage (new Alignment (0.0, 0.5));
174 misc_align->add (lm_input_channel_combo);
175 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
178 xopt = AttachOptions(0);
180 lm_measure_label.set_padding (10, 10);
181 lm_measure_button.add (lm_measure_label);
182 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
183 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
184 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
186 lm_use_button.set_sensitive (false);
188 /* Increase the default spacing around the labels of these three
194 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
195 l->set_padding (10, 10);
198 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
199 l->set_padding (10, 10);
202 preamble = manage (new Label);
203 preamble->set_width_chars (60);
204 preamble->set_line_wrap (true);
205 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
206 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
209 preamble = manage (new Label);
210 preamble->set_width_chars (60);
211 preamble->set_line_wrap (true);
212 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
213 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
215 ++row; // skip a row in the table
216 ++row; // skip a row in the table
218 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220 ++row; // skip a row in the table
221 ++row; // skip a row in the table
223 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
229 lm_vbox.set_border_width (12);
230 lm_vbox.pack_start (lm_table, false, false);
232 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
236 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
237 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
238 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
239 notebook.set_border_width (12);
241 notebook.set_show_tabs (false);
242 notebook.show_all ();
244 notebook.set_name ("SettingsNotebook");
246 /* packup the notebook */
248 get_vbox()->set_border_width (12);
249 get_vbox()->pack_start (notebook);
251 /* need a special function to print "all available channels" when the
252 * channel counts hit zero.
255 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
256 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
258 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
259 midi_devices_button.set_sensitive (false);
260 midi_devices_button.set_name ("generic button");
261 midi_devices_button.set_can_focus(true);
263 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
264 manage_control_app_sensitivity ();
266 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
267 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
268 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
270 /* Pick up any existing audio setup configuration, if appropriate */
272 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
274 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
275 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
276 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
279 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
282 maybe_display_saved_state();
284 /* Connect to signals */
286 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
287 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
288 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
289 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
290 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
292 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
293 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
294 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
295 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
298 set_state (*audio_setup);
301 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
305 EngineControl::on_response (int response_id)
307 ArdourDialog::on_response (response_id);
309 switch (response_id) {
311 push_state_to_backend (true);
314 push_state_to_backend (true);
317 case RESPONSE_DELETE_EVENT:
320 ev.type = GDK_BUTTON_PRESS;
322 on_delete_event ((GdkEventAny*) &ev);
331 EngineControl::build_notebook ()
334 AttachOptions xopt = AttachOptions (FILL|EXPAND);
336 /* clear the table */
338 Gtkmm2ext::container_clear (basic_vbox);
339 Gtkmm2ext::container_clear (basic_packer);
341 if (control_app_button.get_parent()) {
342 control_app_button.get_parent()->remove (control_app_button);
345 label = manage (left_aligned_label (_("Audio System:")));
346 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
347 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
349 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
350 lm_button_audio.set_name ("generic button");
351 lm_button_audio.set_can_focus(true);
354 build_full_control_notebook ();
356 build_no_control_notebook ();
359 basic_vbox.pack_start (basic_hbox, false, false);
362 Gtk::HBox* hpacker = manage (new HBox);
363 hpacker->set_border_width (12);
364 hpacker->pack_start (control_app_button, false, false);
366 control_app_button.show();
367 basic_vbox.pack_start (*hpacker);
370 basic_vbox.show_all ();
374 EngineControl::build_full_control_notebook ()
376 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
379 using namespace Notebook_Helpers;
381 vector<string> strings;
382 AttachOptions xopt = AttachOptions (FILL|EXPAND);
383 int row = 1; // row zero == backend combo
385 /* start packing it up */
387 if (backend->requires_driver_selection()) {
388 label = manage (left_aligned_label (_("Driver:")));
389 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
390 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
394 label = manage (left_aligned_label (_("Device:")));
395 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
396 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
399 label = manage (left_aligned_label (_("Sample rate:")));
400 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
401 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
405 label = manage (left_aligned_label (_("Buffer size:")));
406 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
407 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
408 buffer_size_duration_label.set_alignment (0.0); /* left-align */
409 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
412 input_channels.set_name ("InputChannels");
413 input_channels.set_flags (Gtk::CAN_FOCUS);
414 input_channels.set_digits (0);
415 input_channels.set_wrap (false);
416 output_channels.set_editable (true);
418 label = manage (left_aligned_label (_("Input Channels:")));
419 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
420 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
423 output_channels.set_name ("OutputChannels");
424 output_channels.set_flags (Gtk::CAN_FOCUS);
425 output_channels.set_digits (0);
426 output_channels.set_wrap (false);
427 output_channels.set_editable (true);
429 label = manage (left_aligned_label (_("Output Channels:")));
430 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
431 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
434 input_latency.set_name ("InputLatency");
435 input_latency.set_flags (Gtk::CAN_FOCUS);
436 input_latency.set_digits (0);
437 input_latency.set_wrap (false);
438 input_latency.set_editable (true);
440 label = manage (left_aligned_label (_("Hardware input latency:")));
441 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
442 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
443 label = manage (left_aligned_label (_("samples")));
444 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
447 output_latency.set_name ("OutputLatency");
448 output_latency.set_flags (Gtk::CAN_FOCUS);
449 output_latency.set_digits (0);
450 output_latency.set_wrap (false);
451 output_latency.set_editable (true);
453 label = manage (left_aligned_label (_("Hardware output latency:")));
454 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
455 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
456 label = manage (left_aligned_label (_("samples")));
457 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
459 /* button spans 2 rows */
461 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
464 label = manage (left_aligned_label (_("MIDI System")));
465 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
466 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
467 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
472 EngineControl::build_no_control_notebook ()
474 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
477 using namespace Notebook_Helpers;
479 vector<string> strings;
480 AttachOptions xopt = AttachOptions (FILL|EXPAND);
481 int row = 1; // row zero == backend combo
482 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
484 label = manage (new Label);
485 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
486 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
489 if (backend->can_change_sample_rate_when_running()) {
490 label = manage (left_aligned_label (_("Sample rate:")));
491 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
492 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
496 if (backend->can_change_buffer_size_when_running()) {
497 label = manage (left_aligned_label (_("Buffer size:")));
498 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
499 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
500 buffer_size_duration_label.set_alignment (0.0); /* left-align */
501 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
505 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
507 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
511 EngineControl::~EngineControl ()
513 ignore_changes = true;
517 EngineControl::disable_latency_tab ()
519 vector<string> empty;
520 set_popdown_strings (lm_output_channel_combo, empty);
521 set_popdown_strings (lm_input_channel_combo, empty);
522 lm_measure_button.set_sensitive (false);
523 lm_use_button.set_sensitive (false);
527 EngineControl::enable_latency_tab ()
529 vector<string> outputs;
530 vector<string> inputs;
532 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
533 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
534 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
536 if (inputs.empty() || outputs.empty()) {
537 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
538 lm_measure_button.set_sensitive (false);
539 notebook.set_current_page (0);
544 if (!outputs.empty()) {
545 set_popdown_strings (lm_output_channel_combo, outputs);
546 lm_output_channel_combo.set_active_text (outputs.front());
547 lm_output_channel_combo.set_sensitive (true);
549 lm_output_channel_combo.set_sensitive (false);
552 if (!inputs.empty()) {
553 set_popdown_strings (lm_input_channel_combo, inputs);
554 lm_input_channel_combo.set_active_text (inputs.front());
555 lm_input_channel_combo.set_sensitive (true);
557 lm_input_channel_combo.set_sensitive (false);
560 lm_measure_button.set_sensitive (true);
564 EngineControl::setup_midi_tab_for_backend ()
566 string backend = backend_combo.get_active_text ();
568 Gtkmm2ext::container_clear (midi_vbox);
570 midi_vbox.set_border_width (12);
571 midi_device_table.set_border_width (12);
573 if (backend == "JACK") {
574 setup_midi_tab_for_jack ();
577 midi_vbox.pack_start (midi_device_table, true, true);
578 midi_vbox.pack_start (midi_back_button, false, false);
579 midi_vbox.show_all ();
583 EngineControl::setup_midi_tab_for_jack ()
588 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
590 device->input_latency = a->get_value();
592 device->output_latency = a->get_value();
597 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
598 b->set_active (!b->get_active());
599 device->enabled = b->get_active();
600 refresh_midi_display(device->name);
604 EngineControl::refresh_midi_display (std::string focus)
606 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
610 AttachOptions xopt = AttachOptions (FILL|EXPAND);
613 Gtkmm2ext::container_clear (midi_device_table);
615 midi_device_table.set_spacings (6);
617 l = manage (new Label);
618 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
619 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
620 l->set_alignment (0.5, 0.5);
624 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
625 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
626 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
627 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
629 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
630 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
631 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
632 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
635 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
640 bool enabled = (*p)->enabled;
642 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
643 m->set_name ("midi device");
644 m->set_can_focus (Gtk::CAN_FOCUS);
645 m->add_events (Gdk::BUTTON_RELEASE_MASK);
646 m->set_active (enabled);
647 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
648 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
649 if ((*p)->name == focus) {
653 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
654 s = manage (new Gtk::SpinButton (*a));
655 a->set_value ((*p)->input_latency);
656 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
657 s->set_sensitive (_can_set_midi_latencies && enabled);
658 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
660 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
661 s = manage (new Gtk::SpinButton (*a));
662 a->set_value ((*p)->output_latency);
663 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
664 s->set_sensitive (_can_set_midi_latencies && enabled);
665 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
667 b = manage (new Button (_("Calibrate")));
668 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
669 b->set_sensitive (_can_set_midi_latencies && enabled);
670 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
677 EngineControl::update_sensitivity ()
682 EngineControl::backend_changed ()
684 string backend_name = backend_combo.get_active_text();
685 boost::shared_ptr<ARDOUR::AudioBackend> backend;
687 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
688 /* eh? setting the backend failed... how ? */
692 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
695 setup_midi_tab_for_backend ();
696 _midi_devices.clear();
698 if (backend->requires_driver_selection()) {
699 vector<string> drivers = backend->enumerate_drivers();
700 driver_combo.set_sensitive (true);
702 if (!drivers.empty()) {
704 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
705 set_popdown_strings (driver_combo, drivers);
706 driver_combo.set_active_text (drivers.front());
713 driver_combo.set_sensitive (false);
714 /* this will change the device text which will cause a call to
715 * device changed which will set up parameters
720 vector<string> midi_options = backend->enumerate_midi_options();
722 if (midi_options.size() == 1) {
723 /* only contains the "none" option */
724 midi_option_combo.set_sensitive (false);
727 set_popdown_strings (midi_option_combo, midi_options);
728 midi_option_combo.set_active_text (midi_options.front());
729 midi_option_combo.set_sensitive (true);
731 midi_option_combo.set_sensitive (false);
735 midi_option_changed();
737 started_at_least_once = false;
739 if (!ignore_changes) {
740 maybe_display_saved_state ();
745 EngineControl::print_channel_count (Gtk::SpinButton* sb)
747 uint32_t cnt = (uint32_t) sb->get_value();
749 sb->set_text (_("all available channels"));
752 snprintf (buf, sizeof (buf), "%d", cnt);
759 EngineControl::list_devices ()
761 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
764 /* now fill out devices, mark sample rates, buffer sizes insensitive */
766 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
768 /* NOTE: Ardour currently does not display the "available" field of the
771 * Doing so would require a different GUI widget than the combo
772 * box/popdown that we currently use, since it has no way to list
773 * items that are not selectable. Something more like a popup menu,
774 * which could have unselectable items, would be appropriate.
777 vector<string> available_devices;
779 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
780 available_devices.push_back (i->name);
783 if (!available_devices.empty()) {
785 update_sensitivity ();
788 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
789 set_popdown_strings (device_combo, available_devices);
790 device_combo.set_active_text (available_devices.front());
795 ok_button->set_sensitive (true);
796 apply_button->set_sensitive (true);
799 sample_rate_combo.set_sensitive (false);
800 buffer_size_combo.set_sensitive (false);
801 input_latency.set_sensitive (false);
802 output_latency.set_sensitive (false);
803 input_channels.set_sensitive (false);
804 output_channels.set_sensitive (false);
806 ok_button->set_sensitive (false);
807 apply_button->set_sensitive (false);
809 ok_button->set_sensitive (true);
810 apply_button->set_sensitive (true);
816 EngineControl::driver_changed ()
818 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
821 backend->set_driver (driver_combo.get_active_text());
824 if (!ignore_changes) {
825 maybe_display_saved_state ();
830 EngineControl::device_changed ()
833 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
835 string device_name = device_combo.get_active_text ();
839 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
841 /* don't allow programmatic change to combos to cause a
842 recursive call to this method.
852 sr = backend->available_sample_rates (device_name);
855 sr.push_back (8000.0f);
856 sr.push_back (16000.0f);
857 sr.push_back (32000.0f);
858 sr.push_back (44100.0f);
859 sr.push_back (48000.0f);
860 sr.push_back (88200.0f);
861 sr.push_back (96000.0f);
862 sr.push_back (192000.0f);
863 sr.push_back (384000.0f);
866 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
867 s.push_back (rate_as_string (*x));
868 if (*x == _desired_sample_rate) {
874 sample_rate_combo.set_sensitive (true);
875 set_popdown_strings (sample_rate_combo, s);
877 if (desired.empty()) {
878 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
880 sample_rate_combo.set_active_text (desired);
884 sample_rate_combo.set_sensitive (false);
892 bs = backend->available_buffer_sizes (device_name);
893 } else if (backend->can_change_buffer_size_when_running()) {
907 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
908 s.push_back (bufsize_as_string (*x));
912 buffer_size_combo.set_sensitive (true);
913 set_popdown_strings (buffer_size_combo, s);
915 buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
916 show_buffer_duration ();
918 buffer_size_combo.set_sensitive (false);
921 /* XXX theoretically need to set min + max channel counts here
924 manage_control_app_sensitivity ();
927 /* pick up any saved state for this device */
929 if (!ignore_changes) {
930 maybe_display_saved_state ();
935 EngineControl::bufsize_as_string (uint32_t sz)
937 /* Translators: "samples" is always plural here, so no
938 need for plural+singular forms.
941 snprintf (buf, sizeof (buf), _("%u samples"), sz);
946 EngineControl::sample_rate_changed ()
948 /* reset the strings for buffer size to show the correct msec value
949 (reflecting the new sample rate).
952 show_buffer_duration ();
953 if (!ignore_changes) {
960 EngineControl::buffer_size_changed ()
962 show_buffer_duration ();
963 if (!ignore_changes) {
969 EngineControl::show_buffer_duration ()
972 /* buffer sizes - convert from just samples to samples + msecs for
973 * the displayed string
976 string bs_text = buffer_size_combo.get_active_text ();
977 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
978 uint32_t rate = get_rate();
980 /* Translators: "msecs" is ALWAYS plural here, so we do not
981 need singular form as well.
983 /* Developers: note the hard-coding of a double buffered model
984 in the (2 * samples) computation of latency. we always start
985 the audiobackend in this configuration.
988 snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
989 buffer_size_duration_label.set_text (buf);
993 EngineControl::midi_option_changed ()
995 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
998 backend->set_midi_option (get_midi_option());
1000 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1002 //_midi_devices.clear(); // TODO merge with state-saved settings..
1003 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1004 std::vector<MidiDeviceSettings> new_devices;
1006 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1007 MidiDeviceSettings mds = find_midi_device (i->name);
1008 if (i->available && !mds) {
1009 uint32_t input_latency = 0;
1010 uint32_t output_latency = 0;
1011 if (_can_set_midi_latencies) {
1012 input_latency = backend->systemic_midi_input_latency (i->name);
1013 output_latency = backend->systemic_midi_output_latency (i->name);
1015 bool enabled = backend->midi_device_enabled (i->name);
1016 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1017 new_devices.push_back (ptr);
1018 } else if (i->available) {
1019 new_devices.push_back (mds);
1022 _midi_devices = new_devices;
1024 if (_midi_devices.empty()) {
1025 midi_devices_button.set_sensitive (false);
1027 midi_devices_button.set_sensitive (true);
1030 if (!ignore_changes) {
1036 EngineControl::parameter_changed ()
1038 if (!ignore_changes) {
1043 EngineControl::State*
1044 EngineControl::get_matching_state (
1045 const string& backend,
1046 const string& driver,
1047 const string& device)
1049 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1050 if ((*i).backend == backend &&
1051 (*i).driver == driver &&
1052 (*i).device == device) {
1059 EngineControl::State*
1060 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1062 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1065 return get_matching_state (backend_combo.get_active_text(),
1066 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1067 device_combo.get_active_text());
1071 return get_matching_state (backend_combo.get_active_text(),
1073 device_combo.get_active_text());
1076 EngineControl::State*
1077 EngineControl::save_state ()
1079 if (!_have_control) {
1082 State* state = new State;
1083 store_state (*state);
1085 for (StateList::iterator i = states.begin(); i != states.end();) {
1086 if ((*i).backend == state->backend &&
1087 (*i).driver == state->driver &&
1088 (*i).device == state->device) {
1089 i = states.erase(i);
1095 states.push_back (*state);
1101 EngineControl::store_state (State& state)
1103 state.backend = get_backend ();
1104 state.driver = get_driver ();
1105 state.device = get_device_name ();
1106 state.sample_rate = get_rate ();
1107 state.buffer_size = get_buffer_size ();
1108 state.input_latency = get_input_latency ();
1109 state.output_latency = get_output_latency ();
1110 state.input_channels = get_input_channels ();
1111 state.output_channels = get_output_channels ();
1112 state.midi_option = get_midi_option ();
1113 state.midi_devices = _midi_devices;
1117 EngineControl::maybe_display_saved_state ()
1119 if (!_have_control) {
1123 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1126 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1128 if (!_desired_sample_rate) {
1129 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1131 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1132 /* call this explicitly because we're ignoring changes to
1133 the controls at this point.
1135 show_buffer_duration ();
1136 input_latency.set_value (state->input_latency);
1137 output_latency.set_value (state->output_latency);
1139 if (!state->midi_option.empty()) {
1140 midi_option_combo.set_active_text (state->midi_option);
1141 _midi_devices = state->midi_devices;
1147 EngineControl::get_state ()
1149 XMLNode* root = new XMLNode ("AudioMIDISetup");
1152 if (!states.empty()) {
1153 XMLNode* state_nodes = new XMLNode ("EngineStates");
1155 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1157 XMLNode* node = new XMLNode ("State");
1159 node->add_property ("backend", (*i).backend);
1160 node->add_property ("driver", (*i).driver);
1161 node->add_property ("device", (*i).device);
1162 node->add_property ("sample-rate", (*i).sample_rate);
1163 node->add_property ("buffer-size", (*i).buffer_size);
1164 node->add_property ("input-latency", (*i).input_latency);
1165 node->add_property ("output-latency", (*i).output_latency);
1166 node->add_property ("input-channels", (*i).input_channels);
1167 node->add_property ("output-channels", (*i).output_channels);
1168 node->add_property ("active", (*i).active ? "yes" : "no");
1169 node->add_property ("midi-option", (*i).midi_option);
1171 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1172 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i).midi_devices.begin(); p != (*i).midi_devices.end(); ++p) {
1173 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1174 midi_device_stuff->add_property (X_("name"), (*p)->name);
1175 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1176 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1177 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1178 midi_devices->add_child_nocopy (*midi_device_stuff);
1180 node->add_child_nocopy (*midi_devices);
1182 state_nodes->add_child_nocopy (*node);
1185 root->add_child_nocopy (*state_nodes);
1192 EngineControl::set_state (const XMLNode& root)
1194 XMLNodeList clist, cclist;
1195 XMLNodeConstIterator citer, cciter;
1197 XMLNode* grandchild;
1198 XMLProperty* prop = NULL;
1200 if (root.name() != "AudioMIDISetup") {
1204 clist = root.children();
1208 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1212 if (child->name() != "EngineStates") {
1216 cclist = child->children();
1218 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1221 grandchild = *cciter;
1223 if (grandchild->name() != "State") {
1227 if ((prop = grandchild->property ("backend")) == 0) {
1230 state.backend = prop->value ();
1232 if ((prop = grandchild->property ("driver")) == 0) {
1235 state.driver = prop->value ();
1237 if ((prop = grandchild->property ("device")) == 0) {
1240 state.device = prop->value ();
1242 if ((prop = grandchild->property ("sample-rate")) == 0) {
1245 state.sample_rate = atof (prop->value ());
1247 if ((prop = grandchild->property ("buffer-size")) == 0) {
1250 state.buffer_size = atoi (prop->value ());
1252 if ((prop = grandchild->property ("input-latency")) == 0) {
1255 state.input_latency = atoi (prop->value ());
1257 if ((prop = grandchild->property ("output-latency")) == 0) {
1260 state.output_latency = atoi (prop->value ());
1262 if ((prop = grandchild->property ("input-channels")) == 0) {
1265 state.input_channels = atoi (prop->value ());
1267 if ((prop = grandchild->property ("output-channels")) == 0) {
1270 state.output_channels = atoi (prop->value ());
1272 if ((prop = grandchild->property ("active")) == 0) {
1275 state.active = string_is_affirmative (prop->value ());
1277 if ((prop = grandchild->property ("midi-option")) == 0) {
1280 state.midi_option = prop->value ();
1282 state.midi_devices.clear();
1284 if ((midinode = find_named_node (*grandchild, "MIDIDevices")) != 0) {
1285 const XMLNodeList mnc = midinode->children();
1286 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1287 if ((*n)->property (X_("name")) == 0
1288 || (*n)->property (X_("enabled")) == 0
1289 || (*n)->property (X_("input-latency")) == 0
1290 || (*n)->property (X_("output-latency")) == 0
1295 MidiDeviceSettings ptr (new MidiDeviceSetting(
1296 (*n)->property (X_("name"))->value (),
1297 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1298 atoi ((*n)->property (X_("input-latency"))->value ()),
1299 atoi ((*n)->property (X_("output-latency"))->value ())
1301 state.midi_devices.push_back (ptr);
1306 /* remove accumulated duplicates (due to bug in ealier version)
1307 * this can be removed again before release
1309 for (StateList::iterator i = states.begin(); i != states.end();) {
1310 if ((*i).backend == state.backend &&
1311 (*i).driver == state.driver &&
1312 (*i).device == state.device) {
1313 i = states.erase(i);
1320 states.push_back (state);
1324 /* now see if there was an active state and switch the setup to it */
1326 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1330 backend_combo.set_active_text ((*i).backend);
1331 driver_combo.set_active_text ((*i).driver);
1332 device_combo.set_active_text ((*i).device);
1333 sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
1334 buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
1335 input_latency.set_value ((*i).input_latency);
1336 output_latency.set_value ((*i).output_latency);
1337 midi_option_combo.set_active_text ((*i).midi_option);
1345 EngineControl::push_state_to_backend (bool start)
1347 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1353 /* figure out what is going to change */
1355 bool restart_required = false;
1356 bool was_running = ARDOUR::AudioEngine::instance()->running();
1357 bool change_driver = false;
1358 bool change_device = false;
1359 bool change_rate = false;
1360 bool change_bufsize = false;
1361 bool change_latency = false;
1362 bool change_channels = false;
1363 bool change_midi = false;
1365 uint32_t ochan = get_output_channels ();
1366 uint32_t ichan = get_input_channels ();
1368 if (_have_control) {
1370 if (started_at_least_once) {
1372 /* we can control the backend */
1374 if (backend->requires_driver_selection()) {
1375 if (get_driver() != backend->driver_name()) {
1376 change_driver = true;
1380 if (get_device_name() != backend->device_name()) {
1381 change_device = true;
1384 if (get_rate() != backend->sample_rate()) {
1388 if (get_buffer_size() != backend->buffer_size()) {
1389 change_bufsize = true;
1392 if (get_midi_option() != backend->midi_option()) {
1396 /* zero-requested channels means "all available" */
1399 ichan = backend->input_channels();
1403 ochan = backend->output_channels();
1406 if (ichan != backend->input_channels()) {
1407 change_channels = true;
1410 if (ochan != backend->output_channels()) {
1411 change_channels = true;
1414 if (get_input_latency() != backend->systemic_input_latency() ||
1415 get_output_latency() != backend->systemic_output_latency()) {
1416 change_latency = true;
1419 /* backend never started, so we have to force a group
1422 change_device = true;
1423 if (backend->requires_driver_selection()) {
1424 change_driver = true;
1427 change_bufsize = true;
1428 change_channels = true;
1429 change_latency = true;
1435 /* we have no control over the backend, meaning that we can
1436 * only possibly change sample rate and buffer size.
1440 if (get_rate() != backend->sample_rate()) {
1441 change_bufsize = true;
1444 if (get_buffer_size() != backend->buffer_size()) {
1445 change_bufsize = true;
1449 if (!_have_control) {
1451 /* We do not have control over the backend, so the best we can
1452 * do is try to change the sample rate and/or bufsize and get
1456 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1460 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1465 backend->set_sample_rate (get_rate());
1468 if (change_bufsize) {
1469 backend->set_buffer_size (get_buffer_size());
1473 if (ARDOUR::AudioEngine::instance()->start ()) {
1474 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1484 /* determine if we need to stop the backend before changing parameters */
1486 if (change_driver || change_device || change_channels || change_latency ||
1487 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1489 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1490 restart_required = true;
1492 restart_required = false;
1497 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1498 /* no changes in any parameters that absolutely require a
1499 * restart, so check those that might be changeable without a
1503 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1504 /* can't do this while running ... */
1505 restart_required = true;
1508 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1509 /* can't do this while running ... */
1510 restart_required = true;
1516 if (restart_required) {
1517 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1524 if (change_driver && backend->set_driver (get_driver())) {
1525 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1528 if (change_device && backend->set_device_name (get_device_name())) {
1529 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1532 if (change_rate && backend->set_sample_rate (get_rate())) {
1533 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1536 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1537 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1541 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1542 if (backend->set_input_channels (get_input_channels())) {
1543 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1546 if (backend->set_output_channels (get_output_channels())) {
1547 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1551 if (change_latency) {
1552 if (backend->set_systemic_input_latency (get_input_latency())) {
1553 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1556 if (backend->set_systemic_output_latency (get_output_latency())) {
1557 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1563 backend->set_midi_option (get_midi_option());
1567 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1568 if (_measure_midi) {
1569 if (*p == _measure_midi) {
1570 backend->set_midi_device_enabled ((*p)->name, true);
1572 backend->set_midi_device_enabled ((*p)->name, false);
1576 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1577 if (backend->can_set_systemic_midi_latencies()) {
1578 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1579 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1584 if (start || (was_running && restart_required)) {
1585 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1596 EngineControl::post_push ()
1598 /* get a pointer to the current state object, creating one if
1602 if (_have_control) {
1603 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1606 state = save_state ();
1612 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1613 (*i).active = false;
1616 /* mark this one active (to be used next time the dialog is
1620 state->active = true;
1622 manage_control_app_sensitivity ();
1625 /* schedule a redisplay of MIDI ports */
1626 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1631 EngineControl::get_rate () const
1633 float r = atof (sample_rate_combo.get_active_text ());
1634 /* the string may have been translated with an abbreviation for
1635 * thousands, so use a crude heuristic to fix this.
1645 EngineControl::get_buffer_size () const
1647 string txt = buffer_size_combo.get_active_text ();
1650 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1658 EngineControl::get_midi_option () const
1660 return midi_option_combo.get_active_text();
1664 EngineControl::get_input_channels() const
1666 return (uint32_t) input_channels_adjustment.get_value();
1670 EngineControl::get_output_channels() const
1672 return (uint32_t) output_channels_adjustment.get_value();
1676 EngineControl::get_input_latency() const
1678 return (uint32_t) input_latency_adjustment.get_value();
1682 EngineControl::get_output_latency() const
1684 return (uint32_t) output_latency_adjustment.get_value();
1688 EngineControl::get_backend () const
1690 return backend_combo.get_active_text ();
1694 EngineControl::get_driver () const
1696 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1697 return driver_combo.get_active_text ();
1704 EngineControl::get_device_name () const
1706 return device_combo.get_active_text ();
1710 EngineControl::control_app_button_clicked ()
1712 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1718 backend->launch_control_app ();
1722 EngineControl::manage_control_app_sensitivity ()
1724 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1730 string appname = backend->control_app_name();
1732 if (appname.empty()) {
1733 control_app_button.set_sensitive (false);
1735 control_app_button.set_sensitive (true);
1740 EngineControl::set_desired_sample_rate (uint32_t sr)
1742 _desired_sample_rate = sr;
1747 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1749 if (page_num == 0) {
1750 cancel_button->set_sensitive (true);
1751 ok_button->set_sensitive (true);
1752 apply_button->set_sensitive (true);
1753 _measure_midi.reset();
1755 cancel_button->set_sensitive (false);
1756 ok_button->set_sensitive (false);
1757 apply_button->set_sensitive (false);
1760 if (page_num == midi_tab) {
1762 refresh_midi_display ();
1765 if (page_num == latency_tab) {
1768 if (ARDOUR::AudioEngine::instance()->running()) {
1769 // TODO - mark as 'stopped for latency
1770 ARDOUR_UI::instance()->disconnect_from_engine ();
1774 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1776 /* save any existing latency values */
1778 uint32_t il = (uint32_t) input_latency.get_value ();
1779 uint32_t ol = (uint32_t) input_latency.get_value ();
1781 /* reset to zero so that our new test instance
1782 will be clean of any existing latency measures.
1784 NB. this should really be done by the backend
1785 when stated for latency measurement.
1788 input_latency.set_value (0);
1789 output_latency.set_value (0);
1791 push_state_to_backend (false);
1795 input_latency.set_value (il);
1796 output_latency.set_value (ol);
1799 // This should be done in push_state_to_backend()
1800 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1801 disable_latency_tab ();
1804 enable_latency_tab ();
1808 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1813 /* latency measurement */
1816 EngineControl::check_audio_latency_measurement ()
1818 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1820 if (mtdm->resolve () < 0) {
1821 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1825 if (mtdm->err () > 0.3) {
1831 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1833 if (sample_rate == 0) {
1834 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1835 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1839 int frames_total = mtdm->del();
1840 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1842 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1843 _("Detected roundtrip latency: "),
1844 frames_total, frames_total * 1000.0f/sample_rate,
1845 _("Systemic latency: "),
1846 extra, extra * 1000.0f/sample_rate);
1850 if (mtdm->err () > 0.2) {
1852 strcat (buf, _("(signal detection error)"));
1858 strcat (buf, _("(inverted - bad wiring)"));
1863 end_latency_detection ();
1864 lm_use_button.set_sensitive (true);
1865 have_lm_results = true;
1868 lm_results.set_markup (string_compose (results_markup, buf));
1874 EngineControl::check_midi_latency_measurement ()
1876 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1878 if (!mididm->have_signal () || mididm->latency () == 0) {
1879 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1884 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1886 if (sample_rate == 0) {
1887 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1888 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1892 ARDOUR::framecnt_t frames_total = mididm->latency();
1893 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1894 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1895 _("Detected roundtrip latency: "),
1896 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1897 _("Systemic latency: "),
1898 extra, extra * 1000.0f / sample_rate);
1902 if (!mididm->ok ()) {
1904 strcat (buf, _("(averaging)"));
1908 if (mididm->deviation () > 50.0) {
1910 strcat (buf, _("(too large jitter)"));
1912 } else if (mididm->deviation () > 10.0) {
1914 strcat (buf, _("(large jitter)"));
1918 end_latency_detection ();
1919 lm_use_button.set_sensitive (true);
1920 have_lm_results = true;
1923 lm_results.set_markup (string_compose (results_markup, buf));
1929 EngineControl::start_latency_detection ()
1931 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1932 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1934 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1935 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1936 if (_measure_midi) {
1937 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1939 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1941 lm_measure_label.set_text (_("Cancel"));
1942 have_lm_results = false;
1943 lm_use_button.set_sensitive (false);
1944 lm_input_channel_combo.set_sensitive (false);
1945 lm_output_channel_combo.set_sensitive (false);
1949 lm_back_button_signal.disconnect();
1950 if (_measure_midi) {
1951 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1953 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1958 EngineControl::end_latency_detection ()
1960 latency_timeout.disconnect ();
1961 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1962 lm_measure_label.set_text (_("Measure"));
1963 if (!have_lm_results) {
1964 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1966 lm_use_button.set_sensitive (false);
1968 lm_input_channel_combo.set_sensitive (true);
1969 lm_output_channel_combo.set_sensitive (true);
1974 EngineControl::latency_button_clicked ()
1977 start_latency_detection ();
1979 end_latency_detection ();
1984 EngineControl::use_latency_button_clicked ()
1986 if (_measure_midi) {
1987 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1991 ARDOUR::framecnt_t frames_total = mididm->latency();
1992 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1993 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
1994 _measure_midi->input_latency = one_way;
1995 _measure_midi->output_latency = one_way;
1996 notebook.set_current_page (midi_tab);
1998 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2004 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2005 one_way = std::max (0., one_way);
2007 input_latency_adjustment.set_value (one_way);
2008 output_latency_adjustment.set_value (one_way);
2010 /* back to settings page */
2011 notebook.set_current_page (0);
2017 EngineControl::on_delete_event (GdkEventAny* ev)
2019 if (notebook.get_current_page() == 2) {
2020 /* currently on latency tab - be sure to clean up */
2021 end_latency_detection ();
2023 return ArdourDialog::on_delete_event (ev);
2027 EngineControl::engine_running ()
2029 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2032 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2033 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2035 buffer_size_combo.set_sensitive (true);
2036 sample_rate_combo.set_sensitive (true);
2038 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2040 started_at_least_once = true;
2044 EngineControl::engine_stopped ()
2046 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2049 buffer_size_combo.set_sensitive (false);
2050 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2052 sample_rate_combo.set_sensitive (true);
2053 buffer_size_combo.set_sensitive (true);
2057 EngineControl::connect_disconnect_click()
2059 if (ARDOUR::AudioEngine::instance()->running()) {
2060 ARDOUR_UI::instance()->disconnect_from_engine ();
2062 ARDOUR_UI::instance()->reconnect_to_engine ();
2067 EngineControl::calibrate_audio_latency ()
2069 _measure_midi.reset();
2070 notebook.set_current_page (latency_tab);
2074 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2077 notebook.set_current_page (latency_tab);
2081 EngineControl::configure_midi_devices ()
2083 notebook.set_current_page (midi_tab);