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));
302 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
303 connect_disconnect_button.set_no_show_all();
308 EngineControl::on_show ()
310 ArdourDialog::on_show ();
312 ok_button->grab_focus();
316 EngineControl::on_response (int response_id)
318 ArdourDialog::on_response (response_id);
320 switch (response_id) {
322 push_state_to_backend (true);
325 push_state_to_backend (true);
328 case RESPONSE_DELETE_EVENT:
331 ev.type = GDK_BUTTON_PRESS;
333 on_delete_event ((GdkEventAny*) &ev);
342 EngineControl::build_notebook ()
345 AttachOptions xopt = AttachOptions (FILL|EXPAND);
347 /* clear the table */
349 Gtkmm2ext::container_clear (basic_vbox);
350 Gtkmm2ext::container_clear (basic_packer);
352 if (control_app_button.get_parent()) {
353 control_app_button.get_parent()->remove (control_app_button);
356 label = manage (left_aligned_label (_("Audio System:")));
357 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
358 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
360 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
361 lm_button_audio.set_name ("generic button");
362 lm_button_audio.set_can_focus(true);
365 build_full_control_notebook ();
367 build_no_control_notebook ();
370 basic_vbox.pack_start (basic_hbox, false, false);
373 Gtk::HBox* hpacker = manage (new HBox);
374 hpacker->set_border_width (12);
375 hpacker->pack_start (control_app_button, false, false);
377 control_app_button.show();
378 basic_vbox.pack_start (*hpacker);
382 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
383 basic_vbox.show_all ();
388 EngineControl::build_full_control_notebook ()
390 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
393 using namespace Notebook_Helpers;
395 vector<string> strings;
396 AttachOptions xopt = AttachOptions (FILL|EXPAND);
397 int row = 1; // row zero == backend combo
399 /* start packing it up */
401 if (backend->requires_driver_selection()) {
402 label = manage (left_aligned_label (_("Driver:")));
403 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
404 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
408 label = manage (left_aligned_label (_("Device:")));
409 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
410 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
413 label = manage (left_aligned_label (_("Sample rate:")));
414 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
415 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
419 label = manage (left_aligned_label (_("Buffer size:")));
420 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
421 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
422 buffer_size_duration_label.set_alignment (0.0); /* left-align */
423 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
426 input_channels.set_name ("InputChannels");
427 input_channels.set_flags (Gtk::CAN_FOCUS);
428 input_channels.set_digits (0);
429 input_channels.set_wrap (false);
430 output_channels.set_editable (true);
432 label = manage (left_aligned_label (_("Input Channels:")));
433 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
434 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
437 output_channels.set_name ("OutputChannels");
438 output_channels.set_flags (Gtk::CAN_FOCUS);
439 output_channels.set_digits (0);
440 output_channels.set_wrap (false);
441 output_channels.set_editable (true);
443 label = manage (left_aligned_label (_("Output Channels:")));
444 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
445 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
448 input_latency.set_name ("InputLatency");
449 input_latency.set_flags (Gtk::CAN_FOCUS);
450 input_latency.set_digits (0);
451 input_latency.set_wrap (false);
452 input_latency.set_editable (true);
454 label = manage (left_aligned_label (_("Hardware input latency:")));
455 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
456 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
457 label = manage (left_aligned_label (_("samples")));
458 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
461 output_latency.set_name ("OutputLatency");
462 output_latency.set_flags (Gtk::CAN_FOCUS);
463 output_latency.set_digits (0);
464 output_latency.set_wrap (false);
465 output_latency.set_editable (true);
467 label = manage (left_aligned_label (_("Hardware output latency:")));
468 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
469 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
470 label = manage (left_aligned_label (_("samples")));
471 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
473 /* button spans 2 rows */
475 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
478 label = manage (left_aligned_label (_("MIDI System")));
479 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
480 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
481 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
486 EngineControl::build_no_control_notebook ()
488 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
491 using namespace Notebook_Helpers;
493 vector<string> strings;
494 AttachOptions xopt = AttachOptions (FILL|EXPAND);
495 int row = 1; // row zero == backend combo
496 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
498 label = manage (new Label);
499 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
500 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
503 if (backend->can_change_sample_rate_when_running()) {
504 label = manage (left_aligned_label (_("Sample rate:")));
505 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
506 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
510 if (backend->can_change_buffer_size_when_running()) {
511 label = manage (left_aligned_label (_("Buffer size:")));
512 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
513 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
514 buffer_size_duration_label.set_alignment (0.0); /* left-align */
515 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
519 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
523 EngineControl::~EngineControl ()
525 ignore_changes = true;
529 EngineControl::disable_latency_tab ()
531 vector<string> empty;
532 set_popdown_strings (lm_output_channel_combo, empty);
533 set_popdown_strings (lm_input_channel_combo, empty);
534 lm_measure_button.set_sensitive (false);
535 lm_use_button.set_sensitive (false);
539 EngineControl::enable_latency_tab ()
541 vector<string> outputs;
542 vector<string> inputs;
544 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
545 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
546 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
548 if (!ARDOUR::AudioEngine::instance()->running()) {
549 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
550 notebook.set_current_page (0);
554 else if (inputs.empty() || outputs.empty()) {
555 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
556 notebook.set_current_page (0);
561 lm_back_button_signal.disconnect();
563 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
566 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
570 set_popdown_strings (lm_output_channel_combo, outputs);
571 lm_output_channel_combo.set_active_text (outputs.front());
572 lm_output_channel_combo.set_sensitive (true);
574 set_popdown_strings (lm_input_channel_combo, inputs);
575 lm_input_channel_combo.set_active_text (inputs.front());
576 lm_input_channel_combo.set_sensitive (true);
578 lm_measure_button.set_sensitive (true);
582 EngineControl::setup_midi_tab_for_backend ()
584 string backend = backend_combo.get_active_text ();
586 Gtkmm2ext::container_clear (midi_vbox);
588 midi_vbox.set_border_width (12);
589 midi_device_table.set_border_width (12);
591 if (backend == "JACK") {
592 setup_midi_tab_for_jack ();
595 midi_vbox.pack_start (midi_device_table, true, true);
596 midi_vbox.pack_start (midi_back_button, false, false);
597 midi_vbox.show_all ();
601 EngineControl::setup_midi_tab_for_jack ()
606 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
608 device->input_latency = a->get_value();
610 device->output_latency = a->get_value();
615 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
616 b->set_active (!b->get_active());
617 device->enabled = b->get_active();
618 refresh_midi_display(device->name);
622 EngineControl::refresh_midi_display (std::string focus)
624 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
628 AttachOptions xopt = AttachOptions (FILL|EXPAND);
631 Gtkmm2ext::container_clear (midi_device_table);
633 midi_device_table.set_spacings (6);
635 l = manage (new Label);
636 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
637 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
638 l->set_alignment (0.5, 0.5);
642 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
643 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
644 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
645 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
647 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
648 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
649 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
650 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
653 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
658 bool enabled = (*p)->enabled;
660 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
661 m->set_name ("midi device");
662 m->set_can_focus (Gtk::CAN_FOCUS);
663 m->add_events (Gdk::BUTTON_RELEASE_MASK);
664 m->set_active (enabled);
665 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
666 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
667 if ((*p)->name == focus) {
671 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
672 s = manage (new Gtk::SpinButton (*a));
673 a->set_value ((*p)->input_latency);
674 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
675 s->set_sensitive (_can_set_midi_latencies && enabled);
676 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
678 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
679 s = manage (new Gtk::SpinButton (*a));
680 a->set_value ((*p)->output_latency);
681 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
682 s->set_sensitive (_can_set_midi_latencies && enabled);
683 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
685 b = manage (new Button (_("Calibrate")));
686 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
687 b->set_sensitive (_can_set_midi_latencies && enabled);
688 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
695 EngineControl::update_sensitivity ()
700 EngineControl::backend_changed ()
702 string backend_name = backend_combo.get_active_text();
703 boost::shared_ptr<ARDOUR::AudioBackend> backend;
705 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
706 /* eh? setting the backend failed... how ? */
710 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
713 setup_midi_tab_for_backend ();
714 _midi_devices.clear();
716 if (backend->requires_driver_selection()) {
717 vector<string> drivers = backend->enumerate_drivers();
718 driver_combo.set_sensitive (true);
720 if (!drivers.empty()) {
722 string current_driver;
723 current_driver = backend->driver_name ();
725 // driver might not have been set yet
726 if (current_driver == "") {
727 current_driver = driver_combo.get_active_text ();
728 if (current_driver == "")
729 // driver has never been set, make sure it's not blank
730 current_driver = drivers.front ();
733 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
734 set_popdown_strings (driver_combo, drivers);
735 driver_combo.set_active_text (current_driver);
742 driver_combo.set_sensitive (false);
743 /* this will change the device text which will cause a call to
744 * device changed which will set up parameters
749 vector<string> midi_options = backend->enumerate_midi_options();
751 if (midi_options.size() == 1) {
752 /* only contains the "none" option */
753 midi_option_combo.set_sensitive (false);
756 set_popdown_strings (midi_option_combo, midi_options);
757 midi_option_combo.set_active_text (midi_options.front());
758 midi_option_combo.set_sensitive (true);
760 midi_option_combo.set_sensitive (false);
764 connect_disconnect_button.hide();
766 midi_option_changed();
768 started_at_least_once = false;
770 if (!ignore_changes) {
771 maybe_display_saved_state ();
776 EngineControl::print_channel_count (Gtk::SpinButton* sb)
778 uint32_t cnt = (uint32_t) sb->get_value();
780 sb->set_text (_("all available channels"));
783 snprintf (buf, sizeof (buf), "%d", cnt);
790 EngineControl::list_devices ()
792 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
795 /* now fill out devices, mark sample rates, buffer sizes insensitive */
797 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
799 /* NOTE: Ardour currently does not display the "available" field of the
802 * Doing so would require a different GUI widget than the combo
803 * box/popdown that we currently use, since it has no way to list
804 * items that are not selectable. Something more like a popup menu,
805 * which could have unselectable items, would be appropriate.
808 vector<string> available_devices;
810 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
811 available_devices.push_back (i->name);
814 if (!available_devices.empty()) {
816 update_sensitivity ();
819 string current_device;
820 current_device = backend->device_name ();
821 if (current_device == "") {
822 // device might not have been set yet
823 current_device = device_combo.get_active_text ();
824 if (current_device == "")
825 // device has never been set, make sure it's not blank
826 current_device = available_devices.front ();
829 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
830 set_popdown_strings (device_combo, available_devices);
832 device_combo.set_active_text (current_device);
837 input_latency.set_sensitive (true);
838 output_latency.set_sensitive (true);
839 input_channels.set_sensitive (true);
840 output_channels.set_sensitive (true);
842 ok_button->set_sensitive (true);
843 apply_button->set_sensitive (true);
846 device_combo.clear();
847 sample_rate_combo.set_sensitive (false);
848 buffer_size_combo.set_sensitive (false);
849 input_latency.set_sensitive (false);
850 output_latency.set_sensitive (false);
851 input_channels.set_sensitive (false);
852 output_channels.set_sensitive (false);
854 ok_button->set_sensitive (false);
855 apply_button->set_sensitive (false);
857 ok_button->set_sensitive (true);
858 apply_button->set_sensitive (true);
859 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
860 sample_rate_combo.set_sensitive (true);
862 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
863 buffer_size_combo.set_sensitive (true);
871 EngineControl::driver_changed ()
873 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
876 backend->set_driver (driver_combo.get_active_text());
879 if (!ignore_changes) {
880 maybe_display_saved_state ();
885 EngineControl::device_changed ()
888 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
890 string device_name = device_combo.get_active_text ();
894 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
896 /* don't allow programmatic change to combos to cause a
897 recursive call to this method.
907 sr = backend->available_sample_rates (device_name);
910 sr.push_back (8000.0f);
911 sr.push_back (16000.0f);
912 sr.push_back (32000.0f);
913 sr.push_back (44100.0f);
914 sr.push_back (48000.0f);
915 sr.push_back (88200.0f);
916 sr.push_back (96000.0f);
917 sr.push_back (192000.0f);
918 sr.push_back (384000.0f);
921 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
922 s.push_back (rate_as_string (*x));
923 if (*x == _desired_sample_rate) {
929 sample_rate_combo.set_sensitive (true);
930 set_popdown_strings (sample_rate_combo, s);
932 if (desired.empty()) {
933 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
935 sample_rate_combo.set_active_text (desired);
939 sample_rate_combo.set_sensitive (false);
947 bs = backend->available_buffer_sizes (device_name);
948 } else if (backend->can_change_buffer_size_when_running()) {
962 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
963 s.push_back (bufsize_as_string (*x));
967 buffer_size_combo.set_sensitive (true);
968 set_popdown_strings (buffer_size_combo, s);
970 uint32_t period = backend->buffer_size();
972 period = backend->default_buffer_size(device_name);
974 buffer_size_combo.set_active_text (bufsize_as_string (period));
975 show_buffer_duration ();
977 buffer_size_combo.set_sensitive (false);
980 /* XXX theoretically need to set min + max channel counts here
983 manage_control_app_sensitivity ();
986 /* pick up any saved state for this device */
988 if (!ignore_changes) {
989 maybe_display_saved_state ();
994 EngineControl::bufsize_as_string (uint32_t sz)
996 /* Translators: "samples" is always plural here, so no
997 need for plural+singular forms.
1000 snprintf (buf, sizeof (buf), _("%u samples"), sz);
1005 EngineControl::sample_rate_changed ()
1007 /* reset the strings for buffer size to show the correct msec value
1008 (reflecting the new sample rate).
1011 show_buffer_duration ();
1012 if (!ignore_changes) {
1019 EngineControl::buffer_size_changed ()
1021 show_buffer_duration ();
1022 if (!ignore_changes) {
1028 EngineControl::show_buffer_duration ()
1031 /* buffer sizes - convert from just samples to samples + msecs for
1032 * the displayed string
1035 string bs_text = buffer_size_combo.get_active_text ();
1036 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1037 uint32_t rate = get_rate();
1039 /* Developers: note the hard-coding of a double buffered model
1040 in the (2 * samples) computation of latency. we always start
1041 the audiobackend in this configuration.
1043 /* note to jack1 developers: ardour also always starts the engine
1044 * in async mode (no jack2 --sync option) which adds an extra cycle
1045 * of latency with jack2 (and *3 would be correct)
1046 * The value can also be wrong if jackd is started externally..
1048 * At the time of writing the ALSA backend always uses double-buffering *2,
1049 * The Dummy backend *1, and who knows what ASIO really does :)
1051 * So just display the period size, that's also what
1052 * ARDOUR_UI::update_sample_rate() does for the status bar.
1053 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1054 * but still, that's the buffer period, not [round-trip] latency)
1057 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1058 buffer_size_duration_label.set_text (buf);
1062 EngineControl::midi_option_changed ()
1064 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1067 backend->set_midi_option (get_midi_option());
1069 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1071 //_midi_devices.clear(); // TODO merge with state-saved settings..
1072 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1073 std::vector<MidiDeviceSettings> new_devices;
1075 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1076 MidiDeviceSettings mds = find_midi_device (i->name);
1077 if (i->available && !mds) {
1078 uint32_t input_latency = 0;
1079 uint32_t output_latency = 0;
1080 if (_can_set_midi_latencies) {
1081 input_latency = backend->systemic_midi_input_latency (i->name);
1082 output_latency = backend->systemic_midi_output_latency (i->name);
1084 bool enabled = backend->midi_device_enabled (i->name);
1085 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1086 new_devices.push_back (ptr);
1087 } else if (i->available) {
1088 new_devices.push_back (mds);
1091 _midi_devices = new_devices;
1093 if (_midi_devices.empty()) {
1094 midi_devices_button.set_sensitive (false);
1096 midi_devices_button.set_sensitive (true);
1099 if (!ignore_changes) {
1105 EngineControl::parameter_changed ()
1107 if (!ignore_changes) {
1112 EngineControl::State
1113 EngineControl::get_matching_state (
1114 const string& backend,
1115 const string& driver,
1116 const string& device)
1118 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1119 if ((*i)->backend == backend &&
1120 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1128 EngineControl::State
1129 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1131 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1134 return get_matching_state (backend_combo.get_active_text(),
1135 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1136 device_combo.get_active_text());
1140 return get_matching_state (backend_combo.get_active_text(),
1142 device_combo.get_active_text());
1145 EngineControl::State
1146 EngineControl::save_state ()
1150 if (!_have_control) {
1151 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1155 state.reset(new StateStruct);
1156 state->backend = get_backend ();
1158 state.reset(new StateStruct);
1159 store_state (state);
1162 for (StateList::iterator i = states.begin(); i != states.end();) {
1163 if ((*i)->backend == state->backend &&
1164 (*i)->driver == state->driver &&
1165 (*i)->device == state->device) {
1166 i = states.erase(i);
1172 states.push_back (state);
1178 EngineControl::store_state (State state)
1180 state->backend = get_backend ();
1181 state->driver = get_driver ();
1182 state->device = get_device_name ();
1183 state->sample_rate = get_rate ();
1184 state->buffer_size = get_buffer_size ();
1185 state->input_latency = get_input_latency ();
1186 state->output_latency = get_output_latency ();
1187 state->input_channels = get_input_channels ();
1188 state->output_channels = get_output_channels ();
1189 state->midi_option = get_midi_option ();
1190 state->midi_devices = _midi_devices;
1194 EngineControl::maybe_display_saved_state ()
1196 if (!_have_control) {
1200 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1203 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1205 if (!_desired_sample_rate) {
1206 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1208 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1209 /* call this explicitly because we're ignoring changes to
1210 the controls at this point.
1212 show_buffer_duration ();
1213 input_latency.set_value (state->input_latency);
1214 output_latency.set_value (state->output_latency);
1216 if (!state->midi_option.empty()) {
1217 midi_option_combo.set_active_text (state->midi_option);
1218 _midi_devices = state->midi_devices;
1224 EngineControl::get_state ()
1226 XMLNode* root = new XMLNode ("AudioMIDISetup");
1229 if (!states.empty()) {
1230 XMLNode* state_nodes = new XMLNode ("EngineStates");
1232 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1234 XMLNode* node = new XMLNode ("State");
1236 node->add_property ("backend", (*i)->backend);
1237 node->add_property ("driver", (*i)->driver);
1238 node->add_property ("device", (*i)->device);
1239 node->add_property ("sample-rate", (*i)->sample_rate);
1240 node->add_property ("buffer-size", (*i)->buffer_size);
1241 node->add_property ("input-latency", (*i)->input_latency);
1242 node->add_property ("output-latency", (*i)->output_latency);
1243 node->add_property ("input-channels", (*i)->input_channels);
1244 node->add_property ("output-channels", (*i)->output_channels);
1245 node->add_property ("active", (*i)->active ? "yes" : "no");
1246 node->add_property ("midi-option", (*i)->midi_option);
1248 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1249 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1250 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1251 midi_device_stuff->add_property (X_("name"), (*p)->name);
1252 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1253 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1254 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1255 midi_devices->add_child_nocopy (*midi_device_stuff);
1257 node->add_child_nocopy (*midi_devices);
1259 state_nodes->add_child_nocopy (*node);
1262 root->add_child_nocopy (*state_nodes);
1269 EngineControl::set_state (const XMLNode& root)
1271 XMLNodeList clist, cclist;
1272 XMLNodeConstIterator citer, cciter;
1274 XMLNode* grandchild;
1275 XMLProperty* prop = NULL;
1277 if (root.name() != "AudioMIDISetup") {
1281 clist = root.children();
1285 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1289 if (child->name() != "EngineStates") {
1293 cclist = child->children();
1295 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1296 State state (new StateStruct);
1298 grandchild = *cciter;
1300 if (grandchild->name() != "State") {
1304 if ((prop = grandchild->property ("backend")) == 0) {
1307 state->backend = prop->value ();
1309 if ((prop = grandchild->property ("driver")) == 0) {
1312 state->driver = prop->value ();
1314 if ((prop = grandchild->property ("device")) == 0) {
1317 state->device = prop->value ();
1319 if ((prop = grandchild->property ("sample-rate")) == 0) {
1322 state->sample_rate = atof (prop->value ());
1324 if ((prop = grandchild->property ("buffer-size")) == 0) {
1327 state->buffer_size = atoi (prop->value ());
1329 if ((prop = grandchild->property ("input-latency")) == 0) {
1332 state->input_latency = atoi (prop->value ());
1334 if ((prop = grandchild->property ("output-latency")) == 0) {
1337 state->output_latency = atoi (prop->value ());
1339 if ((prop = grandchild->property ("input-channels")) == 0) {
1342 state->input_channels = atoi (prop->value ());
1344 if ((prop = grandchild->property ("output-channels")) == 0) {
1347 state->output_channels = atoi (prop->value ());
1349 if ((prop = grandchild->property ("active")) == 0) {
1352 state->active = string_is_affirmative (prop->value ());
1354 if ((prop = grandchild->property ("midi-option")) == 0) {
1357 state->midi_option = prop->value ();
1359 state->midi_devices.clear();
1361 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1362 const XMLNodeList mnc = midinode->children();
1363 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1364 if ((*n)->property (X_("name")) == 0
1365 || (*n)->property (X_("enabled")) == 0
1366 || (*n)->property (X_("input-latency")) == 0
1367 || (*n)->property (X_("output-latency")) == 0
1372 MidiDeviceSettings ptr (new MidiDeviceSetting(
1373 (*n)->property (X_("name"))->value (),
1374 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1375 atoi ((*n)->property (X_("input-latency"))->value ()),
1376 atoi ((*n)->property (X_("output-latency"))->value ())
1378 state->midi_devices.push_back (ptr);
1383 /* remove accumulated duplicates (due to bug in ealier version)
1384 * this can be removed again before release
1386 for (StateList::iterator i = states.begin(); i != states.end();) {
1387 if ((*i)->backend == state->backend &&
1388 (*i)->driver == state->driver &&
1389 (*i)->device == state->device) {
1390 i = states.erase(i);
1397 states.push_back (state);
1401 /* now see if there was an active state and switch the setup to it */
1403 // purge states of backend that are not available in this built
1404 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1405 vector<std::string> backend_names;
1407 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1408 backend_names.push_back((*i)->name);
1410 for (StateList::iterator i = states.begin(); i != states.end();) {
1411 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1412 i = states.erase(i);
1418 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1422 backend_combo.set_active_text ((*i)->backend);
1423 driver_combo.set_active_text ((*i)->driver);
1424 device_combo.set_active_text ((*i)->device);
1425 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1426 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1427 input_latency.set_value ((*i)->input_latency);
1428 output_latency.set_value ((*i)->output_latency);
1429 midi_option_combo.set_active_text ((*i)->midi_option);
1437 EngineControl::push_state_to_backend (bool start)
1439 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1445 /* figure out what is going to change */
1447 bool restart_required = false;
1448 bool was_running = ARDOUR::AudioEngine::instance()->running();
1449 bool change_driver = false;
1450 bool change_device = false;
1451 bool change_rate = false;
1452 bool change_bufsize = false;
1453 bool change_latency = false;
1454 bool change_channels = false;
1455 bool change_midi = false;
1457 uint32_t ochan = get_output_channels ();
1458 uint32_t ichan = get_input_channels ();
1460 if (_have_control) {
1462 if (started_at_least_once) {
1464 /* we can control the backend */
1466 if (backend->requires_driver_selection()) {
1467 if (get_driver() != backend->driver_name()) {
1468 change_driver = true;
1472 if (get_device_name() != backend->device_name()) {
1473 change_device = true;
1476 if (get_rate() != backend->sample_rate()) {
1480 if (get_buffer_size() != backend->buffer_size()) {
1481 change_bufsize = true;
1484 if (get_midi_option() != backend->midi_option()) {
1488 /* zero-requested channels means "all available" */
1491 ichan = backend->input_channels();
1495 ochan = backend->output_channels();
1498 if (ichan != backend->input_channels()) {
1499 change_channels = true;
1502 if (ochan != backend->output_channels()) {
1503 change_channels = true;
1506 if (get_input_latency() != backend->systemic_input_latency() ||
1507 get_output_latency() != backend->systemic_output_latency()) {
1508 change_latency = true;
1511 /* backend never started, so we have to force a group
1514 change_device = true;
1515 if (backend->requires_driver_selection()) {
1516 change_driver = true;
1519 change_bufsize = true;
1520 change_channels = true;
1521 change_latency = true;
1527 /* we have no control over the backend, meaning that we can
1528 * only possibly change sample rate and buffer size.
1532 if (get_rate() != backend->sample_rate()) {
1533 change_bufsize = true;
1536 if (get_buffer_size() != backend->buffer_size()) {
1537 change_bufsize = true;
1541 if (!_have_control) {
1543 /* We do not have control over the backend, so the best we can
1544 * do is try to change the sample rate and/or bufsize and get
1548 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1552 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1557 backend->set_sample_rate (get_rate());
1560 if (change_bufsize) {
1561 backend->set_buffer_size (get_buffer_size());
1565 if (ARDOUR::AudioEngine::instance()->start ()) {
1566 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1576 /* determine if we need to stop the backend before changing parameters */
1578 if (change_driver || change_device || change_channels || change_latency ||
1579 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1581 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1582 restart_required = true;
1584 restart_required = false;
1589 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1590 /* no changes in any parameters that absolutely require a
1591 * restart, so check those that might be changeable without a
1595 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1596 /* can't do this while running ... */
1597 restart_required = true;
1600 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1601 /* can't do this while running ... */
1602 restart_required = true;
1608 if (restart_required) {
1609 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1616 if (change_driver && backend->set_driver (get_driver())) {
1617 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1620 if (change_device && backend->set_device_name (get_device_name())) {
1621 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1624 if (change_rate && backend->set_sample_rate (get_rate())) {
1625 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1628 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1629 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1633 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1634 if (backend->set_input_channels (get_input_channels())) {
1635 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1638 if (backend->set_output_channels (get_output_channels())) {
1639 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1643 if (change_latency) {
1644 if (backend->set_systemic_input_latency (get_input_latency())) {
1645 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1648 if (backend->set_systemic_output_latency (get_output_latency())) {
1649 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1655 backend->set_midi_option (get_midi_option());
1659 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1660 if (_measure_midi) {
1661 if (*p == _measure_midi) {
1662 backend->set_midi_device_enabled ((*p)->name, true);
1664 backend->set_midi_device_enabled ((*p)->name, false);
1668 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1669 if (backend->can_set_systemic_midi_latencies()) {
1670 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1671 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1676 if (start || (was_running && restart_required)) {
1677 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1688 EngineControl::post_push ()
1690 /* get a pointer to the current state object, creating one if
1694 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1697 state = save_state ();
1703 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1704 (*i)->active = false;
1707 /* mark this one active (to be used next time the dialog is
1711 state->active = true;
1713 if (_have_control) { // XXX
1714 manage_control_app_sensitivity ();
1717 /* schedule a redisplay of MIDI ports */
1718 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1723 EngineControl::get_rate () const
1725 float r = atof (sample_rate_combo.get_active_text ());
1726 /* the string may have been translated with an abbreviation for
1727 * thousands, so use a crude heuristic to fix this.
1737 EngineControl::get_buffer_size () const
1739 string txt = buffer_size_combo.get_active_text ();
1742 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1750 EngineControl::get_midi_option () const
1752 return midi_option_combo.get_active_text();
1756 EngineControl::get_input_channels() const
1758 return (uint32_t) input_channels_adjustment.get_value();
1762 EngineControl::get_output_channels() const
1764 return (uint32_t) output_channels_adjustment.get_value();
1768 EngineControl::get_input_latency() const
1770 return (uint32_t) input_latency_adjustment.get_value();
1774 EngineControl::get_output_latency() const
1776 return (uint32_t) output_latency_adjustment.get_value();
1780 EngineControl::get_backend () const
1782 return backend_combo.get_active_text ();
1786 EngineControl::get_driver () const
1788 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1789 return driver_combo.get_active_text ();
1796 EngineControl::get_device_name () const
1798 return device_combo.get_active_text ();
1802 EngineControl::control_app_button_clicked ()
1804 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1810 backend->launch_control_app ();
1814 EngineControl::manage_control_app_sensitivity ()
1816 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1822 string appname = backend->control_app_name();
1824 if (appname.empty()) {
1825 control_app_button.set_sensitive (false);
1827 control_app_button.set_sensitive (true);
1832 EngineControl::set_desired_sample_rate (uint32_t sr)
1834 _desired_sample_rate = sr;
1839 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1841 if (page_num == 0) {
1842 cancel_button->set_sensitive (true);
1843 ok_button->set_sensitive (true);
1844 apply_button->set_sensitive (true);
1845 _measure_midi.reset();
1847 cancel_button->set_sensitive (false);
1848 ok_button->set_sensitive (false);
1849 apply_button->set_sensitive (false);
1852 if (page_num == midi_tab) {
1854 refresh_midi_display ();
1857 if (page_num == latency_tab) {
1860 if (ARDOUR::AudioEngine::instance()->running()) {
1861 // TODO - mark as 'stopped for latency
1862 ARDOUR_UI::instance()->disconnect_from_engine ();
1866 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1868 /* save any existing latency values */
1870 uint32_t il = (uint32_t) input_latency.get_value ();
1871 uint32_t ol = (uint32_t) input_latency.get_value ();
1873 /* reset to zero so that our new test instance
1874 will be clean of any existing latency measures.
1876 NB. this should really be done by the backend
1877 when stated for latency measurement.
1880 input_latency.set_value (0);
1881 output_latency.set_value (0);
1883 push_state_to_backend (false);
1887 input_latency.set_value (il);
1888 output_latency.set_value (ol);
1891 // This should be done in push_state_to_backend()
1892 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1893 disable_latency_tab ();
1896 enable_latency_tab ();
1900 end_latency_detection ();
1901 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1906 /* latency measurement */
1909 EngineControl::check_audio_latency_measurement ()
1911 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1913 if (mtdm->resolve () < 0) {
1914 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1918 if (mtdm->err () > 0.3) {
1924 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1926 if (sample_rate == 0) {
1927 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1928 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1932 int frames_total = mtdm->del();
1933 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1935 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1936 _("Detected roundtrip latency: "),
1937 frames_total, frames_total * 1000.0f/sample_rate,
1938 _("Systemic latency: "),
1939 extra, extra * 1000.0f/sample_rate);
1943 if (mtdm->err () > 0.2) {
1945 strcat (buf, _("(signal detection error)"));
1951 strcat (buf, _("(inverted - bad wiring)"));
1956 have_lm_results = true;
1957 end_latency_detection ();
1958 lm_use_button.set_sensitive (true);
1962 lm_results.set_markup (string_compose (results_markup, buf));
1968 EngineControl::check_midi_latency_measurement ()
1970 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1972 if (!mididm->have_signal () || mididm->latency () == 0) {
1973 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1978 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1980 if (sample_rate == 0) {
1981 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1982 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1986 ARDOUR::framecnt_t frames_total = mididm->latency();
1987 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1988 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1989 _("Detected roundtrip latency: "),
1990 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1991 _("Systemic latency: "),
1992 extra, extra * 1000.0f / sample_rate);
1996 if (!mididm->ok ()) {
1998 strcat (buf, _("(averaging)"));
2002 if (mididm->deviation () > 50.0) {
2004 strcat (buf, _("(too large jitter)"));
2006 } else if (mididm->deviation () > 10.0) {
2008 strcat (buf, _("(large jitter)"));
2012 have_lm_results = true;
2013 end_latency_detection ();
2014 lm_use_button.set_sensitive (true);
2016 } else if (mididm->processed () > 400) {
2017 have_lm_results = false;
2018 end_latency_detection ();
2019 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2023 lm_results.set_markup (string_compose (results_markup, buf));
2029 EngineControl::start_latency_detection ()
2031 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2032 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2034 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2035 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2036 if (_measure_midi) {
2037 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2039 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2041 lm_measure_label.set_text (_("Cancel"));
2042 have_lm_results = false;
2043 lm_use_button.set_sensitive (false);
2044 lm_input_channel_combo.set_sensitive (false);
2045 lm_output_channel_combo.set_sensitive (false);
2051 EngineControl::end_latency_detection ()
2053 latency_timeout.disconnect ();
2054 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2055 lm_measure_label.set_text (_("Measure"));
2056 if (!have_lm_results) {
2057 lm_use_button.set_sensitive (false);
2059 lm_input_channel_combo.set_sensitive (true);
2060 lm_output_channel_combo.set_sensitive (true);
2065 EngineControl::latency_button_clicked ()
2068 start_latency_detection ();
2070 end_latency_detection ();
2075 EngineControl::use_latency_button_clicked ()
2077 if (_measure_midi) {
2078 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2082 ARDOUR::framecnt_t frames_total = mididm->latency();
2083 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2084 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2085 _measure_midi->input_latency = one_way;
2086 _measure_midi->output_latency = one_way;
2087 notebook.set_current_page (midi_tab);
2089 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2095 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2096 one_way = std::max (0., one_way);
2098 input_latency_adjustment.set_value (one_way);
2099 output_latency_adjustment.set_value (one_way);
2101 /* back to settings page */
2102 notebook.set_current_page (0);
2108 EngineControl::on_delete_event (GdkEventAny* ev)
2110 if (notebook.get_current_page() == 2) {
2111 /* currently on latency tab - be sure to clean up */
2112 end_latency_detection ();
2114 return ArdourDialog::on_delete_event (ev);
2118 EngineControl::engine_running ()
2120 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2123 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2124 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2126 buffer_size_combo.set_sensitive (true);
2127 sample_rate_combo.set_sensitive (true);
2129 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2130 connect_disconnect_button.show();
2132 started_at_least_once = true;
2136 EngineControl::engine_stopped ()
2138 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2141 buffer_size_combo.set_sensitive (false);
2142 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2143 connect_disconnect_button.show();
2145 sample_rate_combo.set_sensitive (true);
2146 buffer_size_combo.set_sensitive (true);
2150 EngineControl::connect_disconnect_click()
2152 if (ARDOUR::AudioEngine::instance()->running()) {
2153 ARDOUR_UI::instance()->disconnect_from_engine ();
2155 ARDOUR_UI::instance()->reconnect_to_engine ();
2160 EngineControl::calibrate_audio_latency ()
2162 _measure_midi.reset ();
2163 have_lm_results = false;
2164 lm_use_button.set_sensitive (false);
2165 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2166 notebook.set_current_page (latency_tab);
2170 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2173 have_lm_results = false;
2174 lm_use_button.set_sensitive (false);
2175 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2176 notebook.set_current_page (latency_tab);
2180 EngineControl::configure_midi_devices ()
2182 notebook.set_current_page (midi_tab);