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"))
72 , input_latency_adjustment (0, 0, 99999, 1)
73 , input_latency (input_latency_adjustment)
74 , output_latency_adjustment (0, 0, 99999, 1)
75 , output_latency (output_latency_adjustment)
76 , input_channels_adjustment (0, 0, 256, 1)
77 , input_channels (input_channels_adjustment)
78 , output_channels_adjustment (0, 0, 256, 1)
79 , output_channels (output_channels_adjustment)
80 , ports_adjustment (128, 8, 1024, 1, 16)
81 , ports_spinner (ports_adjustment)
82 , control_app_button (_("Device Control Panel"))
83 , midi_devices_button (_("Midi Device Setup"))
84 , lm_measure_label (_("Measure"))
85 , lm_use_button (_("Use results"))
86 , lm_back_button (_("Back to settings ... (ignore results)"))
87 , lm_button_audio (_("Calibrate Audio"))
89 , have_lm_results (false)
91 , midi_back_button (_("Back to settings"))
93 , _desired_sample_rate (0)
94 , started_at_least_once (false)
96 using namespace Notebook_Helpers;
97 vector<string> strings;
99 AttachOptions xopt = AttachOptions (FILL|EXPAND);
102 set_name (X_("AudioMIDISetup"));
104 /* the backend combo is the one thing that is ALWAYS visible */
106 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
108 if (backends.empty()) {
109 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));
111 throw failed_constructor ();
114 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
115 strings.push_back ((*b)->name);
118 set_popdown_strings (backend_combo, strings);
119 backend_combo.set_active_text (strings.front());
120 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
122 /* setup basic packing characteristics for the table used on the main
123 * tab of the notebook
126 basic_packer.set_spacings (6);
127 basic_packer.set_border_width (12);
128 basic_packer.set_homogeneous (false);
132 basic_hbox.pack_start (basic_packer, false, false);
134 /* latency measurement tab */
136 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
139 lm_table.set_row_spacings (12);
140 lm_table.set_col_spacings (6);
141 lm_table.set_homogeneous (false);
143 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
146 lm_preamble.set_width_chars (60);
147 lm_preamble.set_line_wrap (true);
148 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
150 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
153 Gtk::Label* preamble;
154 preamble = manage (new Label);
155 preamble->set_width_chars (60);
156 preamble->set_line_wrap (true);
157 preamble->set_markup (_("Select two channels below and connect them using a cable."));
159 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162 label = manage (new Label (_("Output channel")));
163 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
165 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
166 misc_align->add (lm_output_channel_combo);
167 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
170 label = manage (new Label (_("Input channel")));
171 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
173 misc_align = manage (new Alignment (0.0, 0.5));
174 misc_align->add (lm_input_channel_combo);
175 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
178 xopt = AttachOptions(0);
180 lm_measure_label.set_padding (10, 10);
181 lm_measure_button.add (lm_measure_label);
182 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
183 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
184 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
186 lm_use_button.set_sensitive (false);
188 /* Increase the default spacing around the labels of these three
194 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
195 l->set_padding (10, 10);
198 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
199 l->set_padding (10, 10);
202 preamble = manage (new Label);
203 preamble->set_width_chars (60);
204 preamble->set_line_wrap (true);
205 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
206 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
209 preamble = manage (new Label);
210 preamble->set_width_chars (60);
211 preamble->set_line_wrap (true);
212 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
213 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
215 ++row; // skip a row in the table
216 ++row; // skip a row in the table
218 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
220 ++row; // skip a row in the table
221 ++row; // skip a row in the table
223 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
225 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
229 lm_vbox.set_border_width (12);
230 lm_vbox.pack_start (lm_table, false, false);
232 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
236 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
237 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
238 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
239 notebook.set_border_width (12);
241 notebook.set_show_tabs (false);
242 notebook.show_all ();
244 notebook.set_name ("SettingsNotebook");
246 /* packup the notebook */
248 get_vbox()->set_border_width (12);
249 get_vbox()->pack_start (notebook);
251 /* need a special function to print "all available channels" when the
252 * channel counts hit zero.
255 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
256 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
258 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
259 midi_devices_button.set_sensitive (false);
260 midi_devices_button.set_name ("generic button");
261 midi_devices_button.set_can_focus(true);
263 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
264 manage_control_app_sensitivity ();
266 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
267 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
268 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
270 /* Pick up any existing audio setup configuration, if appropriate */
272 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
274 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
275 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
276 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
280 set_state (*audio_setup);
283 /* ignore: don't save state */
284 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
288 /* Connect to signals */
290 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
291 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
292 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
293 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
294 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
296 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
297 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
298 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
299 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
301 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
303 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
304 connect_disconnect_button.set_no_show_all();
309 EngineControl::on_show ()
311 ArdourDialog::on_show ();
313 ok_button->grab_focus();
317 EngineControl::on_response (int response_id)
319 ArdourDialog::on_response (response_id);
321 switch (response_id) {
323 push_state_to_backend (true);
326 push_state_to_backend (true);
329 case RESPONSE_DELETE_EVENT:
332 ev.type = GDK_BUTTON_PRESS;
334 on_delete_event ((GdkEventAny*) &ev);
343 EngineControl::build_notebook ()
346 AttachOptions xopt = AttachOptions (FILL|EXPAND);
348 /* clear the table */
350 Gtkmm2ext::container_clear (basic_vbox);
351 Gtkmm2ext::container_clear (basic_packer);
353 if (control_app_button.get_parent()) {
354 control_app_button.get_parent()->remove (control_app_button);
357 label = manage (left_aligned_label (_("Audio System:")));
358 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
359 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
361 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
362 lm_button_audio.set_name ("generic button");
363 lm_button_audio.set_can_focus(true);
366 build_full_control_notebook ();
368 build_no_control_notebook ();
371 basic_vbox.pack_start (basic_hbox, false, false);
374 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
375 basic_vbox.show_all ();
380 EngineControl::build_full_control_notebook ()
382 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
385 using namespace Notebook_Helpers;
387 vector<string> strings;
388 AttachOptions xopt = AttachOptions (FILL|EXPAND);
389 int row = 1; // row zero == backend combo
391 /* start packing it up */
393 if (backend->requires_driver_selection()) {
394 label = manage (left_aligned_label (_("Driver:")));
395 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
396 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
400 label = manage (left_aligned_label (_("Device:")));
401 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
402 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
405 label = manage (left_aligned_label (_("Sample rate:")));
406 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
407 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
411 label = manage (left_aligned_label (_("Buffer size:")));
412 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
413 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
414 buffer_size_duration_label.set_alignment (0.0); /* left-align */
415 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
417 /* button spans 2 rows */
419 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
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 if (!ARDOUR::Profile->get_mixbus()) {
429 label = manage (left_aligned_label (_("Input Channels:")));
430 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
431 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
435 output_channels.set_name ("OutputChannels");
436 output_channels.set_flags (Gtk::CAN_FOCUS);
437 output_channels.set_digits (0);
438 output_channels.set_wrap (false);
439 output_channels.set_editable (true);
441 if (!ARDOUR::Profile->get_mixbus()) {
442 label = manage (left_aligned_label (_("Output Channels:")));
443 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
444 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
448 input_latency.set_name ("InputLatency");
449 input_latency.set_flags (Gtk::CAN_FOCUS);
450 input_latency.set_digits (0);
451 input_latency.set_wrap (false);
452 input_latency.set_editable (true);
454 label = manage (left_aligned_label (_("Hardware input latency:")));
455 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
456 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
457 label = manage (left_aligned_label (_("samples")));
458 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
461 output_latency.set_name ("OutputLatency");
462 output_latency.set_flags (Gtk::CAN_FOCUS);
463 output_latency.set_digits (0);
464 output_latency.set_wrap (false);
465 output_latency.set_editable (true);
467 label = manage (left_aligned_label (_("Hardware output latency:")));
468 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
469 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
470 label = manage (left_aligned_label (_("samples")));
471 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
473 /* button spans 2 rows */
475 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
478 label = manage (left_aligned_label (_("MIDI System")));
479 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
480 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
481 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
486 EngineControl::build_no_control_notebook ()
488 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
491 using namespace Notebook_Helpers;
493 vector<string> strings;
494 AttachOptions xopt = AttachOptions (FILL|EXPAND);
495 int row = 1; // row zero == backend combo
496 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
498 label = manage (new Label);
499 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
500 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
503 if (backend->can_change_sample_rate_when_running()) {
504 label = manage (left_aligned_label (_("Sample rate:")));
505 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
506 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
510 if (backend->can_change_buffer_size_when_running()) {
511 label = manage (left_aligned_label (_("Buffer size:")));
512 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
513 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
514 buffer_size_duration_label.set_alignment (0.0); /* left-align */
515 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
519 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
523 EngineControl::~EngineControl ()
525 ignore_changes = true;
529 EngineControl::disable_latency_tab ()
531 vector<string> empty;
532 set_popdown_strings (lm_output_channel_combo, empty);
533 set_popdown_strings (lm_input_channel_combo, empty);
534 lm_measure_button.set_sensitive (false);
535 lm_use_button.set_sensitive (false);
539 EngineControl::enable_latency_tab ()
541 vector<string> outputs;
542 vector<string> inputs;
544 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
545 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
546 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
548 if (!ARDOUR::AudioEngine::instance()->running()) {
549 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
550 notebook.set_current_page (0);
554 else if (inputs.empty() || outputs.empty()) {
555 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
556 notebook.set_current_page (0);
561 lm_back_button_signal.disconnect();
563 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
566 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
570 set_popdown_strings (lm_output_channel_combo, outputs);
571 lm_output_channel_combo.set_active_text (outputs.front());
572 lm_output_channel_combo.set_sensitive (true);
574 set_popdown_strings (lm_input_channel_combo, inputs);
575 lm_input_channel_combo.set_active_text (inputs.front());
576 lm_input_channel_combo.set_sensitive (true);
578 lm_measure_button.set_sensitive (true);
582 EngineControl::setup_midi_tab_for_backend ()
584 string backend = backend_combo.get_active_text ();
586 Gtkmm2ext::container_clear (midi_vbox);
588 midi_vbox.set_border_width (12);
589 midi_device_table.set_border_width (12);
591 if (backend == "JACK") {
592 setup_midi_tab_for_jack ();
595 midi_vbox.pack_start (midi_device_table, true, true);
596 midi_vbox.pack_start (midi_back_button, false, false);
597 midi_vbox.show_all ();
601 EngineControl::setup_midi_tab_for_jack ()
606 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
608 device->input_latency = a->get_value();
610 device->output_latency = a->get_value();
615 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
616 b->set_active (!b->get_active());
617 device->enabled = b->get_active();
618 refresh_midi_display(device->name);
622 EngineControl::refresh_midi_display (std::string focus)
624 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
628 AttachOptions xopt = AttachOptions (FILL|EXPAND);
631 Gtkmm2ext::container_clear (midi_device_table);
633 midi_device_table.set_spacings (6);
635 l = manage (new Label);
636 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
637 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
638 l->set_alignment (0.5, 0.5);
642 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
643 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
644 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
645 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
647 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
648 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
649 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
650 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
653 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
658 bool enabled = (*p)->enabled;
660 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
661 m->set_name ("midi device");
662 m->set_can_focus (Gtk::CAN_FOCUS);
663 m->add_events (Gdk::BUTTON_RELEASE_MASK);
664 m->set_active (enabled);
665 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
666 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
667 if ((*p)->name == focus) {
671 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
672 s = manage (new Gtk::SpinButton (*a));
673 a->set_value ((*p)->input_latency);
674 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
675 s->set_sensitive (_can_set_midi_latencies && enabled);
676 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
678 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
679 s = manage (new Gtk::SpinButton (*a));
680 a->set_value ((*p)->output_latency);
681 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
682 s->set_sensitive (_can_set_midi_latencies && enabled);
683 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
685 b = manage (new Button (_("Calibrate")));
686 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
687 b->set_sensitive (_can_set_midi_latencies && enabled);
688 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
695 EngineControl::update_sensitivity ()
700 EngineControl::backend_changed ()
702 string backend_name = backend_combo.get_active_text();
703 boost::shared_ptr<ARDOUR::AudioBackend> backend;
705 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
706 /* eh? setting the backend failed... how ? */
710 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
713 setup_midi_tab_for_backend ();
714 _midi_devices.clear();
716 if (backend->requires_driver_selection()) {
717 vector<string> drivers = backend->enumerate_drivers();
718 driver_combo.set_sensitive (true);
720 if (!drivers.empty()) {
722 string current_driver;
723 current_driver = backend->driver_name ();
725 // driver might not have been set yet
726 if (current_driver == "") {
727 current_driver = driver_combo.get_active_text ();
728 if (current_driver == "")
729 // driver has never been set, make sure it's not blank
730 current_driver = drivers.front ();
733 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
734 set_popdown_strings (driver_combo, drivers);
735 driver_combo.set_active_text (current_driver);
742 driver_combo.set_sensitive (false);
743 /* this will change the device text which will cause a call to
744 * device changed which will set up parameters
749 vector<string> midi_options = backend->enumerate_midi_options();
751 if (midi_options.size() == 1) {
752 /* only contains the "none" option */
753 midi_option_combo.set_sensitive (false);
756 set_popdown_strings (midi_option_combo, midi_options);
757 midi_option_combo.set_active_text (midi_options.front());
758 midi_option_combo.set_sensitive (true);
760 midi_option_combo.set_sensitive (false);
764 connect_disconnect_button.hide();
766 midi_option_changed();
768 started_at_least_once = false;
770 if (!ignore_changes) {
771 maybe_display_saved_state ();
776 EngineControl::print_channel_count (Gtk::SpinButton* sb)
778 if (ARDOUR::Profile->get_mixbus()) {
779 cout << "Mixbus crash trap. sb->get_value(): " << sb->get_value();
783 uint32_t cnt = (uint32_t) sb->get_value();
785 sb->set_text (_("all available channels"));
788 snprintf (buf, sizeof (buf), "%d", cnt);
795 EngineControl::list_devices ()
797 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
800 /* now fill out devices, mark sample rates, buffer sizes insensitive */
802 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
804 /* NOTE: Ardour currently does not display the "available" field of the
807 * Doing so would require a different GUI widget than the combo
808 * box/popdown that we currently use, since it has no way to list
809 * items that are not selectable. Something more like a popup menu,
810 * which could have unselectable items, would be appropriate.
813 vector<string> available_devices;
815 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
816 available_devices.push_back (i->name);
819 if (!available_devices.empty()) {
821 update_sensitivity ();
824 string current_device;
825 current_device = backend->device_name ();
826 if (current_device == "") {
827 // device might not have been set yet
828 current_device = device_combo.get_active_text ();
829 if (current_device == "")
830 // device has never been set, make sure it's not blank
831 current_device = available_devices.front ();
834 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
835 set_popdown_strings (device_combo, available_devices);
837 device_combo.set_active_text (current_device);
842 input_latency.set_sensitive (true);
843 output_latency.set_sensitive (true);
844 input_channels.set_sensitive (true);
845 output_channels.set_sensitive (true);
847 ok_button->set_sensitive (true);
848 apply_button->set_sensitive (true);
851 device_combo.clear();
852 sample_rate_combo.set_sensitive (false);
853 buffer_size_combo.set_sensitive (false);
854 input_latency.set_sensitive (false);
855 output_latency.set_sensitive (false);
856 input_channels.set_sensitive (false);
857 output_channels.set_sensitive (false);
859 ok_button->set_sensitive (false);
860 apply_button->set_sensitive (false);
862 ok_button->set_sensitive (true);
863 apply_button->set_sensitive (true);
864 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
865 sample_rate_combo.set_sensitive (true);
867 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
868 buffer_size_combo.set_sensitive (true);
876 EngineControl::driver_changed ()
878 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
881 backend->set_driver (driver_combo.get_active_text());
884 if (!ignore_changes) {
885 maybe_display_saved_state ();
890 EngineControl::device_changed ()
893 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
895 string device_name = device_combo.get_active_text ();
899 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
901 /* don't allow programmatic change to combos to cause a
902 recursive call to this method.
912 sr = backend->available_sample_rates (device_name);
915 sr.push_back (8000.0f);
916 sr.push_back (16000.0f);
917 sr.push_back (32000.0f);
918 sr.push_back (44100.0f);
919 sr.push_back (48000.0f);
920 sr.push_back (88200.0f);
921 sr.push_back (96000.0f);
922 sr.push_back (192000.0f);
923 sr.push_back (384000.0f);
926 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
927 s.push_back (rate_as_string (*x));
928 if (*x == _desired_sample_rate) {
934 sample_rate_combo.set_sensitive (true);
935 set_popdown_strings (sample_rate_combo, s);
937 if (desired.empty()) {
938 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
940 sample_rate_combo.set_active_text (desired);
944 sample_rate_combo.set_sensitive (false);
952 bs = backend->available_buffer_sizes (device_name);
953 } else if (backend->can_change_buffer_size_when_running()) {
967 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
968 s.push_back (bufsize_as_string (*x));
972 buffer_size_combo.set_sensitive (true);
973 set_popdown_strings (buffer_size_combo, s);
975 uint32_t period = backend->buffer_size();
977 period = backend->default_buffer_size(device_name);
979 buffer_size_combo.set_active_text (bufsize_as_string (period));
980 show_buffer_duration ();
982 buffer_size_combo.set_sensitive (false);
985 /* XXX theoretically need to set min + max channel counts here
988 manage_control_app_sensitivity ();
991 /* pick up any saved state for this device */
993 if (!ignore_changes) {
994 maybe_display_saved_state ();
999 EngineControl::bufsize_as_string (uint32_t sz)
1001 /* Translators: "samples" is always plural here, so no
1002 need for plural+singular forms.
1005 snprintf (buf, sizeof (buf), _("%u samples"), sz);
1010 EngineControl::sample_rate_changed ()
1012 /* reset the strings for buffer size to show the correct msec value
1013 (reflecting the new sample rate).
1016 show_buffer_duration ();
1017 if (!ignore_changes) {
1024 EngineControl::buffer_size_changed ()
1026 show_buffer_duration ();
1027 if (!ignore_changes) {
1033 EngineControl::show_buffer_duration ()
1036 /* buffer sizes - convert from just samples to samples + msecs for
1037 * the displayed string
1040 string bs_text = buffer_size_combo.get_active_text ();
1041 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1042 uint32_t rate = get_rate();
1044 /* Developers: note the hard-coding of a double buffered model
1045 in the (2 * samples) computation of latency. we always start
1046 the audiobackend in this configuration.
1048 /* note to jack1 developers: ardour also always starts the engine
1049 * in async mode (no jack2 --sync option) which adds an extra cycle
1050 * of latency with jack2 (and *3 would be correct)
1051 * The value can also be wrong if jackd is started externally..
1053 * At the time of writing the ALSA backend always uses double-buffering *2,
1054 * The Dummy backend *1, and who knows what ASIO really does :)
1056 * So just display the period size, that's also what
1057 * ARDOUR_UI::update_sample_rate() does for the status bar.
1058 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1059 * but still, that's the buffer period, not [round-trip] latency)
1062 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1063 buffer_size_duration_label.set_text (buf);
1067 EngineControl::midi_option_changed ()
1069 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1072 backend->set_midi_option (get_midi_option());
1074 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1076 //_midi_devices.clear(); // TODO merge with state-saved settings..
1077 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1078 std::vector<MidiDeviceSettings> new_devices;
1080 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1081 MidiDeviceSettings mds = find_midi_device (i->name);
1082 if (i->available && !mds) {
1083 uint32_t input_latency = 0;
1084 uint32_t output_latency = 0;
1085 if (_can_set_midi_latencies) {
1086 input_latency = backend->systemic_midi_input_latency (i->name);
1087 output_latency = backend->systemic_midi_output_latency (i->name);
1089 bool enabled = backend->midi_device_enabled (i->name);
1090 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1091 new_devices.push_back (ptr);
1092 } else if (i->available) {
1093 new_devices.push_back (mds);
1096 _midi_devices = new_devices;
1098 if (_midi_devices.empty()) {
1099 midi_devices_button.set_sensitive (false);
1101 midi_devices_button.set_sensitive (true);
1104 if (!ignore_changes) {
1110 EngineControl::parameter_changed ()
1112 if (!ignore_changes) {
1117 EngineControl::State
1118 EngineControl::get_matching_state (
1119 const string& backend,
1120 const string& driver,
1121 const string& device)
1123 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1124 if ((*i)->backend == backend &&
1125 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1133 EngineControl::State
1134 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1136 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1139 return get_matching_state (backend_combo.get_active_text(),
1140 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1141 device_combo.get_active_text());
1145 return get_matching_state (backend_combo.get_active_text(),
1147 device_combo.get_active_text());
1150 EngineControl::State
1151 EngineControl::save_state ()
1155 if (!_have_control) {
1156 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1160 state.reset(new StateStruct);
1161 state->backend = get_backend ();
1163 state.reset(new StateStruct);
1164 store_state (state);
1167 for (StateList::iterator i = states.begin(); i != states.end();) {
1168 if ((*i)->backend == state->backend &&
1169 (*i)->driver == state->driver &&
1170 (*i)->device == state->device) {
1171 i = states.erase(i);
1177 states.push_back (state);
1183 EngineControl::store_state (State state)
1185 state->backend = get_backend ();
1186 state->driver = get_driver ();
1187 state->device = get_device_name ();
1188 state->sample_rate = get_rate ();
1189 state->buffer_size = get_buffer_size ();
1190 state->input_latency = get_input_latency ();
1191 state->output_latency = get_output_latency ();
1192 state->input_channels = get_input_channels ();
1193 state->output_channels = get_output_channels ();
1194 state->midi_option = get_midi_option ();
1195 state->midi_devices = _midi_devices;
1199 EngineControl::maybe_display_saved_state ()
1201 if (!_have_control) {
1205 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1208 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1210 if (!_desired_sample_rate) {
1211 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1213 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1214 /* call this explicitly because we're ignoring changes to
1215 the controls at this point.
1217 show_buffer_duration ();
1218 input_latency.set_value (state->input_latency);
1219 output_latency.set_value (state->output_latency);
1221 if (!state->midi_option.empty()) {
1222 midi_option_combo.set_active_text (state->midi_option);
1223 _midi_devices = state->midi_devices;
1229 EngineControl::get_state ()
1231 XMLNode* root = new XMLNode ("AudioMIDISetup");
1234 if (!states.empty()) {
1235 XMLNode* state_nodes = new XMLNode ("EngineStates");
1237 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1239 XMLNode* node = new XMLNode ("State");
1241 node->add_property ("backend", (*i)->backend);
1242 node->add_property ("driver", (*i)->driver);
1243 node->add_property ("device", (*i)->device);
1244 node->add_property ("sample-rate", (*i)->sample_rate);
1245 node->add_property ("buffer-size", (*i)->buffer_size);
1246 node->add_property ("input-latency", (*i)->input_latency);
1247 node->add_property ("output-latency", (*i)->output_latency);
1248 node->add_property ("input-channels", (*i)->input_channels);
1249 node->add_property ("output-channels", (*i)->output_channels);
1250 node->add_property ("active", (*i)->active ? "yes" : "no");
1251 node->add_property ("midi-option", (*i)->midi_option);
1253 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1254 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1255 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1256 midi_device_stuff->add_property (X_("name"), (*p)->name);
1257 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1258 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1259 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1260 midi_devices->add_child_nocopy (*midi_device_stuff);
1262 node->add_child_nocopy (*midi_devices);
1264 state_nodes->add_child_nocopy (*node);
1267 root->add_child_nocopy (*state_nodes);
1274 EngineControl::set_state (const XMLNode& root)
1276 XMLNodeList clist, cclist;
1277 XMLNodeConstIterator citer, cciter;
1279 XMLNode* grandchild;
1280 XMLProperty* prop = NULL;
1282 if (root.name() != "AudioMIDISetup") {
1286 clist = root.children();
1290 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1294 if (child->name() != "EngineStates") {
1298 cclist = child->children();
1300 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1301 State state (new StateStruct);
1303 grandchild = *cciter;
1305 if (grandchild->name() != "State") {
1309 if ((prop = grandchild->property ("backend")) == 0) {
1312 state->backend = prop->value ();
1314 if ((prop = grandchild->property ("driver")) == 0) {
1317 state->driver = prop->value ();
1319 if ((prop = grandchild->property ("device")) == 0) {
1322 state->device = prop->value ();
1324 if ((prop = grandchild->property ("sample-rate")) == 0) {
1327 state->sample_rate = atof (prop->value ());
1329 if ((prop = grandchild->property ("buffer-size")) == 0) {
1332 state->buffer_size = atoi (prop->value ());
1334 if ((prop = grandchild->property ("input-latency")) == 0) {
1337 state->input_latency = atoi (prop->value ());
1339 if ((prop = grandchild->property ("output-latency")) == 0) {
1342 state->output_latency = atoi (prop->value ());
1344 if ((prop = grandchild->property ("input-channels")) == 0) {
1347 state->input_channels = atoi (prop->value ());
1349 if ((prop = grandchild->property ("output-channels")) == 0) {
1352 state->output_channels = atoi (prop->value ());
1354 if ((prop = grandchild->property ("active")) == 0) {
1357 state->active = string_is_affirmative (prop->value ());
1359 if ((prop = grandchild->property ("midi-option")) == 0) {
1362 state->midi_option = prop->value ();
1364 state->midi_devices.clear();
1366 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1367 const XMLNodeList mnc = midinode->children();
1368 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1369 if ((*n)->property (X_("name")) == 0
1370 || (*n)->property (X_("enabled")) == 0
1371 || (*n)->property (X_("input-latency")) == 0
1372 || (*n)->property (X_("output-latency")) == 0
1377 MidiDeviceSettings ptr (new MidiDeviceSetting(
1378 (*n)->property (X_("name"))->value (),
1379 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1380 atoi ((*n)->property (X_("input-latency"))->value ()),
1381 atoi ((*n)->property (X_("output-latency"))->value ())
1383 state->midi_devices.push_back (ptr);
1388 /* remove accumulated duplicates (due to bug in ealier version)
1389 * this can be removed again before release
1391 for (StateList::iterator i = states.begin(); i != states.end();) {
1392 if ((*i)->backend == state->backend &&
1393 (*i)->driver == state->driver &&
1394 (*i)->device == state->device) {
1395 i = states.erase(i);
1402 states.push_back (state);
1406 /* now see if there was an active state and switch the setup to it */
1408 // purge states of backend that are not available in this built
1409 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1410 vector<std::string> backend_names;
1412 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1413 backend_names.push_back((*i)->name);
1415 for (StateList::iterator i = states.begin(); i != states.end();) {
1416 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1417 i = states.erase(i);
1423 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1427 backend_combo.set_active_text ((*i)->backend);
1428 driver_combo.set_active_text ((*i)->driver);
1429 device_combo.set_active_text ((*i)->device);
1430 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1431 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1432 input_latency.set_value ((*i)->input_latency);
1433 output_latency.set_value ((*i)->output_latency);
1434 midi_option_combo.set_active_text ((*i)->midi_option);
1442 EngineControl::push_state_to_backend (bool start)
1444 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1450 /* figure out what is going to change */
1452 bool restart_required = false;
1453 bool was_running = ARDOUR::AudioEngine::instance()->running();
1454 bool change_driver = false;
1455 bool change_device = false;
1456 bool change_rate = false;
1457 bool change_bufsize = false;
1458 bool change_latency = false;
1459 bool change_channels = false;
1460 bool change_midi = false;
1462 uint32_t ochan = get_output_channels ();
1463 uint32_t ichan = get_input_channels ();
1465 if (_have_control) {
1467 if (started_at_least_once) {
1469 /* we can control the backend */
1471 if (backend->requires_driver_selection()) {
1472 if (get_driver() != backend->driver_name()) {
1473 change_driver = true;
1477 if (get_device_name() != backend->device_name()) {
1478 change_device = true;
1481 if (get_rate() != backend->sample_rate()) {
1485 if (get_buffer_size() != backend->buffer_size()) {
1486 change_bufsize = true;
1489 if (get_midi_option() != backend->midi_option()) {
1493 /* zero-requested channels means "all available" */
1496 ichan = backend->input_channels();
1500 ochan = backend->output_channels();
1503 if (ichan != backend->input_channels()) {
1504 change_channels = true;
1507 if (ochan != backend->output_channels()) {
1508 change_channels = true;
1511 if (get_input_latency() != backend->systemic_input_latency() ||
1512 get_output_latency() != backend->systemic_output_latency()) {
1513 change_latency = true;
1516 /* backend never started, so we have to force a group
1519 change_device = true;
1520 if (backend->requires_driver_selection()) {
1521 change_driver = true;
1524 change_bufsize = true;
1525 change_channels = true;
1526 change_latency = true;
1532 /* we have no control over the backend, meaning that we can
1533 * only possibly change sample rate and buffer size.
1537 if (get_rate() != backend->sample_rate()) {
1538 change_bufsize = true;
1541 if (get_buffer_size() != backend->buffer_size()) {
1542 change_bufsize = true;
1546 if (!_have_control) {
1548 /* We do not have control over the backend, so the best we can
1549 * do is try to change the sample rate and/or bufsize and get
1553 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1557 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1562 backend->set_sample_rate (get_rate());
1565 if (change_bufsize) {
1566 backend->set_buffer_size (get_buffer_size());
1570 if (ARDOUR::AudioEngine::instance()->start ()) {
1571 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1581 /* determine if we need to stop the backend before changing parameters */
1583 if (change_driver || change_device || change_channels || change_latency ||
1584 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1586 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1587 restart_required = true;
1589 restart_required = false;
1594 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1595 /* no changes in any parameters that absolutely require a
1596 * restart, so check those that might be changeable without a
1600 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1601 /* can't do this while running ... */
1602 restart_required = true;
1605 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1606 /* can't do this while running ... */
1607 restart_required = true;
1613 if (restart_required) {
1614 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1621 if (change_driver && backend->set_driver (get_driver())) {
1622 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1625 if (change_device && backend->set_device_name (get_device_name())) {
1626 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1629 if (change_rate && backend->set_sample_rate (get_rate())) {
1630 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1633 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1634 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1638 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1639 if (backend->set_input_channels (get_input_channels())) {
1640 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1643 if (backend->set_output_channels (get_output_channels())) {
1644 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1648 if (change_latency) {
1649 if (backend->set_systemic_input_latency (get_input_latency())) {
1650 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1653 if (backend->set_systemic_output_latency (get_output_latency())) {
1654 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1660 backend->set_midi_option (get_midi_option());
1664 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1665 if (_measure_midi) {
1666 if (*p == _measure_midi) {
1667 backend->set_midi_device_enabled ((*p)->name, true);
1669 backend->set_midi_device_enabled ((*p)->name, false);
1673 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1674 if (backend->can_set_systemic_midi_latencies()) {
1675 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1676 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1681 if (start || (was_running && restart_required)) {
1682 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1693 EngineControl::post_push ()
1695 /* get a pointer to the current state object, creating one if
1699 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1702 state = save_state ();
1708 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1709 (*i)->active = false;
1712 /* mark this one active (to be used next time the dialog is
1716 state->active = true;
1718 if (_have_control) { // XXX
1719 manage_control_app_sensitivity ();
1722 /* schedule a redisplay of MIDI ports */
1723 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1728 EngineControl::get_rate () const
1730 float r = atof (sample_rate_combo.get_active_text ());
1731 /* the string may have been translated with an abbreviation for
1732 * thousands, so use a crude heuristic to fix this.
1742 EngineControl::get_buffer_size () const
1744 string txt = buffer_size_combo.get_active_text ();
1747 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1755 EngineControl::get_midi_option () const
1757 return midi_option_combo.get_active_text();
1761 EngineControl::get_input_channels() const
1763 if (ARDOUR::Profile->get_mixbus()) {
1764 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1765 if (!backend) return 0;
1766 return backend->input_channels();
1768 return (uint32_t) input_channels_adjustment.get_value();
1772 EngineControl::get_output_channels() const
1774 if (ARDOUR::Profile->get_mixbus()) {
1775 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1776 if (!backend) return 0;
1777 return backend->input_channels();
1779 return (uint32_t) output_channels_adjustment.get_value();
1783 EngineControl::get_input_latency() const
1785 return (uint32_t) input_latency_adjustment.get_value();
1789 EngineControl::get_output_latency() const
1791 return (uint32_t) output_latency_adjustment.get_value();
1795 EngineControl::get_backend () const
1797 return backend_combo.get_active_text ();
1801 EngineControl::get_driver () const
1803 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1804 return driver_combo.get_active_text ();
1811 EngineControl::get_device_name () const
1813 return device_combo.get_active_text ();
1817 EngineControl::control_app_button_clicked ()
1819 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1825 backend->launch_control_app ();
1829 EngineControl::manage_control_app_sensitivity ()
1831 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1837 string appname = backend->control_app_name();
1839 if (appname.empty()) {
1840 control_app_button.set_sensitive (false);
1842 control_app_button.set_sensitive (true);
1847 EngineControl::set_desired_sample_rate (uint32_t sr)
1849 _desired_sample_rate = sr;
1854 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1856 if (page_num == 0) {
1857 cancel_button->set_sensitive (true);
1858 ok_button->set_sensitive (true);
1859 apply_button->set_sensitive (true);
1860 _measure_midi.reset();
1862 cancel_button->set_sensitive (false);
1863 ok_button->set_sensitive (false);
1864 apply_button->set_sensitive (false);
1867 if (page_num == midi_tab) {
1869 refresh_midi_display ();
1872 if (page_num == latency_tab) {
1875 if (ARDOUR::AudioEngine::instance()->running()) {
1876 // TODO - mark as 'stopped for latency
1877 ARDOUR_UI::instance()->disconnect_from_engine ();
1881 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1883 /* save any existing latency values */
1885 uint32_t il = (uint32_t) input_latency.get_value ();
1886 uint32_t ol = (uint32_t) input_latency.get_value ();
1888 /* reset to zero so that our new test instance
1889 will be clean of any existing latency measures.
1891 NB. this should really be done by the backend
1892 when stated for latency measurement.
1895 input_latency.set_value (0);
1896 output_latency.set_value (0);
1898 push_state_to_backend (false);
1902 input_latency.set_value (il);
1903 output_latency.set_value (ol);
1906 // This should be done in push_state_to_backend()
1907 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1908 disable_latency_tab ();
1911 enable_latency_tab ();
1915 end_latency_detection ();
1916 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1921 /* latency measurement */
1924 EngineControl::check_audio_latency_measurement ()
1926 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1928 if (mtdm->resolve () < 0) {
1929 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1933 if (mtdm->err () > 0.3) {
1939 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1941 if (sample_rate == 0) {
1942 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1943 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1947 int frames_total = mtdm->del();
1948 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1950 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1951 _("Detected roundtrip latency: "),
1952 frames_total, frames_total * 1000.0f/sample_rate,
1953 _("Systemic latency: "),
1954 extra, extra * 1000.0f/sample_rate);
1958 if (mtdm->err () > 0.2) {
1960 strcat (buf, _("(signal detection error)"));
1966 strcat (buf, _("(inverted - bad wiring)"));
1970 lm_results.set_markup (string_compose (results_markup, buf));
1973 have_lm_results = true;
1974 end_latency_detection ();
1975 lm_use_button.set_sensitive (true);
1983 EngineControl::check_midi_latency_measurement ()
1985 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1987 if (!mididm->have_signal () || mididm->latency () == 0) {
1988 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1993 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1995 if (sample_rate == 0) {
1996 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1997 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2001 ARDOUR::framecnt_t frames_total = mididm->latency();
2002 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2003 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2004 _("Detected roundtrip latency: "),
2005 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2006 _("Systemic latency: "),
2007 extra, extra * 1000.0f / sample_rate);
2011 if (!mididm->ok ()) {
2013 strcat (buf, _("(averaging)"));
2017 if (mididm->deviation () > 50.0) {
2019 strcat (buf, _("(too large jitter)"));
2021 } else if (mididm->deviation () > 10.0) {
2023 strcat (buf, _("(large jitter)"));
2027 have_lm_results = true;
2028 end_latency_detection ();
2029 lm_use_button.set_sensitive (true);
2030 lm_results.set_markup (string_compose (results_markup, buf));
2032 } else if (mididm->processed () > 400) {
2033 have_lm_results = false;
2034 end_latency_detection ();
2035 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2039 lm_results.set_markup (string_compose (results_markup, buf));
2045 EngineControl::start_latency_detection ()
2047 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2048 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2050 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2051 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2052 if (_measure_midi) {
2053 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2055 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2057 lm_measure_label.set_text (_("Cancel"));
2058 have_lm_results = false;
2059 lm_use_button.set_sensitive (false);
2060 lm_input_channel_combo.set_sensitive (false);
2061 lm_output_channel_combo.set_sensitive (false);
2067 EngineControl::end_latency_detection ()
2069 latency_timeout.disconnect ();
2070 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2071 lm_measure_label.set_text (_("Measure"));
2072 if (!have_lm_results) {
2073 lm_use_button.set_sensitive (false);
2075 lm_input_channel_combo.set_sensitive (true);
2076 lm_output_channel_combo.set_sensitive (true);
2081 EngineControl::latency_button_clicked ()
2084 start_latency_detection ();
2086 end_latency_detection ();
2091 EngineControl::use_latency_button_clicked ()
2093 if (_measure_midi) {
2094 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2098 ARDOUR::framecnt_t frames_total = mididm->latency();
2099 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2100 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2101 _measure_midi->input_latency = one_way;
2102 _measure_midi->output_latency = one_way;
2103 notebook.set_current_page (midi_tab);
2105 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2111 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2112 one_way = std::max (0., one_way);
2114 input_latency_adjustment.set_value (one_way);
2115 output_latency_adjustment.set_value (one_way);
2117 /* back to settings page */
2118 notebook.set_current_page (0);
2124 EngineControl::on_delete_event (GdkEventAny* ev)
2126 if (notebook.get_current_page() == 2) {
2127 /* currently on latency tab - be sure to clean up */
2128 end_latency_detection ();
2130 return ArdourDialog::on_delete_event (ev);
2134 EngineControl::engine_running ()
2136 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2139 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2140 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2142 buffer_size_combo.set_sensitive (true);
2143 sample_rate_combo.set_sensitive (true);
2145 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2146 connect_disconnect_button.show();
2148 started_at_least_once = true;
2152 EngineControl::engine_stopped ()
2154 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2157 buffer_size_combo.set_sensitive (false);
2158 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2159 connect_disconnect_button.show();
2161 sample_rate_combo.set_sensitive (true);
2162 buffer_size_combo.set_sensitive (true);
2166 EngineControl::connect_disconnect_click()
2168 if (ARDOUR::AudioEngine::instance()->running()) {
2169 ARDOUR_UI::instance()->disconnect_from_engine ();
2171 ARDOUR_UI::instance()->reconnect_to_engine ();
2176 EngineControl::calibrate_audio_latency ()
2178 _measure_midi.reset ();
2179 have_lm_results = false;
2180 lm_use_button.set_sensitive (false);
2181 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2182 notebook.set_current_page (latency_tab);
2186 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2189 have_lm_results = false;
2190 lm_use_button.set_sensitive (false);
2191 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2192 notebook.set_current_page (latency_tab);
2196 EngineControl::configure_midi_devices ()
2198 notebook.set_current_page (midi_tab);