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 end_latency_detection ();
1810 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1815 /* latency measurement */
1818 EngineControl::check_audio_latency_measurement ()
1820 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1822 if (mtdm->resolve () < 0) {
1823 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1827 if (mtdm->err () > 0.3) {
1833 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1835 if (sample_rate == 0) {
1836 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1837 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1841 int frames_total = mtdm->del();
1842 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1844 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1845 _("Detected roundtrip latency: "),
1846 frames_total, frames_total * 1000.0f/sample_rate,
1847 _("Systemic latency: "),
1848 extra, extra * 1000.0f/sample_rate);
1852 if (mtdm->err () > 0.2) {
1854 strcat (buf, _("(signal detection error)"));
1860 strcat (buf, _("(inverted - bad wiring)"));
1865 end_latency_detection ();
1866 lm_use_button.set_sensitive (true);
1867 have_lm_results = true;
1870 lm_results.set_markup (string_compose (results_markup, buf));
1876 EngineControl::check_midi_latency_measurement ()
1878 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1880 if (!mididm->have_signal () || mididm->latency () == 0) {
1881 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1886 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1888 if (sample_rate == 0) {
1889 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1890 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1894 ARDOUR::framecnt_t frames_total = mididm->latency();
1895 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1896 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1897 _("Detected roundtrip latency: "),
1898 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1899 _("Systemic latency: "),
1900 extra, extra * 1000.0f / sample_rate);
1904 if (!mididm->ok ()) {
1906 strcat (buf, _("(averaging)"));
1910 if (mididm->deviation () > 50.0) {
1912 strcat (buf, _("(too large jitter)"));
1914 } else if (mididm->deviation () > 10.0) {
1916 strcat (buf, _("(large jitter)"));
1920 end_latency_detection ();
1921 lm_use_button.set_sensitive (true);
1922 have_lm_results = true;
1925 lm_results.set_markup (string_compose (results_markup, buf));
1931 EngineControl::start_latency_detection ()
1933 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1934 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1936 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1937 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1938 if (_measure_midi) {
1939 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1941 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1943 lm_measure_label.set_text (_("Cancel"));
1944 have_lm_results = false;
1945 lm_use_button.set_sensitive (false);
1946 lm_input_channel_combo.set_sensitive (false);
1947 lm_output_channel_combo.set_sensitive (false);
1951 lm_back_button_signal.disconnect();
1952 if (_measure_midi) {
1953 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1955 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1960 EngineControl::end_latency_detection ()
1962 latency_timeout.disconnect ();
1963 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1964 lm_measure_label.set_text (_("Measure"));
1965 if (!have_lm_results) {
1966 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1968 lm_use_button.set_sensitive (false);
1970 lm_input_channel_combo.set_sensitive (true);
1971 lm_output_channel_combo.set_sensitive (true);
1976 EngineControl::latency_button_clicked ()
1979 start_latency_detection ();
1981 end_latency_detection ();
1986 EngineControl::use_latency_button_clicked ()
1988 if (_measure_midi) {
1989 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1993 ARDOUR::framecnt_t frames_total = mididm->latency();
1994 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1995 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
1996 _measure_midi->input_latency = one_way;
1997 _measure_midi->output_latency = one_way;
1998 notebook.set_current_page (midi_tab);
2000 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2006 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2007 one_way = std::max (0., one_way);
2009 input_latency_adjustment.set_value (one_way);
2010 output_latency_adjustment.set_value (one_way);
2012 /* back to settings page */
2013 notebook.set_current_page (0);
2019 EngineControl::on_delete_event (GdkEventAny* ev)
2021 if (notebook.get_current_page() == 2) {
2022 /* currently on latency tab - be sure to clean up */
2023 end_latency_detection ();
2025 return ArdourDialog::on_delete_event (ev);
2029 EngineControl::engine_running ()
2031 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2034 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2035 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2037 buffer_size_combo.set_sensitive (true);
2038 sample_rate_combo.set_sensitive (true);
2040 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2042 started_at_least_once = true;
2046 EngineControl::engine_stopped ()
2048 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2051 buffer_size_combo.set_sensitive (false);
2052 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2054 sample_rate_combo.set_sensitive (true);
2055 buffer_size_combo.set_sensitive (true);
2059 EngineControl::connect_disconnect_click()
2061 if (ARDOUR::AudioEngine::instance()->running()) {
2062 ARDOUR_UI::instance()->disconnect_from_engine ();
2064 ARDOUR_UI::instance()->reconnect_to_engine ();
2069 EngineControl::calibrate_audio_latency ()
2071 _measure_midi.reset ();
2072 have_lm_results = false;
2073 lm_use_button.set_sensitive (false);
2074 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2075 notebook.set_current_page (latency_tab);
2079 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2082 have_lm_results = false;
2083 lm_use_button.set_sensitive (false);
2084 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2085 notebook.set_current_page (latency_tab);
2089 EngineControl::configure_midi_devices ()
2091 notebook.set_current_page (midi_tab);