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"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
51 #include "ardour_ui.h"
52 #include "engine_dialog.h"
53 #include "gui_thread.h"
59 using namespace Gtkmm2ext;
62 using namespace ARDOUR_UI_UTILS;
64 static const unsigned int midi_tab = 2;
65 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
67 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
69 EngineControl::EngineControl ()
70 : ArdourDialog (_("Audio/MIDI Setup"))
73 , input_latency_adjustment (0, 0, 99999, 1)
74 , input_latency (input_latency_adjustment)
75 , output_latency_adjustment (0, 0, 99999, 1)
76 , output_latency (output_latency_adjustment)
77 , input_channels_adjustment (0, 0, 256, 1)
78 , input_channels (input_channels_adjustment)
79 , output_channels_adjustment (0, 0, 256, 1)
80 , output_channels (output_channels_adjustment)
81 , ports_adjustment (128, 8, 1024, 1, 16)
82 , ports_spinner (ports_adjustment)
83 , control_app_button (_("Device Control Panel"))
84 , midi_devices_button (_("Midi Device Setup"))
85 , lm_measure_label (_("Measure"))
86 , lm_use_button (_("Use results"))
87 , lm_back_button (_("Back to settings ... (ignore results)"))
88 , lm_button_audio (_("Calibrate Audio"))
90 , have_lm_results (false)
92 , midi_back_button (_("Back to settings"))
94 , _desired_sample_rate (0)
95 , started_at_least_once (false)
97 using namespace Notebook_Helpers;
98 vector<string> strings;
100 AttachOptions xopt = AttachOptions (FILL|EXPAND);
103 set_name (X_("AudioMIDISetup"));
105 /* the backend combo is the one thing that is ALWAYS visible */
107 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
109 if (backends.empty()) {
110 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));
112 throw failed_constructor ();
115 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
116 strings.push_back ((*b)->name);
119 set_popdown_strings (backend_combo, strings);
120 backend_combo.set_active_text (strings.front());
121 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
123 /* setup basic packing characteristics for the table used on the main
124 * tab of the notebook
127 basic_packer.set_spacings (6);
128 basic_packer.set_border_width (12);
129 basic_packer.set_homogeneous (false);
133 basic_hbox.pack_start (basic_packer, false, false);
135 /* latency measurement tab */
137 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
140 lm_table.set_row_spacings (12);
141 lm_table.set_col_spacings (6);
142 lm_table.set_homogeneous (false);
144 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
147 lm_preamble.set_width_chars (60);
148 lm_preamble.set_line_wrap (true);
149 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
151 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
154 Gtk::Label* preamble;
155 preamble = manage (new Label);
156 preamble->set_width_chars (60);
157 preamble->set_line_wrap (true);
158 preamble->set_markup (_("Select two channels below and connect them using a cable."));
160 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
163 label = manage (new Label (_("Output channel")));
164 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
166 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
167 misc_align->add (lm_output_channel_combo);
168 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
171 label = manage (new Label (_("Input channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_input_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
179 xopt = AttachOptions(0);
181 lm_measure_label.set_padding (10, 10);
182 lm_measure_button.add (lm_measure_label);
183 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
184 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
185 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
187 lm_use_button.set_sensitive (false);
189 /* Increase the default spacing around the labels of these three
195 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
196 l->set_padding (10, 10);
199 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
200 l->set_padding (10, 10);
203 preamble = manage (new Label);
204 preamble->set_width_chars (60);
205 preamble->set_line_wrap (true);
206 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
207 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
210 preamble = manage (new Label);
211 preamble->set_width_chars (60);
212 preamble->set_line_wrap (true);
213 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
214 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
216 ++row; // skip a row in the table
217 ++row; // skip a row in the table
219 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
221 ++row; // skip a row in the table
222 ++row; // skip a row in the table
224 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
230 lm_vbox.set_border_width (12);
231 lm_vbox.pack_start (lm_table, false, false);
233 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
237 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
238 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
239 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
240 notebook.set_border_width (12);
242 notebook.set_show_tabs (false);
243 notebook.show_all ();
245 notebook.set_name ("SettingsNotebook");
247 /* packup the notebook */
249 get_vbox()->set_border_width (12);
250 get_vbox()->pack_start (notebook);
252 get_action_area()->pack_start (engine_status);
253 engine_status.show();
255 /* need a special function to print "all available channels" when the
256 * channel counts hit zero.
259 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
260 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
262 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
263 midi_devices_button.set_sensitive (false);
264 midi_devices_button.set_name ("generic button");
265 midi_devices_button.set_can_focus(true);
267 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
268 manage_control_app_sensitivity ();
270 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
271 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
272 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
274 /* Pick up any existing audio setup configuration, if appropriate */
276 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
278 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
279 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
280 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
284 set_state (*audio_setup);
287 /* ignore: don't save state */
288 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
292 /* Connect to signals */
294 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
295 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
296 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
297 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
298 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
300 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
301 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
302 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
303 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
305 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
307 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
308 connect_disconnect_button.set_no_show_all();
313 EngineControl::on_show ()
315 ArdourDialog::on_show ();
317 ok_button->grab_focus();
321 EngineControl::on_response (int response_id)
323 ArdourDialog::on_response (response_id);
325 switch (response_id) {
327 push_state_to_backend (true);
330 push_state_to_backend (true);
333 case RESPONSE_DELETE_EVENT:
336 ev.type = GDK_BUTTON_PRESS;
338 on_delete_event ((GdkEventAny*) &ev);
347 EngineControl::build_notebook ()
350 AttachOptions xopt = AttachOptions (FILL|EXPAND);
352 /* clear the table */
354 Gtkmm2ext::container_clear (basic_vbox);
355 Gtkmm2ext::container_clear (basic_packer);
357 if (control_app_button.get_parent()) {
358 control_app_button.get_parent()->remove (control_app_button);
361 label = manage (left_aligned_label (_("Audio System:")));
362 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
363 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
365 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
366 lm_button_audio.set_name ("generic button");
367 lm_button_audio.set_can_focus(true);
370 build_full_control_notebook ();
372 build_no_control_notebook ();
375 basic_vbox.pack_start (basic_hbox, false, false);
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);
421 /* button spans 2 rows */
423 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
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 if (!ARDOUR::Profile->get_mixbus()) {
433 label = manage (left_aligned_label (_("Input Channels:")));
434 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
435 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
439 output_channels.set_name ("OutputChannels");
440 output_channels.set_flags (Gtk::CAN_FOCUS);
441 output_channels.set_digits (0);
442 output_channels.set_wrap (false);
443 output_channels.set_editable (true);
445 if (!ARDOUR::Profile->get_mixbus()) {
446 label = manage (left_aligned_label (_("Output Channels:")));
447 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
448 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
452 input_latency.set_name ("InputLatency");
453 input_latency.set_flags (Gtk::CAN_FOCUS);
454 input_latency.set_digits (0);
455 input_latency.set_wrap (false);
456 input_latency.set_editable (true);
458 label = manage (left_aligned_label (_("Hardware input latency:")));
459 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
460 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
461 label = manage (left_aligned_label (_("samples")));
462 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
465 output_latency.set_name ("OutputLatency");
466 output_latency.set_flags (Gtk::CAN_FOCUS);
467 output_latency.set_digits (0);
468 output_latency.set_wrap (false);
469 output_latency.set_editable (true);
471 label = manage (left_aligned_label (_("Hardware output latency:")));
472 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
473 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
474 label = manage (left_aligned_label (_("samples")));
475 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
477 /* button spans 2 rows */
479 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
482 label = manage (left_aligned_label (_("MIDI System")));
483 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
484 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
485 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
490 EngineControl::build_no_control_notebook ()
492 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
495 using namespace Notebook_Helpers;
497 vector<string> strings;
498 AttachOptions xopt = AttachOptions (FILL|EXPAND);
499 int row = 1; // row zero == backend combo
500 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
502 label = manage (new Label);
503 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
504 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
507 if (backend->can_change_sample_rate_when_running()) {
508 label = manage (left_aligned_label (_("Sample rate:")));
509 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
510 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
514 if (backend->can_change_buffer_size_when_running()) {
515 label = manage (left_aligned_label (_("Buffer size:")));
516 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
517 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
518 buffer_size_duration_label.set_alignment (0.0); /* left-align */
519 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
523 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
527 EngineControl::~EngineControl ()
529 ignore_changes = true;
533 EngineControl::disable_latency_tab ()
535 vector<string> empty;
536 set_popdown_strings (lm_output_channel_combo, empty);
537 set_popdown_strings (lm_input_channel_combo, empty);
538 lm_measure_button.set_sensitive (false);
539 lm_use_button.set_sensitive (false);
543 EngineControl::enable_latency_tab ()
545 vector<string> outputs;
546 vector<string> inputs;
548 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
549 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
550 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
552 if (!ARDOUR::AudioEngine::instance()->running()) {
553 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
554 notebook.set_current_page (0);
558 else if (inputs.empty() || outputs.empty()) {
559 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
560 notebook.set_current_page (0);
565 lm_back_button_signal.disconnect();
567 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
570 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
574 set_popdown_strings (lm_output_channel_combo, outputs);
575 lm_output_channel_combo.set_active_text (outputs.front());
576 lm_output_channel_combo.set_sensitive (true);
578 set_popdown_strings (lm_input_channel_combo, inputs);
579 lm_input_channel_combo.set_active_text (inputs.front());
580 lm_input_channel_combo.set_sensitive (true);
582 lm_measure_button.set_sensitive (true);
586 EngineControl::setup_midi_tab_for_backend ()
588 string backend = backend_combo.get_active_text ();
590 Gtkmm2ext::container_clear (midi_vbox);
592 midi_vbox.set_border_width (12);
593 midi_device_table.set_border_width (12);
595 if (backend == "JACK") {
596 setup_midi_tab_for_jack ();
599 midi_vbox.pack_start (midi_device_table, true, true);
600 midi_vbox.pack_start (midi_back_button, false, false);
601 midi_vbox.show_all ();
605 EngineControl::setup_midi_tab_for_jack ()
610 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
612 device->input_latency = a->get_value();
614 device->output_latency = a->get_value();
619 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
620 b->set_active (!b->get_active());
621 device->enabled = b->get_active();
622 refresh_midi_display(device->name);
626 EngineControl::refresh_midi_display (std::string focus)
628 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
632 AttachOptions xopt = AttachOptions (FILL|EXPAND);
635 Gtkmm2ext::container_clear (midi_device_table);
637 midi_device_table.set_spacings (6);
639 l = manage (new Label);
640 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
641 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
642 l->set_alignment (0.5, 0.5);
646 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
647 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
648 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
649 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
651 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
652 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
653 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
654 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
657 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
662 bool enabled = (*p)->enabled;
664 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
665 m->set_name ("midi device");
666 m->set_can_focus (Gtk::CAN_FOCUS);
667 m->add_events (Gdk::BUTTON_RELEASE_MASK);
668 m->set_active (enabled);
669 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
670 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
671 if ((*p)->name == focus) {
675 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
676 s = manage (new Gtk::SpinButton (*a));
677 a->set_value ((*p)->input_latency);
678 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
679 s->set_sensitive (_can_set_midi_latencies && enabled);
680 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
682 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
683 s = manage (new Gtk::SpinButton (*a));
684 a->set_value ((*p)->output_latency);
685 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
686 s->set_sensitive (_can_set_midi_latencies && enabled);
687 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
689 b = manage (new Button (_("Calibrate")));
690 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
691 b->set_sensitive (_can_set_midi_latencies && enabled);
692 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
699 EngineControl::update_sensitivity ()
704 EngineControl::backend_changed ()
706 string backend_name = backend_combo.get_active_text();
707 boost::shared_ptr<ARDOUR::AudioBackend> backend;
709 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
710 /* eh? setting the backend failed... how ? */
714 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
717 setup_midi_tab_for_backend ();
718 _midi_devices.clear();
720 if (backend->requires_driver_selection()) {
721 vector<string> drivers = backend->enumerate_drivers();
722 driver_combo.set_sensitive (true);
724 if (!drivers.empty()) {
726 string current_driver;
727 current_driver = backend->driver_name ();
729 // driver might not have been set yet
730 if (current_driver == "") {
731 current_driver = driver_combo.get_active_text ();
732 if (current_driver == "")
733 // driver has never been set, make sure it's not blank
734 current_driver = drivers.front ();
737 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
738 set_popdown_strings (driver_combo, drivers);
739 driver_combo.set_active_text (current_driver);
746 driver_combo.set_sensitive (false);
747 /* this will change the device text which will cause a call to
748 * device changed which will set up parameters
753 vector<string> midi_options = backend->enumerate_midi_options();
755 if (midi_options.size() == 1) {
756 /* only contains the "none" option */
757 midi_option_combo.set_sensitive (false);
760 set_popdown_strings (midi_option_combo, midi_options);
761 midi_option_combo.set_active_text (midi_options.front());
762 midi_option_combo.set_sensitive (true);
764 midi_option_combo.set_sensitive (false);
768 connect_disconnect_button.hide();
770 midi_option_changed();
772 started_at_least_once = false;
774 if (!ignore_changes) {
775 maybe_display_saved_state ();
780 EngineControl::print_channel_count (Gtk::SpinButton* sb)
782 if (ARDOUR::Profile->get_mixbus()) {
783 cout << "Mixbus crash trap. sb->get_value(): " << sb->get_value();
787 uint32_t cnt = (uint32_t) sb->get_value();
789 sb->set_text (_("all available channels"));
792 snprintf (buf, sizeof (buf), "%d", cnt);
799 EngineControl::list_devices ()
801 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
804 /* now fill out devices, mark sample rates, buffer sizes insensitive */
806 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
808 /* NOTE: Ardour currently does not display the "available" field of the
811 * Doing so would require a different GUI widget than the combo
812 * box/popdown that we currently use, since it has no way to list
813 * items that are not selectable. Something more like a popup menu,
814 * which could have unselectable items, would be appropriate.
817 vector<string> available_devices;
819 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
820 available_devices.push_back (i->name);
823 if (!available_devices.empty()) {
825 update_sensitivity ();
828 string current_device;
829 current_device = backend->device_name ();
830 if (current_device == "") {
831 // device might not have been set yet
832 current_device = device_combo.get_active_text ();
833 if (current_device == "")
834 // device has never been set, make sure it's not blank
835 current_device = available_devices.front ();
838 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
839 set_popdown_strings (device_combo, available_devices);
841 device_combo.set_active_text (current_device);
846 input_latency.set_sensitive (true);
847 output_latency.set_sensitive (true);
848 input_channels.set_sensitive (true);
849 output_channels.set_sensitive (true);
851 ok_button->set_sensitive (true);
852 apply_button->set_sensitive (true);
855 device_combo.clear();
856 sample_rate_combo.set_sensitive (false);
857 buffer_size_combo.set_sensitive (false);
858 input_latency.set_sensitive (false);
859 output_latency.set_sensitive (false);
860 input_channels.set_sensitive (false);
861 output_channels.set_sensitive (false);
863 ok_button->set_sensitive (false);
864 apply_button->set_sensitive (false);
866 ok_button->set_sensitive (true);
867 apply_button->set_sensitive (true);
868 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
869 sample_rate_combo.set_sensitive (true);
871 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
872 buffer_size_combo.set_sensitive (true);
880 EngineControl::driver_changed ()
882 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
885 backend->set_driver (driver_combo.get_active_text());
888 if (!ignore_changes) {
889 maybe_display_saved_state ();
894 EngineControl::device_changed ()
897 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
899 string device_name = device_combo.get_active_text ();
902 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
903 backend->set_device_name(device_name);
906 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
908 /* don't allow programmatic change to combos to cause a
909 recursive call to this method.
919 sr = backend->available_sample_rates (device_name);
922 sr.push_back (8000.0f);
923 sr.push_back (16000.0f);
924 sr.push_back (32000.0f);
925 sr.push_back (44100.0f);
926 sr.push_back (48000.0f);
927 sr.push_back (88200.0f);
928 sr.push_back (96000.0f);
929 sr.push_back (192000.0f);
930 sr.push_back (384000.0f);
933 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
934 s.push_back (rate_as_string (*x));
935 if (*x == _desired_sample_rate) {
941 sample_rate_combo.set_sensitive (true);
942 set_popdown_strings (sample_rate_combo, s);
944 if (desired.empty()) {
945 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
947 sample_rate_combo.set_active_text (desired);
951 sample_rate_combo.set_sensitive (false);
959 bs = backend->available_buffer_sizes (device_name);
960 } else if (backend->can_change_buffer_size_when_running()) {
974 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
975 s.push_back (bufsize_as_string (*x));
979 buffer_size_combo.set_sensitive (true);
980 set_popdown_strings (buffer_size_combo, s);
982 uint32_t period = backend->buffer_size();
984 period = backend->default_buffer_size(device_name);
986 buffer_size_combo.set_active_text (bufsize_as_string (period));
987 show_buffer_duration ();
989 buffer_size_combo.set_sensitive (false);
992 /* XXX theoretically need to set min + max channel counts here
995 manage_control_app_sensitivity ();
998 /* pick up any saved state for this device */
1000 if (!ignore_changes) {
1001 maybe_display_saved_state ();
1006 EngineControl::bufsize_as_string (uint32_t sz)
1008 /* Translators: "samples" is always plural here, so no
1009 need for plural+singular forms.
1012 snprintf (buf, sizeof (buf), _("%u samples"), sz);
1017 EngineControl::sample_rate_changed ()
1019 /* reset the strings for buffer size to show the correct msec value
1020 (reflecting the new sample rate).
1023 show_buffer_duration ();
1024 if (!ignore_changes) {
1031 EngineControl::buffer_size_changed ()
1033 show_buffer_duration ();
1034 if (!ignore_changes) {
1040 EngineControl::show_buffer_duration ()
1043 /* buffer sizes - convert from just samples to samples + msecs for
1044 * the displayed string
1047 string bs_text = buffer_size_combo.get_active_text ();
1048 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1049 uint32_t rate = get_rate();
1051 /* Developers: note the hard-coding of a double buffered model
1052 in the (2 * samples) computation of latency. we always start
1053 the audiobackend in this configuration.
1055 /* note to jack1 developers: ardour also always starts the engine
1056 * in async mode (no jack2 --sync option) which adds an extra cycle
1057 * of latency with jack2 (and *3 would be correct)
1058 * The value can also be wrong if jackd is started externally..
1060 * At the time of writing the ALSA backend always uses double-buffering *2,
1061 * The Dummy backend *1, and who knows what ASIO really does :)
1063 * So just display the period size, that's also what
1064 * ARDOUR_UI::update_sample_rate() does for the status bar.
1065 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1066 * but still, that's the buffer period, not [round-trip] latency)
1069 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1070 buffer_size_duration_label.set_text (buf);
1074 EngineControl::midi_option_changed ()
1076 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1079 backend->set_midi_option (get_midi_option());
1081 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1083 //_midi_devices.clear(); // TODO merge with state-saved settings..
1084 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1085 std::vector<MidiDeviceSettings> new_devices;
1087 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1088 MidiDeviceSettings mds = find_midi_device (i->name);
1089 if (i->available && !mds) {
1090 uint32_t input_latency = 0;
1091 uint32_t output_latency = 0;
1092 if (_can_set_midi_latencies) {
1093 input_latency = backend->systemic_midi_input_latency (i->name);
1094 output_latency = backend->systemic_midi_output_latency (i->name);
1096 bool enabled = backend->midi_device_enabled (i->name);
1097 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1098 new_devices.push_back (ptr);
1099 } else if (i->available) {
1100 new_devices.push_back (mds);
1103 _midi_devices = new_devices;
1105 if (_midi_devices.empty()) {
1106 midi_devices_button.set_sensitive (false);
1108 midi_devices_button.set_sensitive (true);
1111 if (!ignore_changes) {
1117 EngineControl::parameter_changed ()
1119 if (!ignore_changes) {
1124 EngineControl::State
1125 EngineControl::get_matching_state (
1126 const string& backend,
1127 const string& driver,
1128 const string& device)
1130 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1131 if ((*i)->backend == backend &&
1132 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1140 EngineControl::State
1141 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1143 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1146 return get_matching_state (backend_combo.get_active_text(),
1147 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1148 device_combo.get_active_text());
1152 return get_matching_state (backend_combo.get_active_text(),
1154 device_combo.get_active_text());
1157 EngineControl::State
1158 EngineControl::save_state ()
1162 if (!_have_control) {
1163 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1167 state.reset(new StateStruct);
1168 state->backend = get_backend ();
1170 state.reset(new StateStruct);
1171 store_state (state);
1174 for (StateList::iterator i = states.begin(); i != states.end();) {
1175 if ((*i)->backend == state->backend &&
1176 (*i)->driver == state->driver &&
1177 (*i)->device == state->device) {
1178 i = states.erase(i);
1184 states.push_back (state);
1190 EngineControl::store_state (State state)
1192 state->backend = get_backend ();
1193 state->driver = get_driver ();
1194 state->device = get_device_name ();
1195 state->sample_rate = get_rate ();
1196 state->buffer_size = get_buffer_size ();
1197 state->input_latency = get_input_latency ();
1198 state->output_latency = get_output_latency ();
1199 state->input_channels = get_input_channels ();
1200 state->output_channels = get_output_channels ();
1201 state->midi_option = get_midi_option ();
1202 state->midi_devices = _midi_devices;
1206 EngineControl::maybe_display_saved_state ()
1208 if (!_have_control) {
1212 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1215 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1217 if (!_desired_sample_rate) {
1218 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1220 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1221 /* call this explicitly because we're ignoring changes to
1222 the controls at this point.
1224 show_buffer_duration ();
1225 input_latency.set_value (state->input_latency);
1226 output_latency.set_value (state->output_latency);
1228 if (!state->midi_option.empty()) {
1229 midi_option_combo.set_active_text (state->midi_option);
1230 _midi_devices = state->midi_devices;
1236 EngineControl::get_state ()
1238 XMLNode* root = new XMLNode ("AudioMIDISetup");
1241 if (!states.empty()) {
1242 XMLNode* state_nodes = new XMLNode ("EngineStates");
1244 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1246 XMLNode* node = new XMLNode ("State");
1248 node->add_property ("backend", (*i)->backend);
1249 node->add_property ("driver", (*i)->driver);
1250 node->add_property ("device", (*i)->device);
1251 node->add_property ("sample-rate", (*i)->sample_rate);
1252 node->add_property ("buffer-size", (*i)->buffer_size);
1253 node->add_property ("input-latency", (*i)->input_latency);
1254 node->add_property ("output-latency", (*i)->output_latency);
1255 node->add_property ("input-channels", (*i)->input_channels);
1256 node->add_property ("output-channels", (*i)->output_channels);
1257 node->add_property ("active", (*i)->active ? "yes" : "no");
1258 node->add_property ("midi-option", (*i)->midi_option);
1260 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1261 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1262 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1263 midi_device_stuff->add_property (X_("name"), (*p)->name);
1264 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1265 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1266 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1267 midi_devices->add_child_nocopy (*midi_device_stuff);
1269 node->add_child_nocopy (*midi_devices);
1271 state_nodes->add_child_nocopy (*node);
1274 root->add_child_nocopy (*state_nodes);
1281 EngineControl::set_state (const XMLNode& root)
1283 XMLNodeList clist, cclist;
1284 XMLNodeConstIterator citer, cciter;
1286 XMLNode* grandchild;
1287 XMLProperty* prop = NULL;
1289 if (root.name() != "AudioMIDISetup") {
1293 clist = root.children();
1297 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1301 if (child->name() != "EngineStates") {
1305 cclist = child->children();
1307 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1308 State state (new StateStruct);
1310 grandchild = *cciter;
1312 if (grandchild->name() != "State") {
1316 if ((prop = grandchild->property ("backend")) == 0) {
1319 state->backend = prop->value ();
1321 if ((prop = grandchild->property ("driver")) == 0) {
1324 state->driver = prop->value ();
1326 if ((prop = grandchild->property ("device")) == 0) {
1329 state->device = prop->value ();
1331 if ((prop = grandchild->property ("sample-rate")) == 0) {
1334 state->sample_rate = atof (prop->value ());
1336 if ((prop = grandchild->property ("buffer-size")) == 0) {
1339 state->buffer_size = atoi (prop->value ());
1341 if ((prop = grandchild->property ("input-latency")) == 0) {
1344 state->input_latency = atoi (prop->value ());
1346 if ((prop = grandchild->property ("output-latency")) == 0) {
1349 state->output_latency = atoi (prop->value ());
1351 if ((prop = grandchild->property ("input-channels")) == 0) {
1354 state->input_channels = atoi (prop->value ());
1356 if ((prop = grandchild->property ("output-channels")) == 0) {
1359 state->output_channels = atoi (prop->value ());
1361 if ((prop = grandchild->property ("active")) == 0) {
1364 state->active = string_is_affirmative (prop->value ());
1366 if ((prop = grandchild->property ("midi-option")) == 0) {
1369 state->midi_option = prop->value ();
1371 state->midi_devices.clear();
1373 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1374 const XMLNodeList mnc = midinode->children();
1375 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1376 if ((*n)->property (X_("name")) == 0
1377 || (*n)->property (X_("enabled")) == 0
1378 || (*n)->property (X_("input-latency")) == 0
1379 || (*n)->property (X_("output-latency")) == 0
1384 MidiDeviceSettings ptr (new MidiDeviceSetting(
1385 (*n)->property (X_("name"))->value (),
1386 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1387 atoi ((*n)->property (X_("input-latency"))->value ()),
1388 atoi ((*n)->property (X_("output-latency"))->value ())
1390 state->midi_devices.push_back (ptr);
1395 /* remove accumulated duplicates (due to bug in ealier version)
1396 * this can be removed again before release
1398 for (StateList::iterator i = states.begin(); i != states.end();) {
1399 if ((*i)->backend == state->backend &&
1400 (*i)->driver == state->driver &&
1401 (*i)->device == state->device) {
1402 i = states.erase(i);
1409 states.push_back (state);
1413 /* now see if there was an active state and switch the setup to it */
1415 // purge states of backend that are not available in this built
1416 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1417 vector<std::string> backend_names;
1419 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1420 backend_names.push_back((*i)->name);
1422 for (StateList::iterator i = states.begin(); i != states.end();) {
1423 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1424 i = states.erase(i);
1430 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1434 backend_combo.set_active_text ((*i)->backend);
1435 driver_combo.set_active_text ((*i)->driver);
1436 device_combo.set_active_text ((*i)->device);
1437 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1438 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1439 input_latency.set_value ((*i)->input_latency);
1440 output_latency.set_value ((*i)->output_latency);
1441 midi_option_combo.set_active_text ((*i)->midi_option);
1449 EngineControl::push_state_to_backend (bool start)
1451 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1457 /* figure out what is going to change */
1459 bool restart_required = false;
1460 bool was_running = ARDOUR::AudioEngine::instance()->running();
1461 bool change_driver = false;
1462 bool change_device = false;
1463 bool change_rate = false;
1464 bool change_bufsize = false;
1465 bool change_latency = false;
1466 bool change_channels = false;
1467 bool change_midi = false;
1469 uint32_t ochan = get_output_channels ();
1470 uint32_t ichan = get_input_channels ();
1472 if (_have_control) {
1474 if (started_at_least_once) {
1476 /* we can control the backend */
1478 if (backend->requires_driver_selection()) {
1479 if (get_driver() != backend->driver_name()) {
1480 change_driver = true;
1484 if (get_device_name() != backend->device_name()) {
1485 change_device = true;
1488 if (get_rate() != backend->sample_rate()) {
1492 if (get_buffer_size() != backend->buffer_size()) {
1493 change_bufsize = true;
1496 if (get_midi_option() != backend->midi_option()) {
1500 /* zero-requested channels means "all available" */
1503 ichan = backend->input_channels();
1507 ochan = backend->output_channels();
1510 if (ichan != backend->input_channels()) {
1511 change_channels = true;
1514 if (ochan != backend->output_channels()) {
1515 change_channels = true;
1518 if (get_input_latency() != backend->systemic_input_latency() ||
1519 get_output_latency() != backend->systemic_output_latency()) {
1520 change_latency = true;
1523 /* backend never started, so we have to force a group
1526 change_device = true;
1527 if (backend->requires_driver_selection()) {
1528 change_driver = true;
1531 change_bufsize = true;
1532 change_channels = true;
1533 change_latency = true;
1539 /* we have no control over the backend, meaning that we can
1540 * only possibly change sample rate and buffer size.
1544 if (get_rate() != backend->sample_rate()) {
1545 change_bufsize = true;
1548 if (get_buffer_size() != backend->buffer_size()) {
1549 change_bufsize = true;
1553 if (!_have_control) {
1555 /* We do not have control over the backend, so the best we can
1556 * do is try to change the sample rate and/or bufsize and get
1560 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1564 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1569 backend->set_sample_rate (get_rate());
1572 if (change_bufsize) {
1573 backend->set_buffer_size (get_buffer_size());
1577 if (ARDOUR::AudioEngine::instance()->start ()) {
1578 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1588 /* determine if we need to stop the backend before changing parameters */
1590 if (change_driver || change_device || change_channels || change_latency ||
1591 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1593 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1594 restart_required = true;
1596 restart_required = false;
1601 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1602 /* no changes in any parameters that absolutely require a
1603 * restart, so check those that might be changeable without a
1607 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1608 /* can't do this while running ... */
1609 restart_required = true;
1612 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1613 /* can't do this while running ... */
1614 restart_required = true;
1620 if (restart_required) {
1621 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1628 if (change_driver && backend->set_driver (get_driver())) {
1629 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1632 if (change_device && backend->set_device_name (get_device_name())) {
1633 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1636 if (change_rate && backend->set_sample_rate (get_rate())) {
1637 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1640 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1641 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1645 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1646 if (backend->set_input_channels (get_input_channels())) {
1647 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1650 if (backend->set_output_channels (get_output_channels())) {
1651 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1655 if (change_latency) {
1656 if (backend->set_systemic_input_latency (get_input_latency())) {
1657 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1660 if (backend->set_systemic_output_latency (get_output_latency())) {
1661 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1667 backend->set_midi_option (get_midi_option());
1671 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1672 if (_measure_midi) {
1673 if (*p == _measure_midi) {
1674 backend->set_midi_device_enabled ((*p)->name, true);
1676 backend->set_midi_device_enabled ((*p)->name, false);
1680 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1681 if (backend->can_set_systemic_midi_latencies()) {
1682 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1683 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1688 if (start || (was_running && restart_required)) {
1689 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1700 EngineControl::post_push ()
1702 /* get a pointer to the current state object, creating one if
1706 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1709 state = save_state ();
1715 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1716 (*i)->active = false;
1719 /* mark this one active (to be used next time the dialog is
1723 state->active = true;
1725 if (_have_control) { // XXX
1726 manage_control_app_sensitivity ();
1729 /* schedule a redisplay of MIDI ports */
1730 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1735 EngineControl::get_rate () const
1737 float r = atof (sample_rate_combo.get_active_text ());
1738 /* the string may have been translated with an abbreviation for
1739 * thousands, so use a crude heuristic to fix this.
1749 EngineControl::get_buffer_size () const
1751 string txt = buffer_size_combo.get_active_text ();
1754 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1762 EngineControl::get_midi_option () const
1764 return midi_option_combo.get_active_text();
1768 EngineControl::get_input_channels() const
1770 if (ARDOUR::Profile->get_mixbus()) {
1771 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1772 if (!backend) return 0;
1773 return backend->input_channels();
1775 return (uint32_t) input_channels_adjustment.get_value();
1779 EngineControl::get_output_channels() const
1781 if (ARDOUR::Profile->get_mixbus()) {
1782 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1783 if (!backend) return 0;
1784 return backend->input_channels();
1786 return (uint32_t) output_channels_adjustment.get_value();
1790 EngineControl::get_input_latency() const
1792 return (uint32_t) input_latency_adjustment.get_value();
1796 EngineControl::get_output_latency() const
1798 return (uint32_t) output_latency_adjustment.get_value();
1802 EngineControl::get_backend () const
1804 return backend_combo.get_active_text ();
1808 EngineControl::get_driver () const
1810 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1811 return driver_combo.get_active_text ();
1818 EngineControl::get_device_name () const
1820 return device_combo.get_active_text ();
1824 EngineControl::control_app_button_clicked ()
1826 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1832 backend->launch_control_app ();
1836 EngineControl::manage_control_app_sensitivity ()
1838 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1844 string appname = backend->control_app_name();
1846 if (appname.empty()) {
1847 control_app_button.set_sensitive (false);
1849 control_app_button.set_sensitive (true);
1854 EngineControl::set_desired_sample_rate (uint32_t sr)
1856 _desired_sample_rate = sr;
1861 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1863 if (page_num == 0) {
1864 cancel_button->set_sensitive (true);
1865 ok_button->set_sensitive (true);
1866 apply_button->set_sensitive (true);
1867 _measure_midi.reset();
1869 cancel_button->set_sensitive (false);
1870 ok_button->set_sensitive (false);
1871 apply_button->set_sensitive (false);
1874 if (page_num == midi_tab) {
1876 refresh_midi_display ();
1879 if (page_num == latency_tab) {
1882 if (ARDOUR::AudioEngine::instance()->running()) {
1883 // TODO - mark as 'stopped for latency
1884 ARDOUR_UI::instance()->disconnect_from_engine ();
1888 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1890 /* save any existing latency values */
1892 uint32_t il = (uint32_t) input_latency.get_value ();
1893 uint32_t ol = (uint32_t) input_latency.get_value ();
1895 /* reset to zero so that our new test instance
1896 will be clean of any existing latency measures.
1898 NB. this should really be done by the backend
1899 when stated for latency measurement.
1902 input_latency.set_value (0);
1903 output_latency.set_value (0);
1905 push_state_to_backend (false);
1909 input_latency.set_value (il);
1910 output_latency.set_value (ol);
1913 // This should be done in push_state_to_backend()
1914 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1915 disable_latency_tab ();
1918 enable_latency_tab ();
1922 end_latency_detection ();
1923 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1928 /* latency measurement */
1931 EngineControl::check_audio_latency_measurement ()
1933 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1935 if (mtdm->resolve () < 0) {
1936 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1940 if (mtdm->err () > 0.3) {
1946 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1948 if (sample_rate == 0) {
1949 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1950 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1954 int frames_total = mtdm->del();
1955 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1957 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1958 _("Detected roundtrip latency: "),
1959 frames_total, frames_total * 1000.0f/sample_rate,
1960 _("Systemic latency: "),
1961 extra, extra * 1000.0f/sample_rate);
1965 if (mtdm->err () > 0.2) {
1967 strcat (buf, _("(signal detection error)"));
1973 strcat (buf, _("(inverted - bad wiring)"));
1977 lm_results.set_markup (string_compose (results_markup, buf));
1980 have_lm_results = true;
1981 end_latency_detection ();
1982 lm_use_button.set_sensitive (true);
1990 EngineControl::check_midi_latency_measurement ()
1992 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1994 if (!mididm->have_signal () || mididm->latency () == 0) {
1995 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2000 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2002 if (sample_rate == 0) {
2003 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2004 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2008 ARDOUR::framecnt_t frames_total = mididm->latency();
2009 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2010 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2011 _("Detected roundtrip latency: "),
2012 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2013 _("Systemic latency: "),
2014 extra, extra * 1000.0f / sample_rate);
2018 if (!mididm->ok ()) {
2020 strcat (buf, _("(averaging)"));
2024 if (mididm->deviation () > 50.0) {
2026 strcat (buf, _("(too large jitter)"));
2028 } else if (mididm->deviation () > 10.0) {
2030 strcat (buf, _("(large jitter)"));
2034 have_lm_results = true;
2035 end_latency_detection ();
2036 lm_use_button.set_sensitive (true);
2037 lm_results.set_markup (string_compose (results_markup, buf));
2039 } else if (mididm->processed () > 400) {
2040 have_lm_results = false;
2041 end_latency_detection ();
2042 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2046 lm_results.set_markup (string_compose (results_markup, buf));
2052 EngineControl::start_latency_detection ()
2054 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2055 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2057 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2058 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2059 if (_measure_midi) {
2060 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2062 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2064 lm_measure_label.set_text (_("Cancel"));
2065 have_lm_results = false;
2066 lm_use_button.set_sensitive (false);
2067 lm_input_channel_combo.set_sensitive (false);
2068 lm_output_channel_combo.set_sensitive (false);
2074 EngineControl::end_latency_detection ()
2076 latency_timeout.disconnect ();
2077 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2078 lm_measure_label.set_text (_("Measure"));
2079 if (!have_lm_results) {
2080 lm_use_button.set_sensitive (false);
2082 lm_input_channel_combo.set_sensitive (true);
2083 lm_output_channel_combo.set_sensitive (true);
2088 EngineControl::latency_button_clicked ()
2091 start_latency_detection ();
2093 end_latency_detection ();
2098 EngineControl::use_latency_button_clicked ()
2100 if (_measure_midi) {
2101 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2105 ARDOUR::framecnt_t frames_total = mididm->latency();
2106 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2107 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2108 _measure_midi->input_latency = one_way;
2109 _measure_midi->output_latency = one_way;
2110 notebook.set_current_page (midi_tab);
2112 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2118 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2119 one_way = std::max (0., one_way);
2121 input_latency_adjustment.set_value (one_way);
2122 output_latency_adjustment.set_value (one_way);
2124 /* back to settings page */
2125 notebook.set_current_page (0);
2131 EngineControl::on_delete_event (GdkEventAny* ev)
2133 if (notebook.get_current_page() == 2) {
2134 /* currently on latency tab - be sure to clean up */
2135 end_latency_detection ();
2137 return ArdourDialog::on_delete_event (ev);
2141 EngineControl::engine_running ()
2143 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2146 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2147 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2149 buffer_size_combo.set_sensitive (true);
2150 sample_rate_combo.set_sensitive (true);
2152 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2153 connect_disconnect_button.show();
2155 started_at_least_once = true;
2156 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2160 EngineControl::engine_stopped ()
2162 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2165 buffer_size_combo.set_sensitive (false);
2166 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2167 connect_disconnect_button.show();
2169 sample_rate_combo.set_sensitive (true);
2170 buffer_size_combo.set_sensitive (true);
2171 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2175 EngineControl::connect_disconnect_click()
2177 if (ARDOUR::AudioEngine::instance()->running()) {
2178 ARDOUR_UI::instance()->disconnect_from_engine ();
2180 ARDOUR_UI::instance()->reconnect_to_engine ();
2185 EngineControl::calibrate_audio_latency ()
2187 _measure_midi.reset ();
2188 have_lm_results = false;
2189 lm_use_button.set_sensitive (false);
2190 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2191 notebook.set_current_page (latency_tab);
2195 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2198 have_lm_results = false;
2199 lm_use_button.set_sensitive (false);
2200 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2201 notebook.set_current_page (latency_tab);
2205 EngineControl::configure_midi_devices ()
2207 notebook.set_current_page (midi_tab);