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 device_combo.clear();
800 sample_rate_combo.set_sensitive (false);
801 buffer_size_combo.set_sensitive (false);
802 input_latency.set_sensitive (false);
803 output_latency.set_sensitive (false);
804 input_channels.set_sensitive (false);
805 output_channels.set_sensitive (false);
807 ok_button->set_sensitive (false);
808 apply_button->set_sensitive (false);
810 ok_button->set_sensitive (true);
811 apply_button->set_sensitive (true);
817 EngineControl::driver_changed ()
819 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
822 backend->set_driver (driver_combo.get_active_text());
825 if (!ignore_changes) {
826 maybe_display_saved_state ();
831 EngineControl::device_changed ()
834 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
836 string device_name = device_combo.get_active_text ();
840 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
842 /* don't allow programmatic change to combos to cause a
843 recursive call to this method.
853 sr = backend->available_sample_rates (device_name);
856 sr.push_back (8000.0f);
857 sr.push_back (16000.0f);
858 sr.push_back (32000.0f);
859 sr.push_back (44100.0f);
860 sr.push_back (48000.0f);
861 sr.push_back (88200.0f);
862 sr.push_back (96000.0f);
863 sr.push_back (192000.0f);
864 sr.push_back (384000.0f);
867 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
868 s.push_back (rate_as_string (*x));
869 if (*x == _desired_sample_rate) {
875 sample_rate_combo.set_sensitive (true);
876 set_popdown_strings (sample_rate_combo, s);
878 if (desired.empty()) {
879 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
881 sample_rate_combo.set_active_text (desired);
885 sample_rate_combo.set_sensitive (false);
893 bs = backend->available_buffer_sizes (device_name);
894 } else if (backend->can_change_buffer_size_when_running()) {
908 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
909 s.push_back (bufsize_as_string (*x));
913 buffer_size_combo.set_sensitive (true);
914 set_popdown_strings (buffer_size_combo, s);
916 buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
917 show_buffer_duration ();
919 buffer_size_combo.set_sensitive (false);
922 /* XXX theoretically need to set min + max channel counts here
925 manage_control_app_sensitivity ();
928 /* pick up any saved state for this device */
930 if (!ignore_changes) {
931 maybe_display_saved_state ();
936 EngineControl::bufsize_as_string (uint32_t sz)
938 /* Translators: "samples" is always plural here, so no
939 need for plural+singular forms.
942 snprintf (buf, sizeof (buf), _("%u samples"), sz);
947 EngineControl::sample_rate_changed ()
949 /* reset the strings for buffer size to show the correct msec value
950 (reflecting the new sample rate).
953 show_buffer_duration ();
954 if (!ignore_changes) {
961 EngineControl::buffer_size_changed ()
963 show_buffer_duration ();
964 if (!ignore_changes) {
970 EngineControl::show_buffer_duration ()
973 /* buffer sizes - convert from just samples to samples + msecs for
974 * the displayed string
977 string bs_text = buffer_size_combo.get_active_text ();
978 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
979 uint32_t rate = get_rate();
981 /* Translators: "msecs" is ALWAYS plural here, so we do not
982 need singular form as well.
984 /* Developers: note the hard-coding of a double buffered model
985 in the (2 * samples) computation of latency. we always start
986 the audiobackend in this configuration.
989 snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
990 buffer_size_duration_label.set_text (buf);
994 EngineControl::midi_option_changed ()
996 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
999 backend->set_midi_option (get_midi_option());
1001 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1003 //_midi_devices.clear(); // TODO merge with state-saved settings..
1004 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1005 std::vector<MidiDeviceSettings> new_devices;
1007 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1008 MidiDeviceSettings mds = find_midi_device (i->name);
1009 if (i->available && !mds) {
1010 uint32_t input_latency = 0;
1011 uint32_t output_latency = 0;
1012 if (_can_set_midi_latencies) {
1013 input_latency = backend->systemic_midi_input_latency (i->name);
1014 output_latency = backend->systemic_midi_output_latency (i->name);
1016 bool enabled = backend->midi_device_enabled (i->name);
1017 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1018 new_devices.push_back (ptr);
1019 } else if (i->available) {
1020 new_devices.push_back (mds);
1023 _midi_devices = new_devices;
1025 if (_midi_devices.empty()) {
1026 midi_devices_button.set_sensitive (false);
1028 midi_devices_button.set_sensitive (true);
1031 if (!ignore_changes) {
1037 EngineControl::parameter_changed ()
1039 if (!ignore_changes) {
1044 EngineControl::State
1045 EngineControl::get_matching_state (
1046 const string& backend,
1047 const string& driver,
1048 const string& device)
1050 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1051 if ((*i)->backend == backend &&
1052 (*i)->driver == driver &&
1053 (*i)->device == device) {
1060 EngineControl::State
1061 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1063 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1066 return get_matching_state (backend_combo.get_active_text(),
1067 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1068 device_combo.get_active_text());
1072 return get_matching_state (backend_combo.get_active_text(),
1074 device_combo.get_active_text());
1077 EngineControl::State
1078 EngineControl::save_state ()
1080 if (!_have_control) {
1083 State state (new StateStruct);
1084 store_state (state);
1086 for (StateList::iterator i = states.begin(); i != states.end();) {
1087 if ((*i)->backend == state->backend &&
1088 (*i)->driver == state->driver &&
1089 (*i)->device == state->device) {
1090 i = states.erase(i);
1096 states.push_back (state);
1102 EngineControl::store_state (State state)
1104 state->backend = get_backend ();
1105 state->driver = get_driver ();
1106 state->device = get_device_name ();
1107 state->sample_rate = get_rate ();
1108 state->buffer_size = get_buffer_size ();
1109 state->input_latency = get_input_latency ();
1110 state->output_latency = get_output_latency ();
1111 state->input_channels = get_input_channels ();
1112 state->output_channels = get_output_channels ();
1113 state->midi_option = get_midi_option ();
1114 state->midi_devices = _midi_devices;
1118 EngineControl::maybe_display_saved_state ()
1120 if (!_have_control) {
1124 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1127 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1129 if (!_desired_sample_rate) {
1130 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1132 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1133 /* call this explicitly because we're ignoring changes to
1134 the controls at this point.
1136 show_buffer_duration ();
1137 input_latency.set_value (state->input_latency);
1138 output_latency.set_value (state->output_latency);
1140 if (!state->midi_option.empty()) {
1141 midi_option_combo.set_active_text (state->midi_option);
1142 _midi_devices = state->midi_devices;
1148 EngineControl::get_state ()
1150 XMLNode* root = new XMLNode ("AudioMIDISetup");
1153 if (!states.empty()) {
1154 XMLNode* state_nodes = new XMLNode ("EngineStates");
1156 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1158 XMLNode* node = new XMLNode ("State");
1160 node->add_property ("backend", (*i)->backend);
1161 node->add_property ("driver", (*i)->driver);
1162 node->add_property ("device", (*i)->device);
1163 node->add_property ("sample-rate", (*i)->sample_rate);
1164 node->add_property ("buffer-size", (*i)->buffer_size);
1165 node->add_property ("input-latency", (*i)->input_latency);
1166 node->add_property ("output-latency", (*i)->output_latency);
1167 node->add_property ("input-channels", (*i)->input_channels);
1168 node->add_property ("output-channels", (*i)->output_channels);
1169 node->add_property ("active", (*i)->active ? "yes" : "no");
1170 node->add_property ("midi-option", (*i)->midi_option);
1172 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1173 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1174 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1175 midi_device_stuff->add_property (X_("name"), (*p)->name);
1176 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1177 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1178 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1179 midi_devices->add_child_nocopy (*midi_device_stuff);
1181 node->add_child_nocopy (*midi_devices);
1183 state_nodes->add_child_nocopy (*node);
1186 root->add_child_nocopy (*state_nodes);
1193 EngineControl::set_state (const XMLNode& root)
1195 XMLNodeList clist, cclist;
1196 XMLNodeConstIterator citer, cciter;
1198 XMLNode* grandchild;
1199 XMLProperty* prop = NULL;
1201 if (root.name() != "AudioMIDISetup") {
1205 clist = root.children();
1209 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1213 if (child->name() != "EngineStates") {
1217 cclist = child->children();
1219 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1220 State state (new StateStruct);
1222 grandchild = *cciter;
1224 if (grandchild->name() != "State") {
1228 if ((prop = grandchild->property ("backend")) == 0) {
1231 state->backend = prop->value ();
1233 if ((prop = grandchild->property ("driver")) == 0) {
1236 state->driver = prop->value ();
1238 if ((prop = grandchild->property ("device")) == 0) {
1241 state->device = prop->value ();
1243 if ((prop = grandchild->property ("sample-rate")) == 0) {
1246 state->sample_rate = atof (prop->value ());
1248 if ((prop = grandchild->property ("buffer-size")) == 0) {
1251 state->buffer_size = atoi (prop->value ());
1253 if ((prop = grandchild->property ("input-latency")) == 0) {
1256 state->input_latency = atoi (prop->value ());
1258 if ((prop = grandchild->property ("output-latency")) == 0) {
1261 state->output_latency = atoi (prop->value ());
1263 if ((prop = grandchild->property ("input-channels")) == 0) {
1266 state->input_channels = atoi (prop->value ());
1268 if ((prop = grandchild->property ("output-channels")) == 0) {
1271 state->output_channels = atoi (prop->value ());
1273 if ((prop = grandchild->property ("active")) == 0) {
1276 state->active = string_is_affirmative (prop->value ());
1278 if ((prop = grandchild->property ("midi-option")) == 0) {
1281 state->midi_option = prop->value ();
1283 state->midi_devices.clear();
1285 if ((midinode = find_named_node (*grandchild, "MIDIDevices")) != 0) {
1286 const XMLNodeList mnc = midinode->children();
1287 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1288 if ((*n)->property (X_("name")) == 0
1289 || (*n)->property (X_("enabled")) == 0
1290 || (*n)->property (X_("input-latency")) == 0
1291 || (*n)->property (X_("output-latency")) == 0
1296 MidiDeviceSettings ptr (new MidiDeviceSetting(
1297 (*n)->property (X_("name"))->value (),
1298 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1299 atoi ((*n)->property (X_("input-latency"))->value ()),
1300 atoi ((*n)->property (X_("output-latency"))->value ())
1302 state->midi_devices.push_back (ptr);
1307 /* remove accumulated duplicates (due to bug in ealier version)
1308 * this can be removed again before release
1310 for (StateList::iterator i = states.begin(); i != states.end();) {
1311 if ((*i)->backend == state->backend &&
1312 (*i)->driver == state->driver &&
1313 (*i)->device == state->device) {
1314 i = states.erase(i);
1321 states.push_back (state);
1325 /* now see if there was an active state and switch the setup to it */
1327 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1331 backend_combo.set_active_text ((*i)->backend);
1332 driver_combo.set_active_text ((*i)->driver);
1333 device_combo.set_active_text ((*i)->device);
1334 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1335 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1336 input_latency.set_value ((*i)->input_latency);
1337 output_latency.set_value ((*i)->output_latency);
1338 midi_option_combo.set_active_text ((*i)->midi_option);
1346 EngineControl::push_state_to_backend (bool start)
1348 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1354 /* figure out what is going to change */
1356 bool restart_required = false;
1357 bool was_running = ARDOUR::AudioEngine::instance()->running();
1358 bool change_driver = false;
1359 bool change_device = false;
1360 bool change_rate = false;
1361 bool change_bufsize = false;
1362 bool change_latency = false;
1363 bool change_channels = false;
1364 bool change_midi = false;
1366 uint32_t ochan = get_output_channels ();
1367 uint32_t ichan = get_input_channels ();
1369 if (_have_control) {
1371 if (started_at_least_once) {
1373 /* we can control the backend */
1375 if (backend->requires_driver_selection()) {
1376 if (get_driver() != backend->driver_name()) {
1377 change_driver = true;
1381 if (get_device_name() != backend->device_name()) {
1382 change_device = true;
1385 if (get_rate() != backend->sample_rate()) {
1389 if (get_buffer_size() != backend->buffer_size()) {
1390 change_bufsize = true;
1393 if (get_midi_option() != backend->midi_option()) {
1397 /* zero-requested channels means "all available" */
1400 ichan = backend->input_channels();
1404 ochan = backend->output_channels();
1407 if (ichan != backend->input_channels()) {
1408 change_channels = true;
1411 if (ochan != backend->output_channels()) {
1412 change_channels = true;
1415 if (get_input_latency() != backend->systemic_input_latency() ||
1416 get_output_latency() != backend->systemic_output_latency()) {
1417 change_latency = true;
1420 /* backend never started, so we have to force a group
1423 change_device = true;
1424 if (backend->requires_driver_selection()) {
1425 change_driver = true;
1428 change_bufsize = true;
1429 change_channels = true;
1430 change_latency = true;
1436 /* we have no control over the backend, meaning that we can
1437 * only possibly change sample rate and buffer size.
1441 if (get_rate() != backend->sample_rate()) {
1442 change_bufsize = true;
1445 if (get_buffer_size() != backend->buffer_size()) {
1446 change_bufsize = true;
1450 if (!_have_control) {
1452 /* We do not have control over the backend, so the best we can
1453 * do is try to change the sample rate and/or bufsize and get
1457 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1461 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1466 backend->set_sample_rate (get_rate());
1469 if (change_bufsize) {
1470 backend->set_buffer_size (get_buffer_size());
1474 if (ARDOUR::AudioEngine::instance()->start ()) {
1475 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1485 /* determine if we need to stop the backend before changing parameters */
1487 if (change_driver || change_device || change_channels || change_latency ||
1488 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1490 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1491 restart_required = true;
1493 restart_required = false;
1498 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1499 /* no changes in any parameters that absolutely require a
1500 * restart, so check those that might be changeable without a
1504 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1505 /* can't do this while running ... */
1506 restart_required = true;
1509 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1510 /* can't do this while running ... */
1511 restart_required = true;
1517 if (restart_required) {
1518 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1525 if (change_driver && backend->set_driver (get_driver())) {
1526 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1529 if (change_device && backend->set_device_name (get_device_name())) {
1530 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1533 if (change_rate && backend->set_sample_rate (get_rate())) {
1534 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1537 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1538 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1542 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1543 if (backend->set_input_channels (get_input_channels())) {
1544 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1547 if (backend->set_output_channels (get_output_channels())) {
1548 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1552 if (change_latency) {
1553 if (backend->set_systemic_input_latency (get_input_latency())) {
1554 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1557 if (backend->set_systemic_output_latency (get_output_latency())) {
1558 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1564 backend->set_midi_option (get_midi_option());
1568 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1569 if (_measure_midi) {
1570 if (*p == _measure_midi) {
1571 backend->set_midi_device_enabled ((*p)->name, true);
1573 backend->set_midi_device_enabled ((*p)->name, false);
1577 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1578 if (backend->can_set_systemic_midi_latencies()) {
1579 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1580 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1585 if (start || (was_running && restart_required)) {
1586 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1597 EngineControl::post_push ()
1599 /* get a pointer to the current state object, creating one if
1603 if (_have_control) {
1604 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1607 state = save_state ();
1613 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1614 (*i)->active = false;
1617 /* mark this one active (to be used next time the dialog is
1621 state->active = true;
1623 manage_control_app_sensitivity ();
1626 /* schedule a redisplay of MIDI ports */
1627 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1632 EngineControl::get_rate () const
1634 float r = atof (sample_rate_combo.get_active_text ());
1635 /* the string may have been translated with an abbreviation for
1636 * thousands, so use a crude heuristic to fix this.
1646 EngineControl::get_buffer_size () const
1648 string txt = buffer_size_combo.get_active_text ();
1651 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1659 EngineControl::get_midi_option () const
1661 return midi_option_combo.get_active_text();
1665 EngineControl::get_input_channels() const
1667 return (uint32_t) input_channels_adjustment.get_value();
1671 EngineControl::get_output_channels() const
1673 return (uint32_t) output_channels_adjustment.get_value();
1677 EngineControl::get_input_latency() const
1679 return (uint32_t) input_latency_adjustment.get_value();
1683 EngineControl::get_output_latency() const
1685 return (uint32_t) output_latency_adjustment.get_value();
1689 EngineControl::get_backend () const
1691 return backend_combo.get_active_text ();
1695 EngineControl::get_driver () const
1697 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1698 return driver_combo.get_active_text ();
1705 EngineControl::get_device_name () const
1707 return device_combo.get_active_text ();
1711 EngineControl::control_app_button_clicked ()
1713 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1719 backend->launch_control_app ();
1723 EngineControl::manage_control_app_sensitivity ()
1725 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1731 string appname = backend->control_app_name();
1733 if (appname.empty()) {
1734 control_app_button.set_sensitive (false);
1736 control_app_button.set_sensitive (true);
1741 EngineControl::set_desired_sample_rate (uint32_t sr)
1743 _desired_sample_rate = sr;
1748 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1750 if (page_num == 0) {
1751 cancel_button->set_sensitive (true);
1752 ok_button->set_sensitive (true);
1753 apply_button->set_sensitive (true);
1754 _measure_midi.reset();
1756 cancel_button->set_sensitive (false);
1757 ok_button->set_sensitive (false);
1758 apply_button->set_sensitive (false);
1761 if (page_num == midi_tab) {
1763 refresh_midi_display ();
1766 if (page_num == latency_tab) {
1769 if (ARDOUR::AudioEngine::instance()->running()) {
1770 // TODO - mark as 'stopped for latency
1771 ARDOUR_UI::instance()->disconnect_from_engine ();
1775 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1777 /* save any existing latency values */
1779 uint32_t il = (uint32_t) input_latency.get_value ();
1780 uint32_t ol = (uint32_t) input_latency.get_value ();
1782 /* reset to zero so that our new test instance
1783 will be clean of any existing latency measures.
1785 NB. this should really be done by the backend
1786 when stated for latency measurement.
1789 input_latency.set_value (0);
1790 output_latency.set_value (0);
1792 push_state_to_backend (false);
1796 input_latency.set_value (il);
1797 output_latency.set_value (ol);
1800 // This should be done in push_state_to_backend()
1801 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1802 disable_latency_tab ();
1805 enable_latency_tab ();
1809 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1814 /* latency measurement */
1817 EngineControl::check_audio_latency_measurement ()
1819 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1821 if (mtdm->resolve () < 0) {
1822 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1826 if (mtdm->err () > 0.3) {
1832 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1834 if (sample_rate == 0) {
1835 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1836 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1840 int frames_total = mtdm->del();
1841 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1843 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1844 _("Detected roundtrip latency: "),
1845 frames_total, frames_total * 1000.0f/sample_rate,
1846 _("Systemic latency: "),
1847 extra, extra * 1000.0f/sample_rate);
1851 if (mtdm->err () > 0.2) {
1853 strcat (buf, _("(signal detection error)"));
1859 strcat (buf, _("(inverted - bad wiring)"));
1864 end_latency_detection ();
1865 lm_use_button.set_sensitive (true);
1866 have_lm_results = true;
1869 lm_results.set_markup (string_compose (results_markup, buf));
1875 EngineControl::check_midi_latency_measurement ()
1877 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1879 if (!mididm->have_signal () || mididm->latency () == 0) {
1880 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1885 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1887 if (sample_rate == 0) {
1888 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1889 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1893 ARDOUR::framecnt_t frames_total = mididm->latency();
1894 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1895 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1896 _("Detected roundtrip latency: "),
1897 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1898 _("Systemic latency: "),
1899 extra, extra * 1000.0f / sample_rate);
1903 if (!mididm->ok ()) {
1905 strcat (buf, _("(averaging)"));
1909 if (mididm->deviation () > 50.0) {
1911 strcat (buf, _("(too large jitter)"));
1913 } else if (mididm->deviation () > 10.0) {
1915 strcat (buf, _("(large jitter)"));
1919 end_latency_detection ();
1920 lm_use_button.set_sensitive (true);
1921 have_lm_results = true;
1924 lm_results.set_markup (string_compose (results_markup, buf));
1930 EngineControl::start_latency_detection ()
1932 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1933 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1935 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1936 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1937 if (_measure_midi) {
1938 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1940 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1942 lm_measure_label.set_text (_("Cancel"));
1943 have_lm_results = false;
1944 lm_use_button.set_sensitive (false);
1945 lm_input_channel_combo.set_sensitive (false);
1946 lm_output_channel_combo.set_sensitive (false);
1950 lm_back_button_signal.disconnect();
1951 if (_measure_midi) {
1952 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1954 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1959 EngineControl::end_latency_detection ()
1961 latency_timeout.disconnect ();
1962 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1963 lm_measure_label.set_text (_("Measure"));
1964 if (!have_lm_results) {
1965 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1967 lm_use_button.set_sensitive (false);
1969 lm_input_channel_combo.set_sensitive (true);
1970 lm_output_channel_combo.set_sensitive (true);
1975 EngineControl::latency_button_clicked ()
1978 start_latency_detection ();
1980 end_latency_detection ();
1985 EngineControl::use_latency_button_clicked ()
1987 if (_measure_midi) {
1988 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1992 ARDOUR::framecnt_t frames_total = mididm->latency();
1993 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1994 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
1995 _measure_midi->input_latency = one_way;
1996 _measure_midi->output_latency = one_way;
1997 notebook.set_current_page (midi_tab);
1999 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2005 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2006 one_way = std::max (0., one_way);
2008 input_latency_adjustment.set_value (one_way);
2009 output_latency_adjustment.set_value (one_way);
2011 /* back to settings page */
2012 notebook.set_current_page (0);
2018 EngineControl::on_delete_event (GdkEventAny* ev)
2020 if (notebook.get_current_page() == 2) {
2021 /* currently on latency tab - be sure to clean up */
2022 end_latency_detection ();
2024 return ArdourDialog::on_delete_event (ev);
2028 EngineControl::engine_running ()
2030 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2033 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2034 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2036 buffer_size_combo.set_sensitive (true);
2037 sample_rate_combo.set_sensitive (true);
2039 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2041 started_at_least_once = true;
2045 EngineControl::engine_stopped ()
2047 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2050 buffer_size_combo.set_sensitive (false);
2051 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2053 sample_rate_combo.set_sensitive (true);
2054 buffer_size_combo.set_sensitive (true);
2058 EngineControl::connect_disconnect_click()
2060 if (ARDOUR::AudioEngine::instance()->running()) {
2061 ARDOUR_UI::instance()->disconnect_from_engine ();
2063 ARDOUR_UI::instance()->reconnect_to_engine ();
2068 EngineControl::calibrate_audio_latency ()
2070 _measure_midi.reset();
2071 notebook.set_current_page (latency_tab);
2075 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2078 notebook.set_current_page (latency_tab);
2082 EngineControl::configure_midi_devices ()
2084 notebook.set_current_page (midi_tab);