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;
61 using namespace ARDOUR_UI_UTILS;
63 static const unsigned int midi_tab = 2;
64 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
66 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
68 EngineControl::EngineControl ()
69 : ArdourDialog (_("Audio/MIDI Setup"))
71 , input_latency_adjustment (0, 0, 99999, 1)
72 , input_latency (input_latency_adjustment)
73 , output_latency_adjustment (0, 0, 99999, 1)
74 , output_latency (output_latency_adjustment)
75 , input_channels_adjustment (0, 0, 256, 1)
76 , input_channels (input_channels_adjustment)
77 , output_channels_adjustment (0, 0, 256, 1)
78 , output_channels (output_channels_adjustment)
79 , ports_adjustment (128, 8, 1024, 1, 16)
80 , ports_spinner (ports_adjustment)
81 , control_app_button (_("Device Control Panel"))
82 , midi_devices_button (_("Midi Device Setup"))
83 , lm_measure_label (_("Measure"))
84 , lm_use_button (_("Use results"))
85 , lm_back_button (_("Back to settings ... (ignore results)"))
86 , lm_button_audio (_("Calibrate Audio"))
88 , have_lm_results (false)
90 , midi_back_button (_("Back to settings"))
92 , _desired_sample_rate (0)
93 , started_at_least_once (false)
95 using namespace Notebook_Helpers;
96 vector<string> strings;
98 AttachOptions xopt = AttachOptions (FILL|EXPAND);
101 set_name (X_("AudioMIDISetup"));
103 /* the backend combo is the one thing that is ALWAYS visible */
105 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
107 if (backends.empty()) {
108 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));
110 throw failed_constructor ();
113 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
114 strings.push_back ((*b)->name);
117 set_popdown_strings (backend_combo, strings);
118 backend_combo.set_active_text (strings.front());
119 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
121 /* setup basic packing characteristics for the table used on the main
122 * tab of the notebook
125 basic_packer.set_spacings (6);
126 basic_packer.set_border_width (12);
127 basic_packer.set_homogeneous (false);
131 basic_hbox.pack_start (basic_packer, false, false);
133 /* latency measurement tab */
135 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
138 lm_table.set_row_spacings (12);
139 lm_table.set_col_spacings (6);
140 lm_table.set_homogeneous (false);
142 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
145 lm_preamble.set_width_chars (60);
146 lm_preamble.set_line_wrap (true);
147 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
149 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
152 Gtk::Label* preamble;
153 preamble = manage (new Label);
154 preamble->set_width_chars (60);
155 preamble->set_line_wrap (true);
156 preamble->set_markup (_("Select two channels below and connect them using a cable."));
158 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
161 label = manage (new Label (_("Output channel")));
162 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
164 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
165 misc_align->add (lm_output_channel_combo);
166 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
169 label = manage (new Label (_("Input channel")));
170 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
172 misc_align = manage (new Alignment (0.0, 0.5));
173 misc_align->add (lm_input_channel_combo);
174 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
177 xopt = AttachOptions(0);
179 lm_measure_label.set_padding (10, 10);
180 lm_measure_button.add (lm_measure_label);
181 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
182 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
183 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
185 lm_use_button.set_sensitive (false);
187 /* Increase the default spacing around the labels of these three
193 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
194 l->set_padding (10, 10);
197 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
198 l->set_padding (10, 10);
201 preamble = manage (new Label);
202 preamble->set_width_chars (60);
203 preamble->set_line_wrap (true);
204 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
205 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
208 preamble = manage (new Label);
209 preamble->set_width_chars (60);
210 preamble->set_line_wrap (true);
211 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
212 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
214 ++row; // skip a row in the table
215 ++row; // skip a row in the table
217 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219 ++row; // skip a row in the table
220 ++row; // skip a row in the table
222 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
228 lm_vbox.set_border_width (12);
229 lm_vbox.pack_start (lm_table, false, false);
231 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
235 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
236 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
237 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
238 notebook.set_border_width (12);
240 notebook.set_show_tabs (false);
241 notebook.show_all ();
243 notebook.set_name ("SettingsNotebook");
245 /* packup the notebook */
247 get_vbox()->set_border_width (12);
248 get_vbox()->pack_start (notebook);
250 /* need a special function to print "all available channels" when the
251 * channel counts hit zero.
254 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
255 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
257 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
258 midi_devices_button.set_sensitive (false);
259 midi_devices_button.set_name ("generic button");
260 midi_devices_button.set_can_focus(true);
262 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
263 manage_control_app_sensitivity ();
265 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
266 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
267 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
269 /* Pick up any existing audio setup configuration, if appropriate */
271 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
273 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
274 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
275 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
279 set_state (*audio_setup);
282 /* ignore: don't save state */
283 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
287 /* Connect to signals */
289 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
290 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
291 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
292 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
293 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
295 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
296 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
297 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
298 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
300 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
304 EngineControl::on_show ()
306 ArdourDialog::on_show ();
307 ok_button->grab_focus();
311 EngineControl::on_response (int response_id)
313 ArdourDialog::on_response (response_id);
315 switch (response_id) {
317 push_state_to_backend (true);
320 push_state_to_backend (true);
323 case RESPONSE_DELETE_EVENT:
326 ev.type = GDK_BUTTON_PRESS;
328 on_delete_event ((GdkEventAny*) &ev);
337 EngineControl::build_notebook ()
340 AttachOptions xopt = AttachOptions (FILL|EXPAND);
342 /* clear the table */
344 Gtkmm2ext::container_clear (basic_vbox);
345 Gtkmm2ext::container_clear (basic_packer);
347 if (control_app_button.get_parent()) {
348 control_app_button.get_parent()->remove (control_app_button);
351 label = manage (left_aligned_label (_("Audio System:")));
352 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
353 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
355 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
356 lm_button_audio.set_name ("generic button");
357 lm_button_audio.set_can_focus(true);
360 build_full_control_notebook ();
362 build_no_control_notebook ();
365 basic_vbox.pack_start (basic_hbox, false, false);
368 Gtk::HBox* hpacker = manage (new HBox);
369 hpacker->set_border_width (12);
370 hpacker->pack_start (control_app_button, false, false);
372 control_app_button.show();
373 basic_vbox.pack_start (*hpacker);
377 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
378 basic_vbox.show_all ();
383 EngineControl::build_full_control_notebook ()
385 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
388 using namespace Notebook_Helpers;
390 vector<string> strings;
391 AttachOptions xopt = AttachOptions (FILL|EXPAND);
392 int row = 1; // row zero == backend combo
394 /* start packing it up */
396 if (backend->requires_driver_selection()) {
397 label = manage (left_aligned_label (_("Driver:")));
398 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
399 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
403 label = manage (left_aligned_label (_("Device:")));
404 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
405 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
408 label = manage (left_aligned_label (_("Sample rate:")));
409 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
410 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
414 label = manage (left_aligned_label (_("Buffer size:")));
415 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
416 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
417 buffer_size_duration_label.set_alignment (0.0); /* left-align */
418 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
421 input_channels.set_name ("InputChannels");
422 input_channels.set_flags (Gtk::CAN_FOCUS);
423 input_channels.set_digits (0);
424 input_channels.set_wrap (false);
425 output_channels.set_editable (true);
427 label = manage (left_aligned_label (_("Input Channels:")));
428 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
429 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
432 output_channels.set_name ("OutputChannels");
433 output_channels.set_flags (Gtk::CAN_FOCUS);
434 output_channels.set_digits (0);
435 output_channels.set_wrap (false);
436 output_channels.set_editable (true);
438 label = manage (left_aligned_label (_("Output Channels:")));
439 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
440 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
443 input_latency.set_name ("InputLatency");
444 input_latency.set_flags (Gtk::CAN_FOCUS);
445 input_latency.set_digits (0);
446 input_latency.set_wrap (false);
447 input_latency.set_editable (true);
449 label = manage (left_aligned_label (_("Hardware input latency:")));
450 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
451 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
452 label = manage (left_aligned_label (_("samples")));
453 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
456 output_latency.set_name ("OutputLatency");
457 output_latency.set_flags (Gtk::CAN_FOCUS);
458 output_latency.set_digits (0);
459 output_latency.set_wrap (false);
460 output_latency.set_editable (true);
462 label = manage (left_aligned_label (_("Hardware output latency:")));
463 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
464 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
465 label = manage (left_aligned_label (_("samples")));
466 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
468 /* button spans 2 rows */
470 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
473 label = manage (left_aligned_label (_("MIDI System")));
474 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
475 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
476 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
481 EngineControl::build_no_control_notebook ()
483 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
486 using namespace Notebook_Helpers;
488 vector<string> strings;
489 AttachOptions xopt = AttachOptions (FILL|EXPAND);
490 int row = 1; // row zero == backend combo
491 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
493 label = manage (new Label);
494 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
495 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
498 if (backend->can_change_sample_rate_when_running()) {
499 label = manage (left_aligned_label (_("Sample rate:")));
500 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
501 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
505 if (backend->can_change_buffer_size_when_running()) {
506 label = manage (left_aligned_label (_("Buffer size:")));
507 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
508 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
509 buffer_size_duration_label.set_alignment (0.0); /* left-align */
510 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
514 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
516 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
520 EngineControl::~EngineControl ()
522 ignore_changes = true;
526 EngineControl::disable_latency_tab ()
528 vector<string> empty;
529 set_popdown_strings (lm_output_channel_combo, empty);
530 set_popdown_strings (lm_input_channel_combo, empty);
531 lm_measure_button.set_sensitive (false);
532 lm_use_button.set_sensitive (false);
536 EngineControl::enable_latency_tab ()
538 vector<string> outputs;
539 vector<string> inputs;
541 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
542 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
543 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
545 if (!ARDOUR::AudioEngine::instance()->running()) {
546 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
547 notebook.set_current_page (0);
551 else if (inputs.empty() || outputs.empty()) {
552 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
553 notebook.set_current_page (0);
558 lm_back_button_signal.disconnect();
560 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
563 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
567 set_popdown_strings (lm_output_channel_combo, outputs);
568 lm_output_channel_combo.set_active_text (outputs.front());
569 lm_output_channel_combo.set_sensitive (true);
571 set_popdown_strings (lm_input_channel_combo, inputs);
572 lm_input_channel_combo.set_active_text (inputs.front());
573 lm_input_channel_combo.set_sensitive (true);
575 lm_measure_button.set_sensitive (true);
579 EngineControl::setup_midi_tab_for_backend ()
581 string backend = backend_combo.get_active_text ();
583 Gtkmm2ext::container_clear (midi_vbox);
585 midi_vbox.set_border_width (12);
586 midi_device_table.set_border_width (12);
588 if (backend == "JACK") {
589 setup_midi_tab_for_jack ();
592 midi_vbox.pack_start (midi_device_table, true, true);
593 midi_vbox.pack_start (midi_back_button, false, false);
594 midi_vbox.show_all ();
598 EngineControl::setup_midi_tab_for_jack ()
603 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
605 device->input_latency = a->get_value();
607 device->output_latency = a->get_value();
612 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
613 b->set_active (!b->get_active());
614 device->enabled = b->get_active();
615 refresh_midi_display(device->name);
619 EngineControl::refresh_midi_display (std::string focus)
621 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
625 AttachOptions xopt = AttachOptions (FILL|EXPAND);
628 Gtkmm2ext::container_clear (midi_device_table);
630 midi_device_table.set_spacings (6);
632 l = manage (new Label);
633 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
634 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
635 l->set_alignment (0.5, 0.5);
639 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
640 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
641 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
642 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
644 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
645 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
646 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
647 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
650 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
655 bool enabled = (*p)->enabled;
657 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
658 m->set_name ("midi device");
659 m->set_can_focus (Gtk::CAN_FOCUS);
660 m->add_events (Gdk::BUTTON_RELEASE_MASK);
661 m->set_active (enabled);
662 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
663 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
664 if ((*p)->name == focus) {
668 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
669 s = manage (new Gtk::SpinButton (*a));
670 a->set_value ((*p)->input_latency);
671 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
672 s->set_sensitive (_can_set_midi_latencies && enabled);
673 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
675 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
676 s = manage (new Gtk::SpinButton (*a));
677 a->set_value ((*p)->output_latency);
678 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
679 s->set_sensitive (_can_set_midi_latencies && enabled);
680 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
682 b = manage (new Button (_("Calibrate")));
683 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
684 b->set_sensitive (_can_set_midi_latencies && enabled);
685 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
692 EngineControl::update_sensitivity ()
697 EngineControl::backend_changed ()
699 string backend_name = backend_combo.get_active_text();
700 boost::shared_ptr<ARDOUR::AudioBackend> backend;
702 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
703 /* eh? setting the backend failed... how ? */
707 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
710 setup_midi_tab_for_backend ();
711 _midi_devices.clear();
713 if (backend->requires_driver_selection()) {
714 vector<string> drivers = backend->enumerate_drivers();
715 driver_combo.set_sensitive (true);
717 if (!drivers.empty()) {
719 string current_driver;
720 current_driver = backend->driver_name ();
722 // driver might not have been set yet
723 if (current_driver == "") {
724 current_driver = driver_combo.get_active_text ();
725 if (current_driver == "")
726 // driver has never been set, make sure it's not blank
727 current_driver = drivers.front ();
730 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
731 set_popdown_strings (driver_combo, drivers);
732 driver_combo.set_active_text (current_driver);
739 driver_combo.set_sensitive (false);
740 /* this will change the device text which will cause a call to
741 * device changed which will set up parameters
746 vector<string> midi_options = backend->enumerate_midi_options();
748 if (midi_options.size() == 1) {
749 /* only contains the "none" option */
750 midi_option_combo.set_sensitive (false);
753 set_popdown_strings (midi_option_combo, midi_options);
754 midi_option_combo.set_active_text (midi_options.front());
755 midi_option_combo.set_sensitive (true);
757 midi_option_combo.set_sensitive (false);
761 midi_option_changed();
763 started_at_least_once = false;
765 if (!ignore_changes) {
766 maybe_display_saved_state ();
771 EngineControl::print_channel_count (Gtk::SpinButton* sb)
773 uint32_t cnt = (uint32_t) sb->get_value();
775 sb->set_text (_("all available channels"));
778 snprintf (buf, sizeof (buf), "%d", cnt);
785 EngineControl::list_devices ()
787 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
790 /* now fill out devices, mark sample rates, buffer sizes insensitive */
792 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
794 /* NOTE: Ardour currently does not display the "available" field of the
797 * Doing so would require a different GUI widget than the combo
798 * box/popdown that we currently use, since it has no way to list
799 * items that are not selectable. Something more like a popup menu,
800 * which could have unselectable items, would be appropriate.
803 vector<string> available_devices;
805 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
806 available_devices.push_back (i->name);
809 if (!available_devices.empty()) {
811 update_sensitivity ();
814 string current_device;
815 current_device = backend->device_name ();
816 if (current_device == "") {
817 // device might not have been set yet
818 current_device = device_combo.get_active_text ();
819 if (current_device == "")
820 // device has never been set, make sure it's not blank
821 current_device = available_devices.front ();
824 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
825 set_popdown_strings (device_combo, available_devices);
827 device_combo.set_active_text (current_device);
832 input_latency.set_sensitive (true);
833 output_latency.set_sensitive (true);
834 input_channels.set_sensitive (true);
835 output_channels.set_sensitive (true);
837 ok_button->set_sensitive (true);
838 apply_button->set_sensitive (true);
841 device_combo.clear();
842 sample_rate_combo.set_sensitive (false);
843 buffer_size_combo.set_sensitive (false);
844 input_latency.set_sensitive (false);
845 output_latency.set_sensitive (false);
846 input_channels.set_sensitive (false);
847 output_channels.set_sensitive (false);
849 ok_button->set_sensitive (false);
850 apply_button->set_sensitive (false);
852 ok_button->set_sensitive (true);
853 apply_button->set_sensitive (true);
859 EngineControl::driver_changed ()
861 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
864 backend->set_driver (driver_combo.get_active_text());
867 if (!ignore_changes) {
868 maybe_display_saved_state ();
873 EngineControl::device_changed ()
876 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
878 string device_name = device_combo.get_active_text ();
882 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
884 /* don't allow programmatic change to combos to cause a
885 recursive call to this method.
895 sr = backend->available_sample_rates (device_name);
898 sr.push_back (8000.0f);
899 sr.push_back (16000.0f);
900 sr.push_back (32000.0f);
901 sr.push_back (44100.0f);
902 sr.push_back (48000.0f);
903 sr.push_back (88200.0f);
904 sr.push_back (96000.0f);
905 sr.push_back (192000.0f);
906 sr.push_back (384000.0f);
909 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
910 s.push_back (rate_as_string (*x));
911 if (*x == _desired_sample_rate) {
917 sample_rate_combo.set_sensitive (true);
918 set_popdown_strings (sample_rate_combo, s);
920 if (desired.empty()) {
921 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
923 sample_rate_combo.set_active_text (desired);
927 sample_rate_combo.set_sensitive (false);
935 bs = backend->available_buffer_sizes (device_name);
936 } else if (backend->can_change_buffer_size_when_running()) {
950 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
951 s.push_back (bufsize_as_string (*x));
955 buffer_size_combo.set_sensitive (true);
956 set_popdown_strings (buffer_size_combo, s);
958 buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
959 show_buffer_duration ();
961 buffer_size_combo.set_sensitive (false);
964 /* XXX theoretically need to set min + max channel counts here
967 manage_control_app_sensitivity ();
970 /* pick up any saved state for this device */
972 if (!ignore_changes) {
973 maybe_display_saved_state ();
978 EngineControl::bufsize_as_string (uint32_t sz)
980 /* Translators: "samples" is always plural here, so no
981 need for plural+singular forms.
984 snprintf (buf, sizeof (buf), _("%u samples"), sz);
989 EngineControl::sample_rate_changed ()
991 /* reset the strings for buffer size to show the correct msec value
992 (reflecting the new sample rate).
995 show_buffer_duration ();
996 if (!ignore_changes) {
1003 EngineControl::buffer_size_changed ()
1005 show_buffer_duration ();
1006 if (!ignore_changes) {
1012 EngineControl::show_buffer_duration ()
1015 /* buffer sizes - convert from just samples to samples + msecs for
1016 * the displayed string
1019 string bs_text = buffer_size_combo.get_active_text ();
1020 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1021 uint32_t rate = get_rate();
1023 /* Translators: "msecs" is ALWAYS plural here, so we do not
1024 need singular form as well.
1026 /* Developers: note the hard-coding of a double buffered model
1027 in the (2 * samples) computation of latency. we always start
1028 the audiobackend in this configuration.
1031 snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
1032 buffer_size_duration_label.set_text (buf);
1036 EngineControl::midi_option_changed ()
1038 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1041 backend->set_midi_option (get_midi_option());
1043 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1045 //_midi_devices.clear(); // TODO merge with state-saved settings..
1046 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1047 std::vector<MidiDeviceSettings> new_devices;
1049 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1050 MidiDeviceSettings mds = find_midi_device (i->name);
1051 if (i->available && !mds) {
1052 uint32_t input_latency = 0;
1053 uint32_t output_latency = 0;
1054 if (_can_set_midi_latencies) {
1055 input_latency = backend->systemic_midi_input_latency (i->name);
1056 output_latency = backend->systemic_midi_output_latency (i->name);
1058 bool enabled = backend->midi_device_enabled (i->name);
1059 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1060 new_devices.push_back (ptr);
1061 } else if (i->available) {
1062 new_devices.push_back (mds);
1065 _midi_devices = new_devices;
1067 if (_midi_devices.empty()) {
1068 midi_devices_button.set_sensitive (false);
1070 midi_devices_button.set_sensitive (true);
1073 if (!ignore_changes) {
1079 EngineControl::parameter_changed ()
1081 if (!ignore_changes) {
1086 EngineControl::State
1087 EngineControl::get_matching_state (
1088 const string& backend,
1089 const string& driver,
1090 const string& device)
1092 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1093 if ((*i)->backend == backend &&
1094 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1102 EngineControl::State
1103 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1105 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1108 return get_matching_state (backend_combo.get_active_text(),
1109 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1110 device_combo.get_active_text());
1114 return get_matching_state (backend_combo.get_active_text(),
1116 device_combo.get_active_text());
1119 EngineControl::State
1120 EngineControl::save_state ()
1124 if (!_have_control) {
1125 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1129 state.reset(new StateStruct);
1130 state->backend = get_backend ();
1132 state.reset(new StateStruct);
1133 store_state (state);
1136 for (StateList::iterator i = states.begin(); i != states.end();) {
1137 if ((*i)->backend == state->backend &&
1138 (*i)->driver == state->driver &&
1139 (*i)->device == state->device) {
1140 i = states.erase(i);
1146 states.push_back (state);
1152 EngineControl::store_state (State state)
1154 state->backend = get_backend ();
1155 state->driver = get_driver ();
1156 state->device = get_device_name ();
1157 state->sample_rate = get_rate ();
1158 state->buffer_size = get_buffer_size ();
1159 state->input_latency = get_input_latency ();
1160 state->output_latency = get_output_latency ();
1161 state->input_channels = get_input_channels ();
1162 state->output_channels = get_output_channels ();
1163 state->midi_option = get_midi_option ();
1164 state->midi_devices = _midi_devices;
1168 EngineControl::maybe_display_saved_state ()
1170 if (!_have_control) {
1174 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1177 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1179 if (!_desired_sample_rate) {
1180 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1182 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1183 /* call this explicitly because we're ignoring changes to
1184 the controls at this point.
1186 show_buffer_duration ();
1187 input_latency.set_value (state->input_latency);
1188 output_latency.set_value (state->output_latency);
1190 if (!state->midi_option.empty()) {
1191 midi_option_combo.set_active_text (state->midi_option);
1192 _midi_devices = state->midi_devices;
1198 EngineControl::get_state ()
1200 XMLNode* root = new XMLNode ("AudioMIDISetup");
1203 if (!states.empty()) {
1204 XMLNode* state_nodes = new XMLNode ("EngineStates");
1206 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1208 XMLNode* node = new XMLNode ("State");
1210 node->add_property ("backend", (*i)->backend);
1211 node->add_property ("driver", (*i)->driver);
1212 node->add_property ("device", (*i)->device);
1213 node->add_property ("sample-rate", (*i)->sample_rate);
1214 node->add_property ("buffer-size", (*i)->buffer_size);
1215 node->add_property ("input-latency", (*i)->input_latency);
1216 node->add_property ("output-latency", (*i)->output_latency);
1217 node->add_property ("input-channels", (*i)->input_channels);
1218 node->add_property ("output-channels", (*i)->output_channels);
1219 node->add_property ("active", (*i)->active ? "yes" : "no");
1220 node->add_property ("midi-option", (*i)->midi_option);
1222 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1223 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1224 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1225 midi_device_stuff->add_property (X_("name"), (*p)->name);
1226 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1227 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1228 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1229 midi_devices->add_child_nocopy (*midi_device_stuff);
1231 node->add_child_nocopy (*midi_devices);
1233 state_nodes->add_child_nocopy (*node);
1236 root->add_child_nocopy (*state_nodes);
1243 EngineControl::set_state (const XMLNode& root)
1245 XMLNodeList clist, cclist;
1246 XMLNodeConstIterator citer, cciter;
1248 XMLNode* grandchild;
1249 XMLProperty* prop = NULL;
1251 if (root.name() != "AudioMIDISetup") {
1255 clist = root.children();
1259 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1263 if (child->name() != "EngineStates") {
1267 cclist = child->children();
1269 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1270 State state (new StateStruct);
1272 grandchild = *cciter;
1274 if (grandchild->name() != "State") {
1278 if ((prop = grandchild->property ("backend")) == 0) {
1281 state->backend = prop->value ();
1283 if ((prop = grandchild->property ("driver")) == 0) {
1286 state->driver = prop->value ();
1288 if ((prop = grandchild->property ("device")) == 0) {
1291 state->device = prop->value ();
1293 if ((prop = grandchild->property ("sample-rate")) == 0) {
1296 state->sample_rate = atof (prop->value ());
1298 if ((prop = grandchild->property ("buffer-size")) == 0) {
1301 state->buffer_size = atoi (prop->value ());
1303 if ((prop = grandchild->property ("input-latency")) == 0) {
1306 state->input_latency = atoi (prop->value ());
1308 if ((prop = grandchild->property ("output-latency")) == 0) {
1311 state->output_latency = atoi (prop->value ());
1313 if ((prop = grandchild->property ("input-channels")) == 0) {
1316 state->input_channels = atoi (prop->value ());
1318 if ((prop = grandchild->property ("output-channels")) == 0) {
1321 state->output_channels = atoi (prop->value ());
1323 if ((prop = grandchild->property ("active")) == 0) {
1326 state->active = string_is_affirmative (prop->value ());
1328 if ((prop = grandchild->property ("midi-option")) == 0) {
1331 state->midi_option = prop->value ();
1333 state->midi_devices.clear();
1335 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1336 const XMLNodeList mnc = midinode->children();
1337 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1338 if ((*n)->property (X_("name")) == 0
1339 || (*n)->property (X_("enabled")) == 0
1340 || (*n)->property (X_("input-latency")) == 0
1341 || (*n)->property (X_("output-latency")) == 0
1346 MidiDeviceSettings ptr (new MidiDeviceSetting(
1347 (*n)->property (X_("name"))->value (),
1348 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1349 atoi ((*n)->property (X_("input-latency"))->value ()),
1350 atoi ((*n)->property (X_("output-latency"))->value ())
1352 state->midi_devices.push_back (ptr);
1357 /* remove accumulated duplicates (due to bug in ealier version)
1358 * this can be removed again before release
1360 for (StateList::iterator i = states.begin(); i != states.end();) {
1361 if ((*i)->backend == state->backend &&
1362 (*i)->driver == state->driver &&
1363 (*i)->device == state->device) {
1364 i = states.erase(i);
1371 states.push_back (state);
1375 /* now see if there was an active state and switch the setup to it */
1377 // purge states of backend that are not available in this built
1378 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1379 vector<std::string> backend_names;
1381 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1382 backend_names.push_back((*i)->name);
1384 for (StateList::iterator i = states.begin(); i != states.end();) {
1385 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1386 i = states.erase(i);
1392 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1396 backend_combo.set_active_text ((*i)->backend);
1397 driver_combo.set_active_text ((*i)->driver);
1398 device_combo.set_active_text ((*i)->device);
1399 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1400 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1401 input_latency.set_value ((*i)->input_latency);
1402 output_latency.set_value ((*i)->output_latency);
1403 midi_option_combo.set_active_text ((*i)->midi_option);
1411 EngineControl::push_state_to_backend (bool start)
1413 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1419 /* figure out what is going to change */
1421 bool restart_required = false;
1422 bool was_running = ARDOUR::AudioEngine::instance()->running();
1423 bool change_driver = false;
1424 bool change_device = false;
1425 bool change_rate = false;
1426 bool change_bufsize = false;
1427 bool change_latency = false;
1428 bool change_channels = false;
1429 bool change_midi = false;
1431 uint32_t ochan = get_output_channels ();
1432 uint32_t ichan = get_input_channels ();
1434 if (_have_control) {
1436 if (started_at_least_once) {
1438 /* we can control the backend */
1440 if (backend->requires_driver_selection()) {
1441 if (get_driver() != backend->driver_name()) {
1442 change_driver = true;
1446 if (get_device_name() != backend->device_name()) {
1447 change_device = true;
1450 if (get_rate() != backend->sample_rate()) {
1454 if (get_buffer_size() != backend->buffer_size()) {
1455 change_bufsize = true;
1458 if (get_midi_option() != backend->midi_option()) {
1462 /* zero-requested channels means "all available" */
1465 ichan = backend->input_channels();
1469 ochan = backend->output_channels();
1472 if (ichan != backend->input_channels()) {
1473 change_channels = true;
1476 if (ochan != backend->output_channels()) {
1477 change_channels = true;
1480 if (get_input_latency() != backend->systemic_input_latency() ||
1481 get_output_latency() != backend->systemic_output_latency()) {
1482 change_latency = true;
1485 /* backend never started, so we have to force a group
1488 change_device = true;
1489 if (backend->requires_driver_selection()) {
1490 change_driver = true;
1493 change_bufsize = true;
1494 change_channels = true;
1495 change_latency = true;
1501 /* we have no control over the backend, meaning that we can
1502 * only possibly change sample rate and buffer size.
1506 if (get_rate() != backend->sample_rate()) {
1507 change_bufsize = true;
1510 if (get_buffer_size() != backend->buffer_size()) {
1511 change_bufsize = true;
1515 if (!_have_control) {
1517 /* We do not have control over the backend, so the best we can
1518 * do is try to change the sample rate and/or bufsize and get
1522 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1526 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1531 backend->set_sample_rate (get_rate());
1534 if (change_bufsize) {
1535 backend->set_buffer_size (get_buffer_size());
1539 if (ARDOUR::AudioEngine::instance()->start ()) {
1540 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1550 /* determine if we need to stop the backend before changing parameters */
1552 if (change_driver || change_device || change_channels || change_latency ||
1553 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1555 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1556 restart_required = true;
1558 restart_required = false;
1563 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1564 /* no changes in any parameters that absolutely require a
1565 * restart, so check those that might be changeable without a
1569 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1570 /* can't do this while running ... */
1571 restart_required = true;
1574 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1575 /* can't do this while running ... */
1576 restart_required = true;
1582 if (restart_required) {
1583 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1590 if (change_driver && backend->set_driver (get_driver())) {
1591 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1594 if (change_device && backend->set_device_name (get_device_name())) {
1595 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1598 if (change_rate && backend->set_sample_rate (get_rate())) {
1599 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1602 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1603 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1607 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1608 if (backend->set_input_channels (get_input_channels())) {
1609 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1612 if (backend->set_output_channels (get_output_channels())) {
1613 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1617 if (change_latency) {
1618 if (backend->set_systemic_input_latency (get_input_latency())) {
1619 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1622 if (backend->set_systemic_output_latency (get_output_latency())) {
1623 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1629 backend->set_midi_option (get_midi_option());
1633 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1634 if (_measure_midi) {
1635 if (*p == _measure_midi) {
1636 backend->set_midi_device_enabled ((*p)->name, true);
1638 backend->set_midi_device_enabled ((*p)->name, false);
1642 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1643 if (backend->can_set_systemic_midi_latencies()) {
1644 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1645 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1650 if (start || (was_running && restart_required)) {
1651 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1662 EngineControl::post_push ()
1664 /* get a pointer to the current state object, creating one if
1668 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1671 state = save_state ();
1677 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1678 (*i)->active = false;
1681 /* mark this one active (to be used next time the dialog is
1685 state->active = true;
1687 if (_have_control) { // XXX
1688 manage_control_app_sensitivity ();
1691 /* schedule a redisplay of MIDI ports */
1692 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1697 EngineControl::get_rate () const
1699 float r = atof (sample_rate_combo.get_active_text ());
1700 /* the string may have been translated with an abbreviation for
1701 * thousands, so use a crude heuristic to fix this.
1711 EngineControl::get_buffer_size () const
1713 string txt = buffer_size_combo.get_active_text ();
1716 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1724 EngineControl::get_midi_option () const
1726 return midi_option_combo.get_active_text();
1730 EngineControl::get_input_channels() const
1732 return (uint32_t) input_channels_adjustment.get_value();
1736 EngineControl::get_output_channels() const
1738 return (uint32_t) output_channels_adjustment.get_value();
1742 EngineControl::get_input_latency() const
1744 return (uint32_t) input_latency_adjustment.get_value();
1748 EngineControl::get_output_latency() const
1750 return (uint32_t) output_latency_adjustment.get_value();
1754 EngineControl::get_backend () const
1756 return backend_combo.get_active_text ();
1760 EngineControl::get_driver () const
1762 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1763 return driver_combo.get_active_text ();
1770 EngineControl::get_device_name () const
1772 return device_combo.get_active_text ();
1776 EngineControl::control_app_button_clicked ()
1778 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1784 backend->launch_control_app ();
1788 EngineControl::manage_control_app_sensitivity ()
1790 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1796 string appname = backend->control_app_name();
1798 if (appname.empty()) {
1799 control_app_button.set_sensitive (false);
1801 control_app_button.set_sensitive (true);
1806 EngineControl::set_desired_sample_rate (uint32_t sr)
1808 _desired_sample_rate = sr;
1813 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1815 if (page_num == 0) {
1816 cancel_button->set_sensitive (true);
1817 ok_button->set_sensitive (true);
1818 apply_button->set_sensitive (true);
1819 _measure_midi.reset();
1821 cancel_button->set_sensitive (false);
1822 ok_button->set_sensitive (false);
1823 apply_button->set_sensitive (false);
1826 if (page_num == midi_tab) {
1828 refresh_midi_display ();
1831 if (page_num == latency_tab) {
1834 if (ARDOUR::AudioEngine::instance()->running()) {
1835 // TODO - mark as 'stopped for latency
1836 ARDOUR_UI::instance()->disconnect_from_engine ();
1840 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1842 /* save any existing latency values */
1844 uint32_t il = (uint32_t) input_latency.get_value ();
1845 uint32_t ol = (uint32_t) input_latency.get_value ();
1847 /* reset to zero so that our new test instance
1848 will be clean of any existing latency measures.
1850 NB. this should really be done by the backend
1851 when stated for latency measurement.
1854 input_latency.set_value (0);
1855 output_latency.set_value (0);
1857 push_state_to_backend (false);
1861 input_latency.set_value (il);
1862 output_latency.set_value (ol);
1865 // This should be done in push_state_to_backend()
1866 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1867 disable_latency_tab ();
1870 enable_latency_tab ();
1874 end_latency_detection ();
1875 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1880 /* latency measurement */
1883 EngineControl::check_audio_latency_measurement ()
1885 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1887 if (mtdm->resolve () < 0) {
1888 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1892 if (mtdm->err () > 0.3) {
1898 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1900 if (sample_rate == 0) {
1901 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1902 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1906 int frames_total = mtdm->del();
1907 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1909 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1910 _("Detected roundtrip latency: "),
1911 frames_total, frames_total * 1000.0f/sample_rate,
1912 _("Systemic latency: "),
1913 extra, extra * 1000.0f/sample_rate);
1917 if (mtdm->err () > 0.2) {
1919 strcat (buf, _("(signal detection error)"));
1925 strcat (buf, _("(inverted - bad wiring)"));
1930 have_lm_results = true;
1931 end_latency_detection ();
1932 lm_use_button.set_sensitive (true);
1936 lm_results.set_markup (string_compose (results_markup, buf));
1942 EngineControl::check_midi_latency_measurement ()
1944 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1946 if (!mididm->have_signal () || mididm->latency () == 0) {
1947 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1952 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1954 if (sample_rate == 0) {
1955 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1956 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1960 ARDOUR::framecnt_t frames_total = mididm->latency();
1961 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1962 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1963 _("Detected roundtrip latency: "),
1964 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1965 _("Systemic latency: "),
1966 extra, extra * 1000.0f / sample_rate);
1970 if (!mididm->ok ()) {
1972 strcat (buf, _("(averaging)"));
1976 if (mididm->deviation () > 50.0) {
1978 strcat (buf, _("(too large jitter)"));
1980 } else if (mididm->deviation () > 10.0) {
1982 strcat (buf, _("(large jitter)"));
1986 have_lm_results = true;
1987 end_latency_detection ();
1988 lm_use_button.set_sensitive (true);
1990 } else if (mididm->processed () > 400) {
1991 have_lm_results = false;
1992 end_latency_detection ();
1993 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
1997 lm_results.set_markup (string_compose (results_markup, buf));
2003 EngineControl::start_latency_detection ()
2005 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2006 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2008 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2009 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2010 if (_measure_midi) {
2011 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2013 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2015 lm_measure_label.set_text (_("Cancel"));
2016 have_lm_results = false;
2017 lm_use_button.set_sensitive (false);
2018 lm_input_channel_combo.set_sensitive (false);
2019 lm_output_channel_combo.set_sensitive (false);
2025 EngineControl::end_latency_detection ()
2027 latency_timeout.disconnect ();
2028 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2029 lm_measure_label.set_text (_("Measure"));
2030 if (!have_lm_results) {
2031 lm_use_button.set_sensitive (false);
2033 lm_input_channel_combo.set_sensitive (true);
2034 lm_output_channel_combo.set_sensitive (true);
2039 EngineControl::latency_button_clicked ()
2042 start_latency_detection ();
2044 end_latency_detection ();
2049 EngineControl::use_latency_button_clicked ()
2051 if (_measure_midi) {
2052 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2056 ARDOUR::framecnt_t frames_total = mididm->latency();
2057 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2058 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2059 _measure_midi->input_latency = one_way;
2060 _measure_midi->output_latency = one_way;
2061 notebook.set_current_page (midi_tab);
2063 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2069 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2070 one_way = std::max (0., one_way);
2072 input_latency_adjustment.set_value (one_way);
2073 output_latency_adjustment.set_value (one_way);
2075 /* back to settings page */
2076 notebook.set_current_page (0);
2082 EngineControl::on_delete_event (GdkEventAny* ev)
2084 if (notebook.get_current_page() == 2) {
2085 /* currently on latency tab - be sure to clean up */
2086 end_latency_detection ();
2088 return ArdourDialog::on_delete_event (ev);
2092 EngineControl::engine_running ()
2094 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2097 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2098 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2100 buffer_size_combo.set_sensitive (true);
2101 sample_rate_combo.set_sensitive (true);
2103 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2105 started_at_least_once = true;
2109 EngineControl::engine_stopped ()
2111 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2114 buffer_size_combo.set_sensitive (false);
2115 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2117 sample_rate_combo.set_sensitive (true);
2118 buffer_size_combo.set_sensitive (true);
2122 EngineControl::connect_disconnect_click()
2124 if (ARDOUR::AudioEngine::instance()->running()) {
2125 ARDOUR_UI::instance()->disconnect_from_engine ();
2127 ARDOUR_UI::instance()->reconnect_to_engine ();
2132 EngineControl::calibrate_audio_latency ()
2134 _measure_midi.reset ();
2135 have_lm_results = false;
2136 lm_use_button.set_sensitive (false);
2137 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2138 notebook.set_current_page (latency_tab);
2142 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2145 have_lm_results = false;
2146 lm_use_button.set_sensitive (false);
2147 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2148 notebook.set_current_page (latency_tab);
2152 EngineControl::configure_midi_devices ()
2154 notebook.set_current_page (midi_tab);