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 ();
308 ok_button->grab_focus();
312 EngineControl::on_response (int response_id)
314 ArdourDialog::on_response (response_id);
316 switch (response_id) {
318 push_state_to_backend (true);
321 push_state_to_backend (true);
324 case RESPONSE_DELETE_EVENT:
327 ev.type = GDK_BUTTON_PRESS;
329 on_delete_event ((GdkEventAny*) &ev);
338 EngineControl::build_notebook ()
341 AttachOptions xopt = AttachOptions (FILL|EXPAND);
343 /* clear the table */
345 Gtkmm2ext::container_clear (basic_vbox);
346 Gtkmm2ext::container_clear (basic_packer);
348 if (control_app_button.get_parent()) {
349 control_app_button.get_parent()->remove (control_app_button);
352 label = manage (left_aligned_label (_("Audio System:")));
353 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
354 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
356 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
357 lm_button_audio.set_name ("generic button");
358 lm_button_audio.set_can_focus(true);
361 build_full_control_notebook ();
363 build_no_control_notebook ();
366 basic_vbox.pack_start (basic_hbox, false, false);
369 Gtk::HBox* hpacker = manage (new HBox);
370 hpacker->set_border_width (12);
371 hpacker->pack_start (control_app_button, false, false);
373 control_app_button.show();
374 basic_vbox.pack_start (*hpacker);
378 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
379 basic_vbox.show_all ();
384 EngineControl::build_full_control_notebook ()
386 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
389 using namespace Notebook_Helpers;
391 vector<string> strings;
392 AttachOptions xopt = AttachOptions (FILL|EXPAND);
393 int row = 1; // row zero == backend combo
395 /* start packing it up */
397 if (backend->requires_driver_selection()) {
398 label = manage (left_aligned_label (_("Driver:")));
399 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
400 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
404 label = manage (left_aligned_label (_("Device:")));
405 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
406 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
409 label = manage (left_aligned_label (_("Sample rate:")));
410 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
411 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
415 label = manage (left_aligned_label (_("Buffer size:")));
416 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
417 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
418 buffer_size_duration_label.set_alignment (0.0); /* left-align */
419 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
422 input_channels.set_name ("InputChannels");
423 input_channels.set_flags (Gtk::CAN_FOCUS);
424 input_channels.set_digits (0);
425 input_channels.set_wrap (false);
426 output_channels.set_editable (true);
428 label = manage (left_aligned_label (_("Input Channels:")));
429 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
430 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
433 output_channels.set_name ("OutputChannels");
434 output_channels.set_flags (Gtk::CAN_FOCUS);
435 output_channels.set_digits (0);
436 output_channels.set_wrap (false);
437 output_channels.set_editable (true);
439 label = manage (left_aligned_label (_("Output Channels:")));
440 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
441 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
444 input_latency.set_name ("InputLatency");
445 input_latency.set_flags (Gtk::CAN_FOCUS);
446 input_latency.set_digits (0);
447 input_latency.set_wrap (false);
448 input_latency.set_editable (true);
450 label = manage (left_aligned_label (_("Hardware input latency:")));
451 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
452 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
453 label = manage (left_aligned_label (_("samples")));
454 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
457 output_latency.set_name ("OutputLatency");
458 output_latency.set_flags (Gtk::CAN_FOCUS);
459 output_latency.set_digits (0);
460 output_latency.set_wrap (false);
461 output_latency.set_editable (true);
463 label = manage (left_aligned_label (_("Hardware output latency:")));
464 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
465 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
466 label = manage (left_aligned_label (_("samples")));
467 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
469 /* button spans 2 rows */
471 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
474 label = manage (left_aligned_label (_("MIDI System")));
475 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
476 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
477 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
482 EngineControl::build_no_control_notebook ()
484 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
487 using namespace Notebook_Helpers;
489 vector<string> strings;
490 AttachOptions xopt = AttachOptions (FILL|EXPAND);
491 int row = 1; // row zero == backend combo
492 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
494 label = manage (new Label);
495 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
496 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
499 if (backend->can_change_sample_rate_when_running()) {
500 label = manage (left_aligned_label (_("Sample rate:")));
501 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
502 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
506 if (backend->can_change_buffer_size_when_running()) {
507 label = manage (left_aligned_label (_("Buffer size:")));
508 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
509 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
510 buffer_size_duration_label.set_alignment (0.0); /* left-align */
511 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
515 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
517 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
521 EngineControl::~EngineControl ()
523 ignore_changes = true;
527 EngineControl::disable_latency_tab ()
529 vector<string> empty;
530 set_popdown_strings (lm_output_channel_combo, empty);
531 set_popdown_strings (lm_input_channel_combo, empty);
532 lm_measure_button.set_sensitive (false);
533 lm_use_button.set_sensitive (false);
537 EngineControl::enable_latency_tab ()
539 vector<string> outputs;
540 vector<string> inputs;
542 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
543 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
544 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
546 if (!ARDOUR::AudioEngine::instance()->running()) {
547 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
548 notebook.set_current_page (0);
552 else if (inputs.empty() || outputs.empty()) {
553 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
554 notebook.set_current_page (0);
559 lm_back_button_signal.disconnect();
561 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
564 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
568 set_popdown_strings (lm_output_channel_combo, outputs);
569 lm_output_channel_combo.set_active_text (outputs.front());
570 lm_output_channel_combo.set_sensitive (true);
572 set_popdown_strings (lm_input_channel_combo, inputs);
573 lm_input_channel_combo.set_active_text (inputs.front());
574 lm_input_channel_combo.set_sensitive (true);
576 lm_measure_button.set_sensitive (true);
580 EngineControl::setup_midi_tab_for_backend ()
582 string backend = backend_combo.get_active_text ();
584 Gtkmm2ext::container_clear (midi_vbox);
586 midi_vbox.set_border_width (12);
587 midi_device_table.set_border_width (12);
589 if (backend == "JACK") {
590 setup_midi_tab_for_jack ();
593 midi_vbox.pack_start (midi_device_table, true, true);
594 midi_vbox.pack_start (midi_back_button, false, false);
595 midi_vbox.show_all ();
599 EngineControl::setup_midi_tab_for_jack ()
604 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
606 device->input_latency = a->get_value();
608 device->output_latency = a->get_value();
613 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
614 b->set_active (!b->get_active());
615 device->enabled = b->get_active();
616 refresh_midi_display(device->name);
620 EngineControl::refresh_midi_display (std::string focus)
622 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
626 AttachOptions xopt = AttachOptions (FILL|EXPAND);
629 Gtkmm2ext::container_clear (midi_device_table);
631 midi_device_table.set_spacings (6);
633 l = manage (new Label);
634 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
635 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
636 l->set_alignment (0.5, 0.5);
640 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
641 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
642 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
643 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
645 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
646 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
647 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
648 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
651 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
656 bool enabled = (*p)->enabled;
658 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
659 m->set_name ("midi device");
660 m->set_can_focus (Gtk::CAN_FOCUS);
661 m->add_events (Gdk::BUTTON_RELEASE_MASK);
662 m->set_active (enabled);
663 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
664 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
665 if ((*p)->name == focus) {
669 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
670 s = manage (new Gtk::SpinButton (*a));
671 a->set_value ((*p)->input_latency);
672 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
673 s->set_sensitive (_can_set_midi_latencies && enabled);
674 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
676 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
677 s = manage (new Gtk::SpinButton (*a));
678 a->set_value ((*p)->output_latency);
679 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
680 s->set_sensitive (_can_set_midi_latencies && enabled);
681 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
683 b = manage (new Button (_("Calibrate")));
684 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
685 b->set_sensitive (_can_set_midi_latencies && enabled);
686 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
693 EngineControl::update_sensitivity ()
698 EngineControl::backend_changed ()
700 string backend_name = backend_combo.get_active_text();
701 boost::shared_ptr<ARDOUR::AudioBackend> backend;
703 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
704 /* eh? setting the backend failed... how ? */
708 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
711 setup_midi_tab_for_backend ();
712 _midi_devices.clear();
714 if (backend->requires_driver_selection()) {
715 vector<string> drivers = backend->enumerate_drivers();
716 driver_combo.set_sensitive (true);
718 if (!drivers.empty()) {
720 string current_driver;
721 current_driver = backend->driver_name ();
723 // driver might not have been set yet
724 if (current_driver == "") {
725 current_driver = driver_combo.get_active_text ();
726 if (current_driver == "")
727 // driver has never been set, make sure it's not blank
728 current_driver = drivers.front ();
731 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
732 set_popdown_strings (driver_combo, drivers);
733 driver_combo.set_active_text (current_driver);
740 driver_combo.set_sensitive (false);
741 /* this will change the device text which will cause a call to
742 * device changed which will set up parameters
747 vector<string> midi_options = backend->enumerate_midi_options();
749 if (midi_options.size() == 1) {
750 /* only contains the "none" option */
751 midi_option_combo.set_sensitive (false);
754 set_popdown_strings (midi_option_combo, midi_options);
755 midi_option_combo.set_active_text (midi_options.front());
756 midi_option_combo.set_sensitive (true);
758 midi_option_combo.set_sensitive (false);
762 midi_option_changed();
764 started_at_least_once = false;
766 if (!ignore_changes) {
767 maybe_display_saved_state ();
772 EngineControl::print_channel_count (Gtk::SpinButton* sb)
774 uint32_t cnt = (uint32_t) sb->get_value();
776 sb->set_text (_("all available channels"));
779 snprintf (buf, sizeof (buf), "%d", cnt);
786 EngineControl::list_devices ()
788 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
791 /* now fill out devices, mark sample rates, buffer sizes insensitive */
793 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
795 /* NOTE: Ardour currently does not display the "available" field of the
798 * Doing so would require a different GUI widget than the combo
799 * box/popdown that we currently use, since it has no way to list
800 * items that are not selectable. Something more like a popup menu,
801 * which could have unselectable items, would be appropriate.
804 vector<string> available_devices;
806 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
807 available_devices.push_back (i->name);
810 if (!available_devices.empty()) {
812 update_sensitivity ();
815 string current_device;
816 current_device = backend->device_name ();
817 if (current_device == "") {
818 // device might not have been set yet
819 current_device = device_combo.get_active_text ();
820 if (current_device == "")
821 // device has never been set, make sure it's not blank
822 current_device = available_devices.front ();
825 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
826 set_popdown_strings (device_combo, available_devices);
828 device_combo.set_active_text (current_device);
833 input_latency.set_sensitive (true);
834 output_latency.set_sensitive (true);
835 input_channels.set_sensitive (true);
836 output_channels.set_sensitive (true);
838 ok_button->set_sensitive (true);
839 apply_button->set_sensitive (true);
842 device_combo.clear();
843 sample_rate_combo.set_sensitive (false);
844 buffer_size_combo.set_sensitive (false);
845 input_latency.set_sensitive (false);
846 output_latency.set_sensitive (false);
847 input_channels.set_sensitive (false);
848 output_channels.set_sensitive (false);
850 ok_button->set_sensitive (false);
851 apply_button->set_sensitive (false);
853 ok_button->set_sensitive (true);
854 apply_button->set_sensitive (true);
855 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
856 sample_rate_combo.set_sensitive (true);
858 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
859 buffer_size_combo.set_sensitive (true);
867 EngineControl::driver_changed ()
869 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
872 backend->set_driver (driver_combo.get_active_text());
875 if (!ignore_changes) {
876 maybe_display_saved_state ();
881 EngineControl::device_changed ()
884 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
886 string device_name = device_combo.get_active_text ();
890 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
892 /* don't allow programmatic change to combos to cause a
893 recursive call to this method.
903 sr = backend->available_sample_rates (device_name);
906 sr.push_back (8000.0f);
907 sr.push_back (16000.0f);
908 sr.push_back (32000.0f);
909 sr.push_back (44100.0f);
910 sr.push_back (48000.0f);
911 sr.push_back (88200.0f);
912 sr.push_back (96000.0f);
913 sr.push_back (192000.0f);
914 sr.push_back (384000.0f);
917 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
918 s.push_back (rate_as_string (*x));
919 if (*x == _desired_sample_rate) {
925 sample_rate_combo.set_sensitive (true);
926 set_popdown_strings (sample_rate_combo, s);
928 if (desired.empty()) {
929 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
931 sample_rate_combo.set_active_text (desired);
935 sample_rate_combo.set_sensitive (false);
943 bs = backend->available_buffer_sizes (device_name);
944 } else if (backend->can_change_buffer_size_when_running()) {
958 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
959 s.push_back (bufsize_as_string (*x));
963 buffer_size_combo.set_sensitive (true);
964 set_popdown_strings (buffer_size_combo, s);
966 buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size(device_name)));
967 show_buffer_duration ();
969 buffer_size_combo.set_sensitive (false);
972 /* XXX theoretically need to set min + max channel counts here
975 manage_control_app_sensitivity ();
978 /* pick up any saved state for this device */
980 if (!ignore_changes) {
981 maybe_display_saved_state ();
986 EngineControl::bufsize_as_string (uint32_t sz)
988 /* Translators: "samples" is always plural here, so no
989 need for plural+singular forms.
992 snprintf (buf, sizeof (buf), _("%u samples"), sz);
997 EngineControl::sample_rate_changed ()
999 /* reset the strings for buffer size to show the correct msec value
1000 (reflecting the new sample rate).
1003 show_buffer_duration ();
1004 if (!ignore_changes) {
1011 EngineControl::buffer_size_changed ()
1013 show_buffer_duration ();
1014 if (!ignore_changes) {
1020 EngineControl::show_buffer_duration ()
1023 /* buffer sizes - convert from just samples to samples + msecs for
1024 * the displayed string
1027 string bs_text = buffer_size_combo.get_active_text ();
1028 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1029 uint32_t rate = get_rate();
1031 /* Translators: "msecs" is ALWAYS plural here, so we do not
1032 need singular form as well.
1034 /* Developers: note the hard-coding of a double buffered model
1035 in the (2 * samples) computation of latency. we always start
1036 the audiobackend in this configuration.
1039 snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
1040 buffer_size_duration_label.set_text (buf);
1044 EngineControl::midi_option_changed ()
1046 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1049 backend->set_midi_option (get_midi_option());
1051 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1053 //_midi_devices.clear(); // TODO merge with state-saved settings..
1054 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1055 std::vector<MidiDeviceSettings> new_devices;
1057 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1058 MidiDeviceSettings mds = find_midi_device (i->name);
1059 if (i->available && !mds) {
1060 uint32_t input_latency = 0;
1061 uint32_t output_latency = 0;
1062 if (_can_set_midi_latencies) {
1063 input_latency = backend->systemic_midi_input_latency (i->name);
1064 output_latency = backend->systemic_midi_output_latency (i->name);
1066 bool enabled = backend->midi_device_enabled (i->name);
1067 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1068 new_devices.push_back (ptr);
1069 } else if (i->available) {
1070 new_devices.push_back (mds);
1073 _midi_devices = new_devices;
1075 if (_midi_devices.empty()) {
1076 midi_devices_button.set_sensitive (false);
1078 midi_devices_button.set_sensitive (true);
1081 if (!ignore_changes) {
1087 EngineControl::parameter_changed ()
1089 if (!ignore_changes) {
1094 EngineControl::State
1095 EngineControl::get_matching_state (
1096 const string& backend,
1097 const string& driver,
1098 const string& device)
1100 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1101 if ((*i)->backend == backend &&
1102 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1110 EngineControl::State
1111 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1113 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1116 return get_matching_state (backend_combo.get_active_text(),
1117 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1118 device_combo.get_active_text());
1122 return get_matching_state (backend_combo.get_active_text(),
1124 device_combo.get_active_text());
1127 EngineControl::State
1128 EngineControl::save_state ()
1132 if (!_have_control) {
1133 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1137 state.reset(new StateStruct);
1138 state->backend = get_backend ();
1140 state.reset(new StateStruct);
1141 store_state (state);
1144 for (StateList::iterator i = states.begin(); i != states.end();) {
1145 if ((*i)->backend == state->backend &&
1146 (*i)->driver == state->driver &&
1147 (*i)->device == state->device) {
1148 i = states.erase(i);
1154 states.push_back (state);
1160 EngineControl::store_state (State state)
1162 state->backend = get_backend ();
1163 state->driver = get_driver ();
1164 state->device = get_device_name ();
1165 state->sample_rate = get_rate ();
1166 state->buffer_size = get_buffer_size ();
1167 state->input_latency = get_input_latency ();
1168 state->output_latency = get_output_latency ();
1169 state->input_channels = get_input_channels ();
1170 state->output_channels = get_output_channels ();
1171 state->midi_option = get_midi_option ();
1172 state->midi_devices = _midi_devices;
1176 EngineControl::maybe_display_saved_state ()
1178 if (!_have_control) {
1182 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1185 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1187 if (!_desired_sample_rate) {
1188 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1190 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1191 /* call this explicitly because we're ignoring changes to
1192 the controls at this point.
1194 show_buffer_duration ();
1195 input_latency.set_value (state->input_latency);
1196 output_latency.set_value (state->output_latency);
1198 if (!state->midi_option.empty()) {
1199 midi_option_combo.set_active_text (state->midi_option);
1200 _midi_devices = state->midi_devices;
1206 EngineControl::get_state ()
1208 XMLNode* root = new XMLNode ("AudioMIDISetup");
1211 if (!states.empty()) {
1212 XMLNode* state_nodes = new XMLNode ("EngineStates");
1214 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1216 XMLNode* node = new XMLNode ("State");
1218 node->add_property ("backend", (*i)->backend);
1219 node->add_property ("driver", (*i)->driver);
1220 node->add_property ("device", (*i)->device);
1221 node->add_property ("sample-rate", (*i)->sample_rate);
1222 node->add_property ("buffer-size", (*i)->buffer_size);
1223 node->add_property ("input-latency", (*i)->input_latency);
1224 node->add_property ("output-latency", (*i)->output_latency);
1225 node->add_property ("input-channels", (*i)->input_channels);
1226 node->add_property ("output-channels", (*i)->output_channels);
1227 node->add_property ("active", (*i)->active ? "yes" : "no");
1228 node->add_property ("midi-option", (*i)->midi_option);
1230 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1231 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1232 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1233 midi_device_stuff->add_property (X_("name"), (*p)->name);
1234 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1235 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1236 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1237 midi_devices->add_child_nocopy (*midi_device_stuff);
1239 node->add_child_nocopy (*midi_devices);
1241 state_nodes->add_child_nocopy (*node);
1244 root->add_child_nocopy (*state_nodes);
1251 EngineControl::set_state (const XMLNode& root)
1253 XMLNodeList clist, cclist;
1254 XMLNodeConstIterator citer, cciter;
1256 XMLNode* grandchild;
1257 XMLProperty* prop = NULL;
1259 if (root.name() != "AudioMIDISetup") {
1263 clist = root.children();
1267 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1271 if (child->name() != "EngineStates") {
1275 cclist = child->children();
1277 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1278 State state (new StateStruct);
1280 grandchild = *cciter;
1282 if (grandchild->name() != "State") {
1286 if ((prop = grandchild->property ("backend")) == 0) {
1289 state->backend = prop->value ();
1291 if ((prop = grandchild->property ("driver")) == 0) {
1294 state->driver = prop->value ();
1296 if ((prop = grandchild->property ("device")) == 0) {
1299 state->device = prop->value ();
1301 if ((prop = grandchild->property ("sample-rate")) == 0) {
1304 state->sample_rate = atof (prop->value ());
1306 if ((prop = grandchild->property ("buffer-size")) == 0) {
1309 state->buffer_size = atoi (prop->value ());
1311 if ((prop = grandchild->property ("input-latency")) == 0) {
1314 state->input_latency = atoi (prop->value ());
1316 if ((prop = grandchild->property ("output-latency")) == 0) {
1319 state->output_latency = atoi (prop->value ());
1321 if ((prop = grandchild->property ("input-channels")) == 0) {
1324 state->input_channels = atoi (prop->value ());
1326 if ((prop = grandchild->property ("output-channels")) == 0) {
1329 state->output_channels = atoi (prop->value ());
1331 if ((prop = grandchild->property ("active")) == 0) {
1334 state->active = string_is_affirmative (prop->value ());
1336 if ((prop = grandchild->property ("midi-option")) == 0) {
1339 state->midi_option = prop->value ();
1341 state->midi_devices.clear();
1343 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1344 const XMLNodeList mnc = midinode->children();
1345 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1346 if ((*n)->property (X_("name")) == 0
1347 || (*n)->property (X_("enabled")) == 0
1348 || (*n)->property (X_("input-latency")) == 0
1349 || (*n)->property (X_("output-latency")) == 0
1354 MidiDeviceSettings ptr (new MidiDeviceSetting(
1355 (*n)->property (X_("name"))->value (),
1356 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1357 atoi ((*n)->property (X_("input-latency"))->value ()),
1358 atoi ((*n)->property (X_("output-latency"))->value ())
1360 state->midi_devices.push_back (ptr);
1365 /* remove accumulated duplicates (due to bug in ealier version)
1366 * this can be removed again before release
1368 for (StateList::iterator i = states.begin(); i != states.end();) {
1369 if ((*i)->backend == state->backend &&
1370 (*i)->driver == state->driver &&
1371 (*i)->device == state->device) {
1372 i = states.erase(i);
1379 states.push_back (state);
1383 /* now see if there was an active state and switch the setup to it */
1385 // purge states of backend that are not available in this built
1386 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1387 vector<std::string> backend_names;
1389 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1390 backend_names.push_back((*i)->name);
1392 for (StateList::iterator i = states.begin(); i != states.end();) {
1393 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1394 i = states.erase(i);
1400 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1404 backend_combo.set_active_text ((*i)->backend);
1405 driver_combo.set_active_text ((*i)->driver);
1406 device_combo.set_active_text ((*i)->device);
1407 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1408 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1409 input_latency.set_value ((*i)->input_latency);
1410 output_latency.set_value ((*i)->output_latency);
1411 midi_option_combo.set_active_text ((*i)->midi_option);
1419 EngineControl::push_state_to_backend (bool start)
1421 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1427 /* figure out what is going to change */
1429 bool restart_required = false;
1430 bool was_running = ARDOUR::AudioEngine::instance()->running();
1431 bool change_driver = false;
1432 bool change_device = false;
1433 bool change_rate = false;
1434 bool change_bufsize = false;
1435 bool change_latency = false;
1436 bool change_channels = false;
1437 bool change_midi = false;
1439 uint32_t ochan = get_output_channels ();
1440 uint32_t ichan = get_input_channels ();
1442 if (_have_control) {
1444 if (started_at_least_once) {
1446 /* we can control the backend */
1448 if (backend->requires_driver_selection()) {
1449 if (get_driver() != backend->driver_name()) {
1450 change_driver = true;
1454 if (get_device_name() != backend->device_name()) {
1455 change_device = true;
1458 if (get_rate() != backend->sample_rate()) {
1462 if (get_buffer_size() != backend->buffer_size()) {
1463 change_bufsize = true;
1466 if (get_midi_option() != backend->midi_option()) {
1470 /* zero-requested channels means "all available" */
1473 ichan = backend->input_channels();
1477 ochan = backend->output_channels();
1480 if (ichan != backend->input_channels()) {
1481 change_channels = true;
1484 if (ochan != backend->output_channels()) {
1485 change_channels = true;
1488 if (get_input_latency() != backend->systemic_input_latency() ||
1489 get_output_latency() != backend->systemic_output_latency()) {
1490 change_latency = true;
1493 /* backend never started, so we have to force a group
1496 change_device = true;
1497 if (backend->requires_driver_selection()) {
1498 change_driver = true;
1501 change_bufsize = true;
1502 change_channels = true;
1503 change_latency = true;
1509 /* we have no control over the backend, meaning that we can
1510 * only possibly change sample rate and buffer size.
1514 if (get_rate() != backend->sample_rate()) {
1515 change_bufsize = true;
1518 if (get_buffer_size() != backend->buffer_size()) {
1519 change_bufsize = true;
1523 if (!_have_control) {
1525 /* We do not have control over the backend, so the best we can
1526 * do is try to change the sample rate and/or bufsize and get
1530 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1534 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1539 backend->set_sample_rate (get_rate());
1542 if (change_bufsize) {
1543 backend->set_buffer_size (get_buffer_size());
1547 if (ARDOUR::AudioEngine::instance()->start ()) {
1548 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1558 /* determine if we need to stop the backend before changing parameters */
1560 if (change_driver || change_device || change_channels || change_latency ||
1561 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1563 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1564 restart_required = true;
1566 restart_required = false;
1571 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1572 /* no changes in any parameters that absolutely require a
1573 * restart, so check those that might be changeable without a
1577 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1578 /* can't do this while running ... */
1579 restart_required = true;
1582 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1583 /* can't do this while running ... */
1584 restart_required = true;
1590 if (restart_required) {
1591 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1598 if (change_driver && backend->set_driver (get_driver())) {
1599 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1602 if (change_device && backend->set_device_name (get_device_name())) {
1603 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1606 if (change_rate && backend->set_sample_rate (get_rate())) {
1607 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1610 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1611 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1615 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1616 if (backend->set_input_channels (get_input_channels())) {
1617 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1620 if (backend->set_output_channels (get_output_channels())) {
1621 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1625 if (change_latency) {
1626 if (backend->set_systemic_input_latency (get_input_latency())) {
1627 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1630 if (backend->set_systemic_output_latency (get_output_latency())) {
1631 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1637 backend->set_midi_option (get_midi_option());
1641 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1642 if (_measure_midi) {
1643 if (*p == _measure_midi) {
1644 backend->set_midi_device_enabled ((*p)->name, true);
1646 backend->set_midi_device_enabled ((*p)->name, false);
1650 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1651 if (backend->can_set_systemic_midi_latencies()) {
1652 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1653 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1658 if (start || (was_running && restart_required)) {
1659 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1670 EngineControl::post_push ()
1672 /* get a pointer to the current state object, creating one if
1676 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1679 state = save_state ();
1685 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1686 (*i)->active = false;
1689 /* mark this one active (to be used next time the dialog is
1693 state->active = true;
1695 if (_have_control) { // XXX
1696 manage_control_app_sensitivity ();
1699 /* schedule a redisplay of MIDI ports */
1700 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1705 EngineControl::get_rate () const
1707 float r = atof (sample_rate_combo.get_active_text ());
1708 /* the string may have been translated with an abbreviation for
1709 * thousands, so use a crude heuristic to fix this.
1719 EngineControl::get_buffer_size () const
1721 string txt = buffer_size_combo.get_active_text ();
1724 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1732 EngineControl::get_midi_option () const
1734 return midi_option_combo.get_active_text();
1738 EngineControl::get_input_channels() const
1740 return (uint32_t) input_channels_adjustment.get_value();
1744 EngineControl::get_output_channels() const
1746 return (uint32_t) output_channels_adjustment.get_value();
1750 EngineControl::get_input_latency() const
1752 return (uint32_t) input_latency_adjustment.get_value();
1756 EngineControl::get_output_latency() const
1758 return (uint32_t) output_latency_adjustment.get_value();
1762 EngineControl::get_backend () const
1764 return backend_combo.get_active_text ();
1768 EngineControl::get_driver () const
1770 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1771 return driver_combo.get_active_text ();
1778 EngineControl::get_device_name () const
1780 return device_combo.get_active_text ();
1784 EngineControl::control_app_button_clicked ()
1786 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1792 backend->launch_control_app ();
1796 EngineControl::manage_control_app_sensitivity ()
1798 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1804 string appname = backend->control_app_name();
1806 if (appname.empty()) {
1807 control_app_button.set_sensitive (false);
1809 control_app_button.set_sensitive (true);
1814 EngineControl::set_desired_sample_rate (uint32_t sr)
1816 _desired_sample_rate = sr;
1821 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1823 if (page_num == 0) {
1824 cancel_button->set_sensitive (true);
1825 ok_button->set_sensitive (true);
1826 apply_button->set_sensitive (true);
1827 _measure_midi.reset();
1829 cancel_button->set_sensitive (false);
1830 ok_button->set_sensitive (false);
1831 apply_button->set_sensitive (false);
1834 if (page_num == midi_tab) {
1836 refresh_midi_display ();
1839 if (page_num == latency_tab) {
1842 if (ARDOUR::AudioEngine::instance()->running()) {
1843 // TODO - mark as 'stopped for latency
1844 ARDOUR_UI::instance()->disconnect_from_engine ();
1848 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1850 /* save any existing latency values */
1852 uint32_t il = (uint32_t) input_latency.get_value ();
1853 uint32_t ol = (uint32_t) input_latency.get_value ();
1855 /* reset to zero so that our new test instance
1856 will be clean of any existing latency measures.
1858 NB. this should really be done by the backend
1859 when stated for latency measurement.
1862 input_latency.set_value (0);
1863 output_latency.set_value (0);
1865 push_state_to_backend (false);
1869 input_latency.set_value (il);
1870 output_latency.set_value (ol);
1873 // This should be done in push_state_to_backend()
1874 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1875 disable_latency_tab ();
1878 enable_latency_tab ();
1882 end_latency_detection ();
1883 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1888 /* latency measurement */
1891 EngineControl::check_audio_latency_measurement ()
1893 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1895 if (mtdm->resolve () < 0) {
1896 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1900 if (mtdm->err () > 0.3) {
1906 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1908 if (sample_rate == 0) {
1909 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1910 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1914 int frames_total = mtdm->del();
1915 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1917 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1918 _("Detected roundtrip latency: "),
1919 frames_total, frames_total * 1000.0f/sample_rate,
1920 _("Systemic latency: "),
1921 extra, extra * 1000.0f/sample_rate);
1925 if (mtdm->err () > 0.2) {
1927 strcat (buf, _("(signal detection error)"));
1933 strcat (buf, _("(inverted - bad wiring)"));
1938 have_lm_results = true;
1939 end_latency_detection ();
1940 lm_use_button.set_sensitive (true);
1944 lm_results.set_markup (string_compose (results_markup, buf));
1950 EngineControl::check_midi_latency_measurement ()
1952 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1954 if (!mididm->have_signal () || mididm->latency () == 0) {
1955 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1960 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1962 if (sample_rate == 0) {
1963 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1964 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1968 ARDOUR::framecnt_t frames_total = mididm->latency();
1969 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1970 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1971 _("Detected roundtrip latency: "),
1972 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1973 _("Systemic latency: "),
1974 extra, extra * 1000.0f / sample_rate);
1978 if (!mididm->ok ()) {
1980 strcat (buf, _("(averaging)"));
1984 if (mididm->deviation () > 50.0) {
1986 strcat (buf, _("(too large jitter)"));
1988 } else if (mididm->deviation () > 10.0) {
1990 strcat (buf, _("(large jitter)"));
1994 have_lm_results = true;
1995 end_latency_detection ();
1996 lm_use_button.set_sensitive (true);
1998 } else if (mididm->processed () > 400) {
1999 have_lm_results = false;
2000 end_latency_detection ();
2001 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2005 lm_results.set_markup (string_compose (results_markup, buf));
2011 EngineControl::start_latency_detection ()
2013 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2014 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2016 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2017 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2018 if (_measure_midi) {
2019 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2021 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2023 lm_measure_label.set_text (_("Cancel"));
2024 have_lm_results = false;
2025 lm_use_button.set_sensitive (false);
2026 lm_input_channel_combo.set_sensitive (false);
2027 lm_output_channel_combo.set_sensitive (false);
2033 EngineControl::end_latency_detection ()
2035 latency_timeout.disconnect ();
2036 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2037 lm_measure_label.set_text (_("Measure"));
2038 if (!have_lm_results) {
2039 lm_use_button.set_sensitive (false);
2041 lm_input_channel_combo.set_sensitive (true);
2042 lm_output_channel_combo.set_sensitive (true);
2047 EngineControl::latency_button_clicked ()
2050 start_latency_detection ();
2052 end_latency_detection ();
2057 EngineControl::use_latency_button_clicked ()
2059 if (_measure_midi) {
2060 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2064 ARDOUR::framecnt_t frames_total = mididm->latency();
2065 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2066 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2067 _measure_midi->input_latency = one_way;
2068 _measure_midi->output_latency = one_way;
2069 notebook.set_current_page (midi_tab);
2071 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2077 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2078 one_way = std::max (0., one_way);
2080 input_latency_adjustment.set_value (one_way);
2081 output_latency_adjustment.set_value (one_way);
2083 /* back to settings page */
2084 notebook.set_current_page (0);
2090 EngineControl::on_delete_event (GdkEventAny* ev)
2092 if (notebook.get_current_page() == 2) {
2093 /* currently on latency tab - be sure to clean up */
2094 end_latency_detection ();
2096 return ArdourDialog::on_delete_event (ev);
2100 EngineControl::engine_running ()
2102 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2105 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2106 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2108 buffer_size_combo.set_sensitive (true);
2109 sample_rate_combo.set_sensitive (true);
2111 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2113 started_at_least_once = true;
2117 EngineControl::engine_stopped ()
2119 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2122 buffer_size_combo.set_sensitive (false);
2123 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2125 sample_rate_combo.set_sensitive (true);
2126 buffer_size_combo.set_sensitive (true);
2130 EngineControl::connect_disconnect_click()
2132 if (ARDOUR::AudioEngine::instance()->running()) {
2133 ARDOUR_UI::instance()->disconnect_from_engine ();
2135 ARDOUR_UI::instance()->reconnect_to_engine ();
2140 EngineControl::calibrate_audio_latency ()
2142 _measure_midi.reset ();
2143 have_lm_results = false;
2144 lm_use_button.set_sensitive (false);
2145 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2146 notebook.set_current_page (latency_tab);
2150 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2153 have_lm_results = false;
2154 lm_use_button.set_sensitive (false);
2155 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2156 notebook.set_current_page (latency_tab);
2160 EngineControl::configure_midi_devices ()
2162 notebook.set_current_page (midi_tab);