2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
50 #include "ardour_ui.h"
51 #include "engine_dialog.h"
52 #include "gui_thread.h"
58 using namespace Gtkmm2ext;
62 static const unsigned int midi_tab = 2;
63 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
65 static const char* results_markup = X_("<span foreground=\"red\" style=\"italic\" size=\"larger\">%1</span>");
67 EngineControl::EngineControl ()
68 : ArdourDialog (_("Audio/MIDI Setup"))
70 , input_latency_adjustment (0, 0, 99999, 1)
71 , input_latency (input_latency_adjustment)
72 , output_latency_adjustment (0, 0, 99999, 1)
73 , output_latency (output_latency_adjustment)
74 , input_channels_adjustment (0, 0, 256, 1)
75 , input_channels (input_channels_adjustment)
76 , output_channels_adjustment (0, 0, 256, 1)
77 , output_channels (output_channels_adjustment)
78 , ports_adjustment (128, 8, 1024, 1, 16)
79 , ports_spinner (ports_adjustment)
80 , control_app_button (_("Device Control Panel"))
81 , midi_devices_button (_("Midi Device Setup"))
82 , lm_measure_label (_("Measure"))
83 , lm_use_button (_("Use results"))
84 , lm_back_button (_("Back to settings ... (ignore results)"))
85 , lm_button_audio (_("Calibrate Audio"))
87 , have_lm_results (false)
89 , midi_back_button (_("Back to settings"))
91 , _desired_sample_rate (0)
92 , started_at_least_once (false)
94 using namespace Notebook_Helpers;
95 vector<string> strings;
97 AttachOptions xopt = AttachOptions (FILL|EXPAND);
100 set_name (X_("AudioMIDISetup"));
102 /* the backend combo is the one thing that is ALWAYS visible */
104 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
106 if (backends.empty()) {
107 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));
109 throw failed_constructor ();
112 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
113 strings.push_back ((*b)->name);
116 set_popdown_strings (backend_combo, strings);
117 backend_combo.set_active_text (strings.front());
118 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
120 /* setup basic packing characteristics for the table used on the main
121 * tab of the notebook
124 basic_packer.set_spacings (6);
125 basic_packer.set_border_width (12);
126 basic_packer.set_homogeneous (false);
130 basic_hbox.pack_start (basic_packer, false, false);
132 /* latency measurement tab */
134 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
137 lm_table.set_row_spacings (12);
138 lm_table.set_col_spacings (6);
139 lm_table.set_homogeneous (false);
141 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
144 Gtk::Label* preamble;
146 preamble = manage (new Label);
147 preamble->set_width_chars (60);
148 preamble->set_line_wrap (true);
149 preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
151 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
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");
262 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
263 manage_control_app_sensitivity ();
265 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
266 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
267 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
269 /* Pick up any existing audio setup configuration, if appropriate */
271 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
273 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
274 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
275 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
279 /* Connect to signals */
281 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
282 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
283 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
284 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
285 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
287 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
288 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
289 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
290 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
293 set_state (*audio_setup);
296 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
300 EngineControl::on_response (int response_id)
302 ArdourDialog::on_response (response_id);
304 switch (response_id) {
306 push_state_to_backend (true);
309 push_state_to_backend (true);
312 case RESPONSE_DELETE_EVENT:
315 ev.type = GDK_BUTTON_PRESS;
317 on_delete_event ((GdkEventAny*) &ev);
326 EngineControl::build_notebook ()
329 AttachOptions xopt = AttachOptions (FILL|EXPAND);
331 /* clear the table */
333 Gtkmm2ext::container_clear (basic_vbox);
334 Gtkmm2ext::container_clear (basic_packer);
336 if (control_app_button.get_parent()) {
337 control_app_button.get_parent()->remove (control_app_button);
340 label = manage (left_aligned_label (_("Audio System:")));
341 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
342 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
344 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
345 lm_button_audio.set_name ("generic button");
348 build_full_control_notebook ();
350 build_no_control_notebook ();
353 basic_vbox.pack_start (basic_hbox, false, false);
356 Gtk::HBox* hpacker = manage (new HBox);
357 hpacker->set_border_width (12);
358 hpacker->pack_start (control_app_button, false, false);
360 control_app_button.show();
361 basic_vbox.pack_start (*hpacker);
364 basic_vbox.show_all ();
368 EngineControl::build_full_control_notebook ()
370 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
373 using namespace Notebook_Helpers;
375 vector<string> strings;
376 AttachOptions xopt = AttachOptions (FILL|EXPAND);
377 int row = 1; // row zero == backend combo
379 /* start packing it up */
381 if (backend->requires_driver_selection()) {
382 label = manage (left_aligned_label (_("Driver:")));
383 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
384 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
388 label = manage (left_aligned_label (_("Device:")));
389 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
390 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
393 label = manage (left_aligned_label (_("Sample rate:")));
394 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
395 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
399 label = manage (left_aligned_label (_("Buffer size:")));
400 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
401 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
402 buffer_size_duration_label.set_alignment (0.0); /* left-align */
403 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
406 input_channels.set_name ("InputChannels");
407 input_channels.set_flags (Gtk::CAN_FOCUS);
408 input_channels.set_digits (0);
409 input_channels.set_wrap (false);
410 output_channels.set_editable (true);
412 label = manage (left_aligned_label (_("Input Channels:")));
413 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
414 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
417 output_channels.set_name ("OutputChannels");
418 output_channels.set_flags (Gtk::CAN_FOCUS);
419 output_channels.set_digits (0);
420 output_channels.set_wrap (false);
421 output_channels.set_editable (true);
423 label = manage (left_aligned_label (_("Output Channels:")));
424 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
425 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
428 input_latency.set_name ("InputLatency");
429 input_latency.set_flags (Gtk::CAN_FOCUS);
430 input_latency.set_digits (0);
431 input_latency.set_wrap (false);
432 input_latency.set_editable (true);
434 label = manage (left_aligned_label (_("Hardware input latency:")));
435 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
436 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
437 label = manage (left_aligned_label (_("samples")));
438 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
441 output_latency.set_name ("OutputLatency");
442 output_latency.set_flags (Gtk::CAN_FOCUS);
443 output_latency.set_digits (0);
444 output_latency.set_wrap (false);
445 output_latency.set_editable (true);
447 label = manage (left_aligned_label (_("Hardware output latency:")));
448 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
449 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
450 label = manage (left_aligned_label (_("samples")));
451 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
453 /* button spans 2 rows */
455 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
458 label = manage (left_aligned_label (_("MIDI System")));
459 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
460 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
461 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
466 EngineControl::build_no_control_notebook ()
468 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
471 using namespace Notebook_Helpers;
473 vector<string> strings;
474 AttachOptions xopt = AttachOptions (FILL|EXPAND);
475 int row = 1; // row zero == backend combo
476 const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
478 label = manage (new Label);
479 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
480 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
483 if (backend->can_change_sample_rate_when_running()) {
484 label = manage (left_aligned_label (_("Sample rate:")));
485 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
486 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
490 if (backend->can_change_buffer_size_when_running()) {
491 label = manage (left_aligned_label (_("Buffer size:")));
492 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
493 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
494 buffer_size_duration_label.set_alignment (0.0); /* left-align */
495 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
499 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
501 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
505 EngineControl::~EngineControl ()
507 ignore_changes = true;
511 EngineControl::disable_latency_tab ()
513 vector<string> empty;
514 set_popdown_strings (lm_output_channel_combo, empty);
515 set_popdown_strings (lm_input_channel_combo, empty);
516 lm_measure_button.set_sensitive (false);
517 lm_use_button.set_sensitive (false);
521 EngineControl::enable_latency_tab ()
523 vector<string> outputs;
524 vector<string> inputs;
526 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
527 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
528 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
530 if (inputs.empty() || outputs.empty()) {
531 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
532 lm_measure_button.set_sensitive (false);
533 notebook.set_current_page (0);
538 if (!outputs.empty()) {
539 set_popdown_strings (lm_output_channel_combo, outputs);
540 lm_output_channel_combo.set_active_text (outputs.front());
541 lm_output_channel_combo.set_sensitive (true);
543 lm_output_channel_combo.set_sensitive (false);
546 if (!inputs.empty()) {
547 set_popdown_strings (lm_input_channel_combo, inputs);
548 lm_input_channel_combo.set_active_text (inputs.front());
549 lm_input_channel_combo.set_sensitive (true);
551 lm_input_channel_combo.set_sensitive (false);
554 lm_measure_button.set_sensitive (true);
558 EngineControl::setup_midi_tab_for_backend ()
560 string backend = backend_combo.get_active_text ();
562 Gtkmm2ext::container_clear (midi_vbox);
564 midi_vbox.set_border_width (12);
565 midi_device_table.set_border_width (12);
567 if (backend == "JACK") {
568 setup_midi_tab_for_jack ();
571 midi_vbox.pack_start (midi_device_table, true, true);
572 midi_vbox.pack_start (midi_back_button, false, false);
573 midi_vbox.show_all ();
577 EngineControl::setup_midi_tab_for_jack ()
582 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
584 device->input_latency = a->get_value();
586 device->output_latency = a->get_value();
591 EngineControl::midi_device_enabled_toggled (GdkEventButton* ev, ArdourButton *b, MidiDeviceSettings device) {
592 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
595 b->set_active (!b->get_active());
596 device->enabled = b->get_active();
597 refresh_midi_display();
602 EngineControl::refresh_midi_display ()
604 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
608 AttachOptions xopt = AttachOptions (FILL|EXPAND);
611 Gtkmm2ext::container_clear (midi_device_table);
613 midi_device_table.set_spacings (6);
615 l = manage (new Label);
616 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
617 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
618 l->set_alignment (0.5, 0.5);
622 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
623 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
624 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
625 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
627 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
628 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
629 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
630 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
633 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
638 bool enabled = (*p)->enabled;
640 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
641 m->set_name ("midi device");
642 m->add_events (Gdk::BUTTON_RELEASE_MASK);
643 m->set_active (enabled);
644 m->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
645 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
647 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
648 s = manage (new Gtk::SpinButton (*a));
649 a->set_value ((*p)->input_latency);
650 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
651 s->set_sensitive (_can_set_midi_latencies && enabled);
652 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
654 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
655 s = manage (new Gtk::SpinButton (*a));
656 a->set_value ((*p)->output_latency);
657 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
658 s->set_sensitive (_can_set_midi_latencies && enabled);
659 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
661 b = manage (new Button (_("Calibrate")));
662 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
663 b->set_sensitive (_can_set_midi_latencies && enabled);
664 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
671 EngineControl::update_sensitivity ()
676 EngineControl::backend_changed ()
678 string backend_name = backend_combo.get_active_text();
679 boost::shared_ptr<ARDOUR::AudioBackend> backend;
681 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
682 /* eh? setting the backend failed... how ? */
686 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
689 setup_midi_tab_for_backend ();
690 _midi_devices.clear();
692 if (backend->requires_driver_selection()) {
693 vector<string> drivers = backend->enumerate_drivers();
694 driver_combo.set_sensitive (true);
696 if (!drivers.empty()) {
698 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
699 set_popdown_strings (driver_combo, drivers);
700 driver_combo.set_active_text (drivers.front());
707 driver_combo.set_sensitive (false);
708 /* this will change the device text which will cause a call to
709 * device changed which will set up parameters
714 vector<string> midi_options = backend->enumerate_midi_options();
716 if (midi_options.size() == 1) {
717 /* only contains the "none" option */
718 midi_option_combo.set_sensitive (false);
721 set_popdown_strings (midi_option_combo, midi_options);
722 midi_option_combo.set_active_text (midi_options.front());
723 midi_option_combo.set_sensitive (true);
725 midi_option_combo.set_sensitive (false);
729 midi_option_changed();
731 started_at_least_once = false;
733 if (!ignore_changes) {
734 maybe_display_saved_state ();
739 EngineControl::print_channel_count (Gtk::SpinButton* sb)
741 uint32_t cnt = (uint32_t) sb->get_value();
743 sb->set_text (_("all available channels"));
746 snprintf (buf, sizeof (buf), "%d", cnt);
753 EngineControl::list_devices ()
755 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
758 /* now fill out devices, mark sample rates, buffer sizes insensitive */
760 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
762 /* NOTE: Ardour currently does not display the "available" field of the
765 * Doing so would require a different GUI widget than the combo
766 * box/popdown that we currently use, since it has no way to list
767 * items that are not selectable. Something more like a popup menu,
768 * which could have unselectable items, would be appropriate.
771 vector<string> available_devices;
773 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
774 available_devices.push_back (i->name);
777 if (!available_devices.empty()) {
779 update_sensitivity ();
782 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
783 set_popdown_strings (device_combo, available_devices);
784 device_combo.set_active_text (available_devices.front());
789 ok_button->set_sensitive (true);
790 apply_button->set_sensitive (true);
793 sample_rate_combo.set_sensitive (false);
794 buffer_size_combo.set_sensitive (false);
795 input_latency.set_sensitive (false);
796 output_latency.set_sensitive (false);
797 input_channels.set_sensitive (false);
798 output_channels.set_sensitive (false);
799 ok_button->set_sensitive (false);
800 apply_button->set_sensitive (false);
805 EngineControl::driver_changed ()
807 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
810 backend->set_driver (driver_combo.get_active_text());
813 if (!ignore_changes) {
814 maybe_display_saved_state ();
819 EngineControl::device_changed ()
822 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
824 string device_name = device_combo.get_active_text ();
828 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
830 /* don't allow programmatic change to combos to cause a
831 recursive call to this method.
841 sr = backend->available_sample_rates (device_name);
844 sr.push_back (8000.0f);
845 sr.push_back (16000.0f);
846 sr.push_back (32000.0f);
847 sr.push_back (44100.0f);
848 sr.push_back (48000.0f);
849 sr.push_back (88200.0f);
850 sr.push_back (96000.0f);
851 sr.push_back (192000.0f);
852 sr.push_back (384000.0f);
855 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
856 s.push_back (rate_as_string (*x));
857 if (*x == _desired_sample_rate) {
863 sample_rate_combo.set_sensitive (true);
864 set_popdown_strings (sample_rate_combo, s);
866 if (desired.empty()) {
867 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
869 sample_rate_combo.set_active_text (desired);
873 sample_rate_combo.set_sensitive (false);
881 bs = backend->available_buffer_sizes (device_name);
882 } else if (backend->can_change_buffer_size_when_running()) {
896 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
897 s.push_back (bufsize_as_string (*x));
901 buffer_size_combo.set_sensitive (true);
902 set_popdown_strings (buffer_size_combo, s);
904 buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
905 show_buffer_duration ();
907 buffer_size_combo.set_sensitive (false);
910 /* XXX theoretically need to set min + max channel counts here
913 manage_control_app_sensitivity ();
916 /* pick up any saved state for this device */
918 if (!ignore_changes) {
919 maybe_display_saved_state ();
924 EngineControl::bufsize_as_string (uint32_t sz)
926 /* Translators: "samples" is always plural here, so no
927 need for plural+singular forms.
930 snprintf (buf, sizeof (buf), _("%u samples"), sz);
935 EngineControl::sample_rate_changed ()
937 /* reset the strings for buffer size to show the correct msec value
938 (reflecting the new sample rate).
941 show_buffer_duration ();
942 if (!ignore_changes) {
949 EngineControl::buffer_size_changed ()
951 show_buffer_duration ();
952 if (!ignore_changes) {
958 EngineControl::show_buffer_duration ()
961 /* buffer sizes - convert from just samples to samples + msecs for
962 * the displayed string
965 string bs_text = buffer_size_combo.get_active_text ();
966 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
967 uint32_t rate = get_rate();
969 /* Translators: "msecs" is ALWAYS plural here, so we do not
970 need singular form as well.
972 /* Developers: note the hard-coding of a double buffered model
973 in the (2 * samples) computation of latency. we always start
974 the audiobackend in this configuration.
977 snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
978 buffer_size_duration_label.set_text (buf);
982 EngineControl::midi_option_changed ()
984 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
987 backend->set_midi_option (get_midi_option());
989 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
991 //_midi_devices.clear(); // TODO merge with state-saved settings..
992 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
993 std::vector<MidiDeviceSettings> new_devices;
995 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
996 MidiDeviceSettings mds = find_midi_device (i->name);
997 if (i->available && !mds) {
998 uint32_t input_latency = 0;
999 uint32_t output_latency = 0;
1000 if (_can_set_midi_latencies) {
1001 input_latency = backend->systemic_midi_input_latency (i->name);
1002 output_latency = backend->systemic_midi_output_latency (i->name);
1004 bool enabled = backend->midi_device_enabled (i->name);
1005 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1006 new_devices.push_back (ptr);
1007 } else if (i->available) {
1008 new_devices.push_back (mds);
1011 _midi_devices = new_devices;
1013 if (_midi_devices.empty()) {
1014 midi_devices_button.set_sensitive (false);
1016 midi_devices_button.set_sensitive (true);
1019 if (!ignore_changes) {
1025 EngineControl::parameter_changed ()
1027 if (!ignore_changes) {
1032 EngineControl::State*
1033 EngineControl::get_matching_state (
1034 const string& backend,
1035 const string& driver,
1036 const string& device)
1038 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1039 if ((*i).backend == backend &&
1040 (*i).driver == driver &&
1041 (*i).device == device) {
1048 EngineControl::State*
1049 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1051 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1054 return get_matching_state (backend_combo.get_active_text(),
1055 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1056 device_combo.get_active_text());
1060 return get_matching_state (backend_combo.get_active_text(),
1062 device_combo.get_active_text());
1065 EngineControl::State*
1066 EngineControl::save_state ()
1068 if (!_have_control) {
1072 bool existing = true;
1073 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1080 store_state (*state);
1083 states.push_back (*state);
1090 EngineControl::store_state (State& state)
1092 state.backend = get_backend ();
1093 state.driver = get_driver ();
1094 state.device = get_device_name ();
1095 state.sample_rate = get_rate ();
1096 state.buffer_size = get_buffer_size ();
1097 state.input_latency = get_input_latency ();
1098 state.output_latency = get_output_latency ();
1099 state.input_channels = get_input_channels ();
1100 state.output_channels = get_output_channels ();
1101 state.midi_option = get_midi_option ();
1102 state.midi_devices = _midi_devices;
1106 EngineControl::maybe_display_saved_state ()
1108 if (!_have_control) {
1112 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1115 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1117 if (!_desired_sample_rate) {
1118 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1120 buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
1121 /* call this explicitly because we're ignoring changes to
1122 the controls at this point.
1124 show_buffer_duration ();
1125 input_latency.set_value (state->input_latency);
1126 output_latency.set_value (state->output_latency);
1128 if (!state->midi_option.empty()) {
1129 midi_option_combo.set_active_text (state->midi_option);
1130 _midi_devices = state->midi_devices;
1136 EngineControl::get_state ()
1138 XMLNode* root = new XMLNode ("AudioMIDISetup");
1141 if (!states.empty()) {
1142 XMLNode* state_nodes = new XMLNode ("EngineStates");
1144 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1146 XMLNode* node = new XMLNode ("State");
1148 node->add_property ("backend", (*i).backend);
1149 node->add_property ("driver", (*i).driver);
1150 node->add_property ("device", (*i).device);
1151 node->add_property ("sample-rate", (*i).sample_rate);
1152 node->add_property ("buffer-size", (*i).buffer_size);
1153 node->add_property ("input-latency", (*i).input_latency);
1154 node->add_property ("output-latency", (*i).output_latency);
1155 node->add_property ("input-channels", (*i).input_channels);
1156 node->add_property ("output-channels", (*i).output_channels);
1157 node->add_property ("active", (*i).active ? "yes" : "no");
1158 node->add_property ("midi-option", (*i).midi_option);
1160 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1161 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i).midi_devices.begin(); p != (*i).midi_devices.end(); ++p) {
1162 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1163 midi_device_stuff->add_property (X_("name"), (*p)->name);
1164 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1165 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1166 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1167 midi_devices->add_child_nocopy (*midi_device_stuff);
1169 node->add_child_nocopy (*midi_devices);
1171 state_nodes->add_child_nocopy (*node);
1174 root->add_child_nocopy (*state_nodes);
1181 EngineControl::set_state (const XMLNode& root)
1183 XMLNodeList clist, cclist;
1184 XMLNodeConstIterator citer, cciter;
1186 XMLNode* grandchild;
1187 XMLProperty* prop = NULL;
1189 if (root.name() != "AudioMIDISetup") {
1193 clist = root.children();
1197 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1201 if (child->name() != "EngineStates") {
1205 cclist = child->children();
1207 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1210 grandchild = *cciter;
1212 if (grandchild->name() != "State") {
1216 if ((prop = grandchild->property ("backend")) == 0) {
1219 state.backend = prop->value ();
1221 if ((prop = grandchild->property ("driver")) == 0) {
1224 state.driver = prop->value ();
1226 if ((prop = grandchild->property ("device")) == 0) {
1229 state.device = prop->value ();
1231 if ((prop = grandchild->property ("sample-rate")) == 0) {
1234 state.sample_rate = atof (prop->value ());
1236 if ((prop = grandchild->property ("buffer-size")) == 0) {
1239 state.buffer_size = atoi (prop->value ());
1241 if ((prop = grandchild->property ("input-latency")) == 0) {
1244 state.input_latency = atoi (prop->value ());
1246 if ((prop = grandchild->property ("output-latency")) == 0) {
1249 state.output_latency = atoi (prop->value ());
1251 if ((prop = grandchild->property ("input-channels")) == 0) {
1254 state.input_channels = atoi (prop->value ());
1256 if ((prop = grandchild->property ("output-channels")) == 0) {
1259 state.output_channels = atoi (prop->value ());
1261 if ((prop = grandchild->property ("active")) == 0) {
1264 state.active = string_is_affirmative (prop->value ());
1266 if ((prop = grandchild->property ("midi-option")) == 0) {
1269 state.midi_option = prop->value ();
1271 state.midi_devices.clear();
1273 if ((midinode = find_named_node (*grandchild, "MIDIDevices")) != 0) {
1274 const XMLNodeList mnc = midinode->children();
1275 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1276 if ((*n)->property (X_("name")) == 0
1277 || (*n)->property (X_("enabled")) == 0
1278 || (*n)->property (X_("input-latency")) == 0
1279 || (*n)->property (X_("output-latency")) == 0
1284 MidiDeviceSettings ptr (new MidiDeviceSetting(
1285 (*n)->property (X_("name"))->value (),
1286 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1287 atoi ((*n)->property (X_("input-latency"))->value ()),
1288 atoi ((*n)->property (X_("output-latency"))->value ())
1290 state.midi_devices.push_back (ptr);
1294 states.push_back (state);
1298 /* now see if there was an active state and switch the setup to it */
1300 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1304 backend_combo.set_active_text ((*i).backend);
1305 driver_combo.set_active_text ((*i).driver);
1306 device_combo.set_active_text ((*i).device);
1307 sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
1308 buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
1309 input_latency.set_value ((*i).input_latency);
1310 output_latency.set_value ((*i).output_latency);
1311 midi_option_combo.set_active_text ((*i).midi_option);
1319 EngineControl::push_state_to_backend (bool start)
1321 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1327 /* figure out what is going to change */
1329 bool restart_required = false;
1330 bool was_running = ARDOUR::AudioEngine::instance()->running();
1331 bool change_driver = false;
1332 bool change_device = false;
1333 bool change_rate = false;
1334 bool change_bufsize = false;
1335 bool change_latency = false;
1336 bool change_channels = false;
1337 bool change_midi = false;
1339 uint32_t ochan = get_output_channels ();
1340 uint32_t ichan = get_input_channels ();
1342 if (_have_control) {
1344 if (started_at_least_once) {
1346 /* we can control the backend */
1348 if (backend->requires_driver_selection()) {
1349 if (get_driver() != backend->driver_name()) {
1350 change_driver = true;
1354 if (get_device_name() != backend->device_name()) {
1355 change_device = true;
1358 if (get_rate() != backend->sample_rate()) {
1362 if (get_buffer_size() != backend->buffer_size()) {
1363 change_bufsize = true;
1366 if (get_midi_option() != backend->midi_option()) {
1370 /* zero-requested channels means "all available" */
1373 ichan = backend->input_channels();
1377 ochan = backend->output_channels();
1380 if (ichan != backend->input_channels()) {
1381 change_channels = true;
1384 if (ochan != backend->output_channels()) {
1385 change_channels = true;
1388 if (get_input_latency() != backend->systemic_input_latency() ||
1389 get_output_latency() != backend->systemic_output_latency()) {
1390 change_latency = true;
1393 /* backend never started, so we have to force a group
1396 change_device = true;
1397 if (backend->requires_driver_selection()) {
1398 change_driver = true;
1401 change_bufsize = true;
1402 change_channels = true;
1403 change_latency = true;
1409 /* we have no control over the backend, meaning that we can
1410 * only possibly change sample rate and buffer size.
1414 if (get_rate() != backend->sample_rate()) {
1415 change_bufsize = true;
1418 if (get_buffer_size() != backend->buffer_size()) {
1419 change_bufsize = true;
1423 if (!_have_control) {
1425 /* We do not have control over the backend, so the best we can
1426 * do is try to change the sample rate and/or bufsize and get
1430 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1434 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1439 backend->set_sample_rate (get_rate());
1442 if (change_bufsize) {
1443 backend->set_buffer_size (get_buffer_size());
1447 if (ARDOUR::AudioEngine::instance()->start ()) {
1448 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1458 /* determine if we need to stop the backend before changing parameters */
1460 if (change_driver || change_device || change_channels || change_latency ||
1461 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1463 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1464 restart_required = true;
1466 restart_required = false;
1471 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1472 /* no changes in any parameters that absolutely require a
1473 * restart, so check those that might be changeable without a
1477 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1478 /* can't do this while running ... */
1479 restart_required = true;
1482 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1483 /* can't do this while running ... */
1484 restart_required = true;
1490 if (restart_required) {
1491 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1498 if (change_driver && backend->set_driver (get_driver())) {
1499 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1502 if (change_device && backend->set_device_name (get_device_name())) {
1503 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1506 if (change_rate && backend->set_sample_rate (get_rate())) {
1507 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1510 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1511 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1515 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1516 if (backend->set_input_channels (get_input_channels())) {
1517 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1520 if (backend->set_output_channels (get_output_channels())) {
1521 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1525 if (change_latency) {
1526 if (backend->set_systemic_input_latency (get_input_latency())) {
1527 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1530 if (backend->set_systemic_output_latency (get_output_latency())) {
1531 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1537 backend->set_midi_option (get_midi_option());
1541 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1542 if (_measure_midi) {
1543 if (*p == _measure_midi) {
1544 backend->set_midi_device_enabled ((*p)->name, true);
1546 backend->set_midi_device_enabled ((*p)->name, false);
1550 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1551 if (backend->can_set_systemic_midi_latencies()) {
1552 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1553 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1558 if (start || (was_running && restart_required)) {
1559 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1570 EngineControl::post_push ()
1572 /* get a pointer to the current state object, creating one if
1576 if (_have_control) {
1577 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1580 state = save_state ();
1586 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1587 (*i).active = false;
1590 /* mark this one active (to be used next time the dialog is
1594 state->active = true;
1596 manage_control_app_sensitivity ();
1599 /* schedule a redisplay of MIDI ports */
1600 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1605 EngineControl::get_rate () const
1607 float r = atof (sample_rate_combo.get_active_text ());
1608 /* the string may have been translated with an abbreviation for
1609 * thousands, so use a crude heuristic to fix this.
1619 EngineControl::get_buffer_size () const
1621 string txt = buffer_size_combo.get_active_text ();
1624 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1632 EngineControl::get_midi_option () const
1634 return midi_option_combo.get_active_text();
1638 EngineControl::get_input_channels() const
1640 return (uint32_t) input_channels_adjustment.get_value();
1644 EngineControl::get_output_channels() const
1646 return (uint32_t) output_channels_adjustment.get_value();
1650 EngineControl::get_input_latency() const
1652 return (uint32_t) input_latency_adjustment.get_value();
1656 EngineControl::get_output_latency() const
1658 return (uint32_t) output_latency_adjustment.get_value();
1662 EngineControl::get_backend () const
1664 return backend_combo.get_active_text ();
1668 EngineControl::get_driver () const
1670 return driver_combo.get_active_text ();
1674 EngineControl::get_device_name () const
1676 return device_combo.get_active_text ();
1680 EngineControl::control_app_button_clicked ()
1682 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1688 backend->launch_control_app ();
1692 EngineControl::manage_control_app_sensitivity ()
1694 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1700 string appname = backend->control_app_name();
1702 if (appname.empty()) {
1703 control_app_button.set_sensitive (false);
1705 control_app_button.set_sensitive (true);
1710 EngineControl::set_desired_sample_rate (uint32_t sr)
1712 _desired_sample_rate = sr;
1717 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1719 if (page_num == 0) {
1720 cancel_button->set_sensitive (true);
1721 ok_button->set_sensitive (true);
1722 apply_button->set_sensitive (true);
1723 _measure_midi.reset();
1725 cancel_button->set_sensitive (false);
1726 ok_button->set_sensitive (false);
1727 apply_button->set_sensitive (false);
1730 if (page_num == midi_tab) {
1732 refresh_midi_display ();
1735 if (page_num == latency_tab) {
1738 if (ARDOUR::AudioEngine::instance()->running()) {
1739 // TODO - mark as 'stopped for latency
1740 ARDOUR_UI::instance()->disconnect_from_engine ();
1744 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1746 /* save any existing latency values */
1748 uint32_t il = (uint32_t) input_latency.get_value ();
1749 uint32_t ol = (uint32_t) input_latency.get_value ();
1751 /* reset to zero so that our new test instance
1752 will be clean of any existing latency measures.
1754 NB. this should really be done by the backend
1755 when stated for latency measurement.
1758 input_latency.set_value (0);
1759 output_latency.set_value (0);
1761 push_state_to_backend (false);
1765 input_latency.set_value (il);
1766 output_latency.set_value (ol);
1769 // This should be done in push_state_to_backend()
1770 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1771 disable_latency_tab ();
1774 enable_latency_tab ();
1778 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1783 /* latency measurement */
1786 EngineControl::check_audio_latency_measurement ()
1788 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1790 if (mtdm->resolve () < 0) {
1791 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1795 if (mtdm->err () > 0.3) {
1801 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1803 if (sample_rate == 0) {
1804 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1805 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1809 int frames_total = mtdm->del();
1810 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1812 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1813 _("Detected roundtrip latency: "),
1814 frames_total, frames_total * 1000.0f/sample_rate,
1815 _("Systemic latency: "),
1816 extra, extra * 1000.0f/sample_rate);
1820 if (mtdm->err () > 0.2) {
1822 strcat (buf, _("(signal detection error)"));
1828 strcat (buf, _("(inverted - bad wiring)"));
1833 end_latency_detection ();
1834 lm_use_button.set_sensitive (true);
1835 have_lm_results = true;
1838 lm_results.set_markup (string_compose (results_markup, buf));
1844 EngineControl::check_midi_latency_measurement ()
1846 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1848 if (!mididm->have_signal () || mididm->latency () == 0) {
1849 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1854 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1856 if (sample_rate == 0) {
1857 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1858 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1862 ARDOUR::framecnt_t frames_total = mididm->latency();
1863 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1864 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1865 _("Detected roundtrip latency: "),
1866 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1867 _("Systemic latency: "),
1868 extra, extra * 1000.0f / sample_rate);
1872 if (!mididm->ok ()) {
1874 strcat (buf, _("(averaging)"));
1878 if (mididm->deviation () > 50.0) {
1880 strcat (buf, _("(too large jitter)"));
1882 } else if (mididm->deviation () > 10.0) {
1884 strcat (buf, _("(large jitter)"));
1888 end_latency_detection ();
1889 lm_use_button.set_sensitive (true);
1890 have_lm_results = true;
1893 lm_results.set_markup (string_compose (results_markup, buf));
1899 EngineControl::start_latency_detection ()
1901 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1902 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1904 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1905 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1906 if (_measure_midi) {
1907 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1909 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1911 lm_measure_label.set_text (_("Cancel"));
1912 have_lm_results = false;
1913 lm_use_button.set_sensitive (false);
1914 lm_input_channel_combo.set_sensitive (false);
1915 lm_output_channel_combo.set_sensitive (false);
1919 lm_back_button_signal.disconnect();
1920 if (_measure_midi) {
1921 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1923 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1928 EngineControl::end_latency_detection ()
1930 latency_timeout.disconnect ();
1931 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1932 lm_measure_label.set_text (_("Measure"));
1933 if (!have_lm_results) {
1934 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1936 lm_use_button.set_sensitive (false);
1938 lm_input_channel_combo.set_sensitive (true);
1939 lm_output_channel_combo.set_sensitive (true);
1944 EngineControl::latency_button_clicked ()
1947 start_latency_detection ();
1949 end_latency_detection ();
1954 EngineControl::use_latency_button_clicked ()
1956 if (_measure_midi) {
1957 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1961 ARDOUR::framecnt_t frames_total = mididm->latency();
1962 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1963 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
1964 _measure_midi->input_latency = one_way;
1965 _measure_midi->output_latency = one_way;
1966 notebook.set_current_page (midi_tab);
1968 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1974 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
1975 one_way = std::max (0., one_way);
1977 input_latency_adjustment.set_value (one_way);
1978 output_latency_adjustment.set_value (one_way);
1980 /* back to settings page */
1981 notebook.set_current_page (0);
1987 EngineControl::on_delete_event (GdkEventAny* ev)
1989 if (notebook.get_current_page() == 2) {
1990 /* currently on latency tab - be sure to clean up */
1991 end_latency_detection ();
1993 return ArdourDialog::on_delete_event (ev);
1997 EngineControl::engine_running ()
1999 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2002 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2003 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2005 buffer_size_combo.set_sensitive (true);
2006 sample_rate_combo.set_sensitive (true);
2008 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2010 started_at_least_once = true;
2014 EngineControl::engine_stopped ()
2016 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2019 buffer_size_combo.set_sensitive (false);
2020 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2022 sample_rate_combo.set_sensitive (true);
2023 buffer_size_combo.set_sensitive (true);
2027 EngineControl::connect_disconnect_click()
2029 if (ARDOUR::AudioEngine::instance()->running()) {
2030 ARDOUR_UI::instance()->disconnect_from_engine ();
2032 ARDOUR_UI::instance()->reconnect_to_engine ();
2037 EngineControl::calibrate_audio_latency ()
2039 _measure_midi.reset();
2040 notebook.set_current_page (latency_tab);
2044 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2047 notebook.set_current_page (latency_tab);
2051 EngineControl::configure_midi_devices ()
2053 notebook.set_current_page (midi_tab);