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.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 get_action_area()->pack_start (engine_status);
252 engine_status.show();
254 /* need a special function to print "all available channels" when the
255 * channel counts hit zero.
258 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
259 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
261 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
262 midi_devices_button.set_sensitive (false);
263 midi_devices_button.set_name ("generic button");
264 midi_devices_button.set_can_focus(true);
266 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
267 manage_control_app_sensitivity ();
269 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
270 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
271 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
273 /* Pick up any existing audio setup configuration, if appropriate */
275 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
277 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
278 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
279 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
282 set_state (*audio_setup);
284 backend_combo.set_active_text (strings.front());
288 /* ignore: don't save state */
289 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
293 /* Connect to signals */
295 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
296 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
297 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
298 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
299 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
301 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
302 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
303 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
304 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
306 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
308 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
309 connect_disconnect_button.set_no_show_all();
314 EngineControl::on_show ()
316 ArdourDialog::on_show ();
318 ok_button->grab_focus();
322 EngineControl::on_response (int response_id)
324 ArdourDialog::on_response (response_id);
326 switch (response_id) {
328 push_state_to_backend (true);
331 push_state_to_backend (true);
334 case RESPONSE_DELETE_EVENT:
337 ev.type = GDK_BUTTON_PRESS;
339 on_delete_event ((GdkEventAny*) &ev);
348 EngineControl::build_notebook ()
351 AttachOptions xopt = AttachOptions (FILL|EXPAND);
353 /* clear the table */
355 Gtkmm2ext::container_clear (basic_vbox);
356 Gtkmm2ext::container_clear (basic_packer);
358 if (control_app_button.get_parent()) {
359 control_app_button.get_parent()->remove (control_app_button);
362 label = manage (left_aligned_label (_("Audio System:")));
363 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
364 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
366 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
367 lm_button_audio.set_name ("generic button");
368 lm_button_audio.set_can_focus(true);
371 build_full_control_notebook ();
373 build_no_control_notebook ();
376 basic_vbox.pack_start (basic_hbox, false, false);
379 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
380 basic_vbox.show_all ();
385 EngineControl::build_full_control_notebook ()
387 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
390 using namespace Notebook_Helpers;
392 vector<string> strings;
393 AttachOptions xopt = AttachOptions (FILL|EXPAND);
394 int row = 1; // row zero == backend combo
396 /* start packing it up */
398 if (backend->requires_driver_selection()) {
399 label = manage (left_aligned_label (_("Driver:")));
400 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
401 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
405 label = manage (left_aligned_label (_("Device:")));
406 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
407 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
410 label = manage (left_aligned_label (_("Sample rate:")));
411 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
412 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
416 label = manage (left_aligned_label (_("Buffer size:")));
417 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
418 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
419 buffer_size_duration_label.set_alignment (0.0); /* left-align */
420 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
422 /* button spans 2 rows */
424 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
427 input_channels.set_name ("InputChannels");
428 input_channels.set_flags (Gtk::CAN_FOCUS);
429 input_channels.set_digits (0);
430 input_channels.set_wrap (false);
431 output_channels.set_editable (true);
433 if (!ARDOUR::Profile->get_mixbus()) {
434 label = manage (left_aligned_label (_("Input Channels:")));
435 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
436 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
440 output_channels.set_name ("OutputChannels");
441 output_channels.set_flags (Gtk::CAN_FOCUS);
442 output_channels.set_digits (0);
443 output_channels.set_wrap (false);
444 output_channels.set_editable (true);
446 if (!ARDOUR::Profile->get_mixbus()) {
447 label = manage (left_aligned_label (_("Output Channels:")));
448 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
449 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
453 input_latency.set_name ("InputLatency");
454 input_latency.set_flags (Gtk::CAN_FOCUS);
455 input_latency.set_digits (0);
456 input_latency.set_wrap (false);
457 input_latency.set_editable (true);
459 label = manage (left_aligned_label (_("Hardware input latency:")));
460 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
461 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
462 label = manage (left_aligned_label (_("samples")));
463 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
466 output_latency.set_name ("OutputLatency");
467 output_latency.set_flags (Gtk::CAN_FOCUS);
468 output_latency.set_digits (0);
469 output_latency.set_wrap (false);
470 output_latency.set_editable (true);
472 label = manage (left_aligned_label (_("Hardware output latency:")));
473 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
474 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
475 label = manage (left_aligned_label (_("samples")));
476 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
478 /* button spans 2 rows */
480 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
483 label = manage (left_aligned_label (_("MIDI System")));
484 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
485 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
486 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
491 EngineControl::build_no_control_notebook ()
493 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
496 using namespace Notebook_Helpers;
498 vector<string> strings;
499 AttachOptions xopt = AttachOptions (FILL|EXPAND);
500 int row = 1; // row zero == backend combo
501 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
503 label = manage (new Label);
504 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
505 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
508 if (backend->can_change_sample_rate_when_running()) {
509 label = manage (left_aligned_label (_("Sample rate:")));
510 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
511 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
515 if (backend->can_change_buffer_size_when_running()) {
516 label = manage (left_aligned_label (_("Buffer size:")));
517 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
518 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
519 buffer_size_duration_label.set_alignment (0.0); /* left-align */
520 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
524 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
528 EngineControl::~EngineControl ()
530 ignore_changes = true;
534 EngineControl::disable_latency_tab ()
536 vector<string> empty;
537 set_popdown_strings (lm_output_channel_combo, empty);
538 set_popdown_strings (lm_input_channel_combo, empty);
539 lm_measure_button.set_sensitive (false);
540 lm_use_button.set_sensitive (false);
544 EngineControl::enable_latency_tab ()
546 vector<string> outputs;
547 vector<string> inputs;
549 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
550 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
551 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
553 if (!ARDOUR::AudioEngine::instance()->running()) {
554 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
555 notebook.set_current_page (0);
559 else if (inputs.empty() || outputs.empty()) {
560 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
561 notebook.set_current_page (0);
566 lm_back_button_signal.disconnect();
568 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
571 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
575 set_popdown_strings (lm_output_channel_combo, outputs);
576 lm_output_channel_combo.set_active_text (outputs.front());
577 lm_output_channel_combo.set_sensitive (true);
579 set_popdown_strings (lm_input_channel_combo, inputs);
580 lm_input_channel_combo.set_active_text (inputs.front());
581 lm_input_channel_combo.set_sensitive (true);
583 lm_measure_button.set_sensitive (true);
587 EngineControl::setup_midi_tab_for_backend ()
589 string backend = backend_combo.get_active_text ();
591 Gtkmm2ext::container_clear (midi_vbox);
593 midi_vbox.set_border_width (12);
594 midi_device_table.set_border_width (12);
596 if (backend == "JACK") {
597 setup_midi_tab_for_jack ();
600 midi_vbox.pack_start (midi_device_table, true, true);
601 midi_vbox.pack_start (midi_back_button, false, false);
602 midi_vbox.show_all ();
606 EngineControl::setup_midi_tab_for_jack ()
611 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
613 device->input_latency = a->get_value();
615 device->output_latency = a->get_value();
620 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
621 b->set_active (!b->get_active());
622 device->enabled = b->get_active();
623 refresh_midi_display(device->name);
627 EngineControl::refresh_midi_display (std::string focus)
629 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
633 AttachOptions xopt = AttachOptions (FILL|EXPAND);
636 Gtkmm2ext::container_clear (midi_device_table);
638 midi_device_table.set_spacings (6);
640 l = manage (new Label);
641 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
642 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
643 l->set_alignment (0.5, 0.5);
647 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
648 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
649 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
650 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
652 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
653 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
654 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
655 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
658 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
663 bool enabled = (*p)->enabled;
665 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
666 m->set_name ("midi device");
667 m->set_can_focus (Gtk::CAN_FOCUS);
668 m->add_events (Gdk::BUTTON_RELEASE_MASK);
669 m->set_active (enabled);
670 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
671 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
672 if ((*p)->name == focus) {
676 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
677 s = manage (new Gtk::SpinButton (*a));
678 a->set_value ((*p)->input_latency);
679 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
680 s->set_sensitive (_can_set_midi_latencies && enabled);
681 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
683 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
684 s = manage (new Gtk::SpinButton (*a));
685 a->set_value ((*p)->output_latency);
686 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
687 s->set_sensitive (_can_set_midi_latencies && enabled);
688 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
690 b = manage (new Button (_("Calibrate")));
691 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
692 b->set_sensitive (_can_set_midi_latencies && enabled);
693 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
700 EngineControl::update_sensitivity ()
705 EngineControl::backend_changed ()
707 string backend_name = backend_combo.get_active_text();
708 boost::shared_ptr<ARDOUR::AudioBackend> backend;
710 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
711 /* eh? setting the backend failed... how ? */
715 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
718 setup_midi_tab_for_backend ();
719 _midi_devices.clear();
721 if (backend->requires_driver_selection()) {
722 vector<string> drivers = backend->enumerate_drivers();
723 driver_combo.set_sensitive (true);
725 if (!drivers.empty()) {
727 string current_driver;
728 current_driver = backend->driver_name ();
730 // driver might not have been set yet
731 if (current_driver == "") {
732 current_driver = driver_combo.get_active_text ();
733 if (current_driver == "")
734 // driver has never been set, make sure it's not blank
735 current_driver = drivers.front ();
738 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
739 set_popdown_strings (driver_combo, drivers);
740 driver_combo.set_active_text (current_driver);
747 driver_combo.set_sensitive (false);
748 /* this will change the device text which will cause a call to
749 * device changed which will set up parameters
754 vector<string> midi_options = backend->enumerate_midi_options();
756 if (midi_options.size() == 1) {
757 /* only contains the "none" option */
758 midi_option_combo.set_sensitive (false);
761 set_popdown_strings (midi_option_combo, midi_options);
762 midi_option_combo.set_active_text (midi_options.front());
763 midi_option_combo.set_sensitive (true);
765 midi_option_combo.set_sensitive (false);
769 connect_disconnect_button.hide();
771 midi_option_changed();
773 started_at_least_once = false;
775 if (!ignore_changes) {
776 maybe_display_saved_state ();
781 EngineControl::print_channel_count (Gtk::SpinButton* sb)
783 if (ARDOUR::Profile->get_mixbus()) {
784 cout << "Mixbus crash trap. sb->get_value(): " << sb->get_value();
788 uint32_t cnt = (uint32_t) sb->get_value();
790 sb->set_text (_("all available channels"));
793 snprintf (buf, sizeof (buf), "%d", cnt);
800 EngineControl::list_devices ()
802 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
805 /* now fill out devices, mark sample rates, buffer sizes insensitive */
807 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
809 /* NOTE: Ardour currently does not display the "available" field of the
812 * Doing so would require a different GUI widget than the combo
813 * box/popdown that we currently use, since it has no way to list
814 * items that are not selectable. Something more like a popup menu,
815 * which could have unselectable items, would be appropriate.
818 vector<string> available_devices;
820 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
821 available_devices.push_back (i->name);
824 if (!available_devices.empty()) {
826 update_sensitivity ();
829 string current_device, found_device;
830 current_device = device_combo.get_active_text ();
831 if (current_device == "") {
832 current_device = backend->device_name ();
835 // Make sure that the active text is still relevant for this
836 // device (it might only be relevant to the previous device!!)
837 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
838 if (*i == current_device)
839 found_device = current_device;
841 if (found_device == "")
842 // device has never been set (or was not relevant
843 // for this backend) Let's make sure it's not blank
844 current_device = available_devices.front ();
846 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
847 set_popdown_strings (device_combo, available_devices);
849 device_combo.set_active_text (current_device);
854 input_latency.set_sensitive (true);
855 output_latency.set_sensitive (true);
856 input_channels.set_sensitive (true);
857 output_channels.set_sensitive (true);
859 ok_button->set_sensitive (true);
860 apply_button->set_sensitive (true);
863 device_combo.clear();
864 sample_rate_combo.set_sensitive (false);
865 buffer_size_combo.set_sensitive (false);
866 input_latency.set_sensitive (false);
867 output_latency.set_sensitive (false);
868 input_channels.set_sensitive (false);
869 output_channels.set_sensitive (false);
871 ok_button->set_sensitive (false);
872 apply_button->set_sensitive (false);
874 ok_button->set_sensitive (true);
875 apply_button->set_sensitive (true);
876 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
877 sample_rate_combo.set_sensitive (true);
879 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
880 buffer_size_combo.set_sensitive (true);
888 EngineControl::driver_changed ()
890 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
893 backend->set_driver (driver_combo.get_active_text());
896 if (!ignore_changes) {
897 maybe_display_saved_state ();
902 EngineControl::device_changed ()
905 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
907 string device_name = device_combo.get_active_text ();
910 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
911 backend->set_device_name(device_name);
914 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
916 /* don't allow programmatic change to combos to cause a
917 recursive call to this method.
927 sr = backend->available_sample_rates (device_name);
930 sr.push_back (8000.0f);
931 sr.push_back (16000.0f);
932 sr.push_back (32000.0f);
933 sr.push_back (44100.0f);
934 sr.push_back (48000.0f);
935 sr.push_back (88200.0f);
936 sr.push_back (96000.0f);
937 sr.push_back (192000.0f);
938 sr.push_back (384000.0f);
941 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
942 s.push_back (rate_as_string (*x));
943 if (*x == _desired_sample_rate) {
949 sample_rate_combo.set_sensitive (true);
950 set_popdown_strings (sample_rate_combo, s);
952 if (desired.empty()) {
953 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
955 sample_rate_combo.set_active_text (desired);
959 sample_rate_combo.set_sensitive (false);
967 bs = backend->available_buffer_sizes (device_name);
968 } else if (backend->can_change_buffer_size_when_running()) {
982 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
983 s.push_back (bufsize_as_string (*x));
987 buffer_size_combo.set_sensitive (true);
988 set_popdown_strings (buffer_size_combo, s);
990 uint32_t period = backend->buffer_size();
992 period = backend->default_buffer_size(device_name);
994 buffer_size_combo.set_active_text (bufsize_as_string (period));
995 show_buffer_duration ();
997 buffer_size_combo.set_sensitive (false);
1000 /* XXX theoretically need to set min + max channel counts here
1003 manage_control_app_sensitivity ();
1006 /* pick up any saved state for this device */
1008 if (!ignore_changes) {
1009 maybe_display_saved_state ();
1014 EngineControl::bufsize_as_string (uint32_t sz)
1016 /* Translators: "samples" is always plural here, so no
1017 need for plural+singular forms.
1020 snprintf (buf, sizeof (buf), _("%u samples"), sz);
1025 EngineControl::sample_rate_changed ()
1027 /* reset the strings for buffer size to show the correct msec value
1028 (reflecting the new sample rate).
1031 show_buffer_duration ();
1032 if (!ignore_changes) {
1039 EngineControl::buffer_size_changed ()
1041 show_buffer_duration ();
1042 if (!ignore_changes) {
1048 EngineControl::show_buffer_duration ()
1051 /* buffer sizes - convert from just samples to samples + msecs for
1052 * the displayed string
1055 string bs_text = buffer_size_combo.get_active_text ();
1056 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1057 uint32_t rate = get_rate();
1059 /* Developers: note the hard-coding of a double buffered model
1060 in the (2 * samples) computation of latency. we always start
1061 the audiobackend in this configuration.
1063 /* note to jack1 developers: ardour also always starts the engine
1064 * in async mode (no jack2 --sync option) which adds an extra cycle
1065 * of latency with jack2 (and *3 would be correct)
1066 * The value can also be wrong if jackd is started externally..
1068 * At the time of writing the ALSA backend always uses double-buffering *2,
1069 * The Dummy backend *1, and who knows what ASIO really does :)
1071 * So just display the period size, that's also what
1072 * ARDOUR_UI::update_sample_rate() does for the status bar.
1073 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1074 * but still, that's the buffer period, not [round-trip] latency)
1077 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1078 buffer_size_duration_label.set_text (buf);
1082 EngineControl::midi_option_changed ()
1084 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1087 backend->set_midi_option (get_midi_option());
1089 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1091 //_midi_devices.clear(); // TODO merge with state-saved settings..
1092 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1093 std::vector<MidiDeviceSettings> new_devices;
1095 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1096 MidiDeviceSettings mds = find_midi_device (i->name);
1097 if (i->available && !mds) {
1098 uint32_t input_latency = 0;
1099 uint32_t output_latency = 0;
1100 if (_can_set_midi_latencies) {
1101 input_latency = backend->systemic_midi_input_latency (i->name);
1102 output_latency = backend->systemic_midi_output_latency (i->name);
1104 bool enabled = backend->midi_device_enabled (i->name);
1105 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1106 new_devices.push_back (ptr);
1107 } else if (i->available) {
1108 new_devices.push_back (mds);
1111 _midi_devices = new_devices;
1113 if (_midi_devices.empty()) {
1114 midi_devices_button.set_sensitive (false);
1116 midi_devices_button.set_sensitive (true);
1119 if (!ignore_changes) {
1125 EngineControl::parameter_changed ()
1127 if (!ignore_changes) {
1132 EngineControl::State
1133 EngineControl::get_matching_state (
1134 const string& backend,
1135 const string& driver,
1136 const string& device)
1138 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1139 if ((*i)->backend == backend &&
1140 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1148 EngineControl::State
1149 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1151 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1154 return get_matching_state (backend_combo.get_active_text(),
1155 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1156 device_combo.get_active_text());
1160 return get_matching_state (backend_combo.get_active_text(),
1162 device_combo.get_active_text());
1165 EngineControl::State
1166 EngineControl::save_state ()
1170 if (!_have_control) {
1171 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1175 state.reset(new StateStruct);
1176 state->backend = get_backend ();
1178 state.reset(new StateStruct);
1179 store_state (state);
1182 for (StateList::iterator i = states.begin(); i != states.end();) {
1183 if ((*i)->backend == state->backend &&
1184 (*i)->driver == state->driver &&
1185 (*i)->device == state->device) {
1186 i = states.erase(i);
1192 states.push_back (state);
1198 EngineControl::store_state (State state)
1200 state->backend = get_backend ();
1201 state->driver = get_driver ();
1202 state->device = get_device_name ();
1203 state->sample_rate = get_rate ();
1204 state->buffer_size = get_buffer_size ();
1205 state->input_latency = get_input_latency ();
1206 state->output_latency = get_output_latency ();
1207 state->input_channels = get_input_channels ();
1208 state->output_channels = get_output_channels ();
1209 state->midi_option = get_midi_option ();
1210 state->midi_devices = _midi_devices;
1214 EngineControl::maybe_display_saved_state ()
1216 if (!_have_control) {
1220 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1223 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1225 if (!_desired_sample_rate) {
1226 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1228 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1229 /* call this explicitly because we're ignoring changes to
1230 the controls at this point.
1232 show_buffer_duration ();
1233 input_latency.set_value (state->input_latency);
1234 output_latency.set_value (state->output_latency);
1236 if (!state->midi_option.empty()) {
1237 midi_option_combo.set_active_text (state->midi_option);
1238 _midi_devices = state->midi_devices;
1244 EngineControl::get_state ()
1246 XMLNode* root = new XMLNode ("AudioMIDISetup");
1249 if (!states.empty()) {
1250 XMLNode* state_nodes = new XMLNode ("EngineStates");
1252 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1254 XMLNode* node = new XMLNode ("State");
1256 node->add_property ("backend", (*i)->backend);
1257 node->add_property ("driver", (*i)->driver);
1258 node->add_property ("device", (*i)->device);
1259 node->add_property ("sample-rate", (*i)->sample_rate);
1260 node->add_property ("buffer-size", (*i)->buffer_size);
1261 node->add_property ("input-latency", (*i)->input_latency);
1262 node->add_property ("output-latency", (*i)->output_latency);
1263 node->add_property ("input-channels", (*i)->input_channels);
1264 node->add_property ("output-channels", (*i)->output_channels);
1265 node->add_property ("active", (*i)->active ? "yes" : "no");
1266 node->add_property ("midi-option", (*i)->midi_option);
1268 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1269 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1270 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1271 midi_device_stuff->add_property (X_("name"), (*p)->name);
1272 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1273 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1274 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1275 midi_devices->add_child_nocopy (*midi_device_stuff);
1277 node->add_child_nocopy (*midi_devices);
1279 state_nodes->add_child_nocopy (*node);
1282 root->add_child_nocopy (*state_nodes);
1289 EngineControl::set_state (const XMLNode& root)
1291 XMLNodeList clist, cclist;
1292 XMLNodeConstIterator citer, cciter;
1294 XMLNode* grandchild;
1295 XMLProperty* prop = NULL;
1297 if (root.name() != "AudioMIDISetup") {
1301 clist = root.children();
1305 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1309 if (child->name() != "EngineStates") {
1313 cclist = child->children();
1315 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1316 State state (new StateStruct);
1318 grandchild = *cciter;
1320 if (grandchild->name() != "State") {
1324 if ((prop = grandchild->property ("backend")) == 0) {
1327 state->backend = prop->value ();
1329 if ((prop = grandchild->property ("driver")) == 0) {
1332 state->driver = prop->value ();
1334 if ((prop = grandchild->property ("device")) == 0) {
1337 state->device = prop->value ();
1339 if ((prop = grandchild->property ("sample-rate")) == 0) {
1342 state->sample_rate = atof (prop->value ());
1344 if ((prop = grandchild->property ("buffer-size")) == 0) {
1347 state->buffer_size = atoi (prop->value ());
1349 if ((prop = grandchild->property ("input-latency")) == 0) {
1352 state->input_latency = atoi (prop->value ());
1354 if ((prop = grandchild->property ("output-latency")) == 0) {
1357 state->output_latency = atoi (prop->value ());
1359 if ((prop = grandchild->property ("input-channels")) == 0) {
1362 state->input_channels = atoi (prop->value ());
1364 if ((prop = grandchild->property ("output-channels")) == 0) {
1367 state->output_channels = atoi (prop->value ());
1369 if ((prop = grandchild->property ("active")) == 0) {
1372 state->active = string_is_affirmative (prop->value ());
1374 if ((prop = grandchild->property ("midi-option")) == 0) {
1377 state->midi_option = prop->value ();
1379 state->midi_devices.clear();
1381 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1382 const XMLNodeList mnc = midinode->children();
1383 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1384 if ((*n)->property (X_("name")) == 0
1385 || (*n)->property (X_("enabled")) == 0
1386 || (*n)->property (X_("input-latency")) == 0
1387 || (*n)->property (X_("output-latency")) == 0
1392 MidiDeviceSettings ptr (new MidiDeviceSetting(
1393 (*n)->property (X_("name"))->value (),
1394 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1395 atoi ((*n)->property (X_("input-latency"))->value ()),
1396 atoi ((*n)->property (X_("output-latency"))->value ())
1398 state->midi_devices.push_back (ptr);
1403 /* remove accumulated duplicates (due to bug in ealier version)
1404 * this can be removed again before release
1406 for (StateList::iterator i = states.begin(); i != states.end();) {
1407 if ((*i)->backend == state->backend &&
1408 (*i)->driver == state->driver &&
1409 (*i)->device == state->device) {
1410 i = states.erase(i);
1417 states.push_back (state);
1421 /* now see if there was an active state and switch the setup to it */
1423 // purge states of backend that are not available in this built
1424 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1425 vector<std::string> backend_names;
1427 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1428 backend_names.push_back((*i)->name);
1430 for (StateList::iterator i = states.begin(); i != states.end();) {
1431 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1432 i = states.erase(i);
1438 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1442 backend_combo.set_active_text ((*i)->backend);
1443 driver_combo.set_active_text ((*i)->driver);
1444 device_combo.set_active_text ((*i)->device);
1445 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1446 buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
1447 input_latency.set_value ((*i)->input_latency);
1448 output_latency.set_value ((*i)->output_latency);
1449 midi_option_combo.set_active_text ((*i)->midi_option);
1457 EngineControl::push_state_to_backend (bool start)
1459 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1465 /* figure out what is going to change */
1467 bool restart_required = false;
1468 bool was_running = ARDOUR::AudioEngine::instance()->running();
1469 bool change_driver = false;
1470 bool change_device = false;
1471 bool change_rate = false;
1472 bool change_bufsize = false;
1473 bool change_latency = false;
1474 bool change_channels = false;
1475 bool change_midi = false;
1477 uint32_t ochan = get_output_channels ();
1478 uint32_t ichan = get_input_channels ();
1480 if (_have_control) {
1482 if (started_at_least_once) {
1484 /* we can control the backend */
1486 if (backend->requires_driver_selection()) {
1487 if (get_driver() != backend->driver_name()) {
1488 change_driver = true;
1492 if (get_device_name() != backend->device_name()) {
1493 change_device = true;
1496 if (get_rate() != backend->sample_rate()) {
1500 if (get_buffer_size() != backend->buffer_size()) {
1501 change_bufsize = true;
1504 if (get_midi_option() != backend->midi_option()) {
1508 /* zero-requested channels means "all available" */
1511 ichan = backend->input_channels();
1515 ochan = backend->output_channels();
1518 if (ichan != backend->input_channels()) {
1519 change_channels = true;
1522 if (ochan != backend->output_channels()) {
1523 change_channels = true;
1526 if (get_input_latency() != backend->systemic_input_latency() ||
1527 get_output_latency() != backend->systemic_output_latency()) {
1528 change_latency = true;
1531 /* backend never started, so we have to force a group
1534 change_device = true;
1535 if (backend->requires_driver_selection()) {
1536 change_driver = true;
1539 change_bufsize = true;
1540 change_channels = true;
1541 change_latency = true;
1547 /* we have no control over the backend, meaning that we can
1548 * only possibly change sample rate and buffer size.
1552 if (get_rate() != backend->sample_rate()) {
1553 change_bufsize = true;
1556 if (get_buffer_size() != backend->buffer_size()) {
1557 change_bufsize = true;
1561 if (!_have_control) {
1563 /* We do not have control over the backend, so the best we can
1564 * do is try to change the sample rate and/or bufsize and get
1568 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1572 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1577 backend->set_sample_rate (get_rate());
1580 if (change_bufsize) {
1581 backend->set_buffer_size (get_buffer_size());
1585 if (ARDOUR::AudioEngine::instance()->start ()) {
1586 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1596 /* determine if we need to stop the backend before changing parameters */
1598 if (change_driver || change_device || change_channels || change_latency ||
1599 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1601 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1602 restart_required = true;
1604 restart_required = false;
1609 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1610 /* no changes in any parameters that absolutely require a
1611 * restart, so check those that might be changeable without a
1615 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1616 /* can't do this while running ... */
1617 restart_required = true;
1620 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1621 /* can't do this while running ... */
1622 restart_required = true;
1628 if (restart_required) {
1629 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1636 if (change_driver && backend->set_driver (get_driver())) {
1637 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1640 if (change_device && backend->set_device_name (get_device_name())) {
1641 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1644 if (change_rate && backend->set_sample_rate (get_rate())) {
1645 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1648 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1649 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1653 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1654 if (backend->set_input_channels (get_input_channels())) {
1655 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1658 if (backend->set_output_channels (get_output_channels())) {
1659 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1663 if (change_latency) {
1664 if (backend->set_systemic_input_latency (get_input_latency())) {
1665 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1668 if (backend->set_systemic_output_latency (get_output_latency())) {
1669 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1675 backend->set_midi_option (get_midi_option());
1679 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1680 if (_measure_midi) {
1681 if (*p == _measure_midi) {
1682 backend->set_midi_device_enabled ((*p)->name, true);
1684 backend->set_midi_device_enabled ((*p)->name, false);
1688 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1689 if (backend->can_set_systemic_midi_latencies()) {
1690 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1691 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1696 if (start || (was_running && restart_required)) {
1697 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1708 EngineControl::post_push ()
1710 /* get a pointer to the current state object, creating one if
1714 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1717 state = save_state ();
1723 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1724 (*i)->active = false;
1727 /* mark this one active (to be used next time the dialog is
1731 state->active = true;
1733 if (_have_control) { // XXX
1734 manage_control_app_sensitivity ();
1737 /* schedule a redisplay of MIDI ports */
1738 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1743 EngineControl::get_rate () const
1745 float r = atof (sample_rate_combo.get_active_text ());
1746 /* the string may have been translated with an abbreviation for
1747 * thousands, so use a crude heuristic to fix this.
1757 EngineControl::get_buffer_size () const
1759 string txt = buffer_size_combo.get_active_text ();
1762 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1770 EngineControl::get_midi_option () const
1772 return midi_option_combo.get_active_text();
1776 EngineControl::get_input_channels() const
1778 if (ARDOUR::Profile->get_mixbus()) {
1779 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1780 if (!backend) return 0;
1781 return backend->input_channels();
1783 return (uint32_t) input_channels_adjustment.get_value();
1787 EngineControl::get_output_channels() const
1789 if (ARDOUR::Profile->get_mixbus()) {
1790 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1791 if (!backend) return 0;
1792 return backend->input_channels();
1794 return (uint32_t) output_channels_adjustment.get_value();
1798 EngineControl::get_input_latency() const
1800 return (uint32_t) input_latency_adjustment.get_value();
1804 EngineControl::get_output_latency() const
1806 return (uint32_t) output_latency_adjustment.get_value();
1810 EngineControl::get_backend () const
1812 return backend_combo.get_active_text ();
1816 EngineControl::get_driver () const
1818 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1819 return driver_combo.get_active_text ();
1826 EngineControl::get_device_name () const
1828 return device_combo.get_active_text ();
1832 EngineControl::control_app_button_clicked ()
1834 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1840 backend->launch_control_app ();
1844 EngineControl::manage_control_app_sensitivity ()
1846 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1852 string appname = backend->control_app_name();
1854 if (appname.empty()) {
1855 control_app_button.set_sensitive (false);
1857 control_app_button.set_sensitive (true);
1862 EngineControl::set_desired_sample_rate (uint32_t sr)
1864 _desired_sample_rate = sr;
1869 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1871 if (page_num == 0) {
1872 cancel_button->set_sensitive (true);
1873 ok_button->set_sensitive (true);
1874 apply_button->set_sensitive (true);
1875 _measure_midi.reset();
1877 cancel_button->set_sensitive (false);
1878 ok_button->set_sensitive (false);
1879 apply_button->set_sensitive (false);
1882 if (page_num == midi_tab) {
1884 refresh_midi_display ();
1887 if (page_num == latency_tab) {
1890 if (ARDOUR::AudioEngine::instance()->running()) {
1891 // TODO - mark as 'stopped for latency
1892 ARDOUR_UI::instance()->disconnect_from_engine ();
1896 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1898 /* save any existing latency values */
1900 uint32_t il = (uint32_t) input_latency.get_value ();
1901 uint32_t ol = (uint32_t) input_latency.get_value ();
1903 /* reset to zero so that our new test instance
1904 will be clean of any existing latency measures.
1906 NB. this should really be done by the backend
1907 when stated for latency measurement.
1910 input_latency.set_value (0);
1911 output_latency.set_value (0);
1913 push_state_to_backend (false);
1917 input_latency.set_value (il);
1918 output_latency.set_value (ol);
1921 // This should be done in push_state_to_backend()
1922 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1923 disable_latency_tab ();
1926 enable_latency_tab ();
1930 end_latency_detection ();
1931 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1936 /* latency measurement */
1939 EngineControl::check_audio_latency_measurement ()
1941 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1943 if (mtdm->resolve () < 0) {
1944 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1948 if (mtdm->err () > 0.3) {
1954 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1956 if (sample_rate == 0) {
1957 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1958 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1962 int frames_total = mtdm->del();
1963 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1965 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1966 _("Detected roundtrip latency: "),
1967 frames_total, frames_total * 1000.0f/sample_rate,
1968 _("Systemic latency: "),
1969 extra, extra * 1000.0f/sample_rate);
1973 if (mtdm->err () > 0.2) {
1975 strcat (buf, _("(signal detection error)"));
1981 strcat (buf, _("(inverted - bad wiring)"));
1985 lm_results.set_markup (string_compose (results_markup, buf));
1988 have_lm_results = true;
1989 end_latency_detection ();
1990 lm_use_button.set_sensitive (true);
1998 EngineControl::check_midi_latency_measurement ()
2000 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2002 if (!mididm->have_signal () || mididm->latency () == 0) {
2003 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2008 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2010 if (sample_rate == 0) {
2011 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2012 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2016 ARDOUR::framecnt_t frames_total = mididm->latency();
2017 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2018 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2019 _("Detected roundtrip latency: "),
2020 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2021 _("Systemic latency: "),
2022 extra, extra * 1000.0f / sample_rate);
2026 if (!mididm->ok ()) {
2028 strcat (buf, _("(averaging)"));
2032 if (mididm->deviation () > 50.0) {
2034 strcat (buf, _("(too large jitter)"));
2036 } else if (mididm->deviation () > 10.0) {
2038 strcat (buf, _("(large jitter)"));
2042 have_lm_results = true;
2043 end_latency_detection ();
2044 lm_use_button.set_sensitive (true);
2045 lm_results.set_markup (string_compose (results_markup, buf));
2047 } else if (mididm->processed () > 400) {
2048 have_lm_results = false;
2049 end_latency_detection ();
2050 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2054 lm_results.set_markup (string_compose (results_markup, buf));
2060 EngineControl::start_latency_detection ()
2062 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2063 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2065 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2066 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2067 if (_measure_midi) {
2068 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2070 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2072 lm_measure_label.set_text (_("Cancel"));
2073 have_lm_results = false;
2074 lm_use_button.set_sensitive (false);
2075 lm_input_channel_combo.set_sensitive (false);
2076 lm_output_channel_combo.set_sensitive (false);
2082 EngineControl::end_latency_detection ()
2084 latency_timeout.disconnect ();
2085 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2086 lm_measure_label.set_text (_("Measure"));
2087 if (!have_lm_results) {
2088 lm_use_button.set_sensitive (false);
2090 lm_input_channel_combo.set_sensitive (true);
2091 lm_output_channel_combo.set_sensitive (true);
2096 EngineControl::latency_button_clicked ()
2099 start_latency_detection ();
2101 end_latency_detection ();
2106 EngineControl::use_latency_button_clicked ()
2108 if (_measure_midi) {
2109 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2113 ARDOUR::framecnt_t frames_total = mididm->latency();
2114 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2115 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2116 _measure_midi->input_latency = one_way;
2117 _measure_midi->output_latency = one_way;
2118 notebook.set_current_page (midi_tab);
2120 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2126 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2127 one_way = std::max (0., one_way);
2129 input_latency_adjustment.set_value (one_way);
2130 output_latency_adjustment.set_value (one_way);
2132 /* back to settings page */
2133 notebook.set_current_page (0);
2139 EngineControl::on_delete_event (GdkEventAny* ev)
2141 if (notebook.get_current_page() == 2) {
2142 /* currently on latency tab - be sure to clean up */
2143 end_latency_detection ();
2145 return ArdourDialog::on_delete_event (ev);
2149 EngineControl::engine_running ()
2151 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2154 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2155 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2157 buffer_size_combo.set_sensitive (true);
2158 sample_rate_combo.set_sensitive (true);
2160 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2161 connect_disconnect_button.show();
2163 started_at_least_once = true;
2164 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2168 EngineControl::engine_stopped ()
2170 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2173 buffer_size_combo.set_sensitive (false);
2174 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2175 connect_disconnect_button.show();
2177 sample_rate_combo.set_sensitive (true);
2178 buffer_size_combo.set_sensitive (true);
2179 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2183 EngineControl::connect_disconnect_click()
2185 if (ARDOUR::AudioEngine::instance()->running()) {
2186 ARDOUR_UI::instance()->disconnect_from_engine ();
2188 ARDOUR_UI::instance()->reconnect_to_engine ();
2193 EngineControl::calibrate_audio_latency ()
2195 _measure_midi.reset ();
2196 have_lm_results = false;
2197 lm_use_button.set_sensitive (false);
2198 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2199 notebook.set_current_page (latency_tab);
2203 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2206 have_lm_results = false;
2207 lm_use_button.set_sensitive (false);
2208 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2209 notebook.set_current_page (latency_tab);
2213 EngineControl::configure_midi_devices ()
2215 notebook.set_current_page (midi_tab);