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) {
1071 State* state = new State;
1072 store_state (*state);
1074 for (StateList::iterator i = states.begin(); i != states.end();) {
1075 if ((*i).backend == state->backend &&
1076 (*i).driver == state->driver &&
1077 (*i).device == state->device) {
1078 i = states.erase(i);
1084 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);
1295 /* remove accumulated duplicates (due to bug in ealier version)
1296 * this can be removed again before release
1298 for (StateList::iterator i = states.begin(); i != states.end();) {
1299 if ((*i).backend == state.backend &&
1300 (*i).driver == state.driver &&
1301 (*i).device == state.device) {
1302 i = states.erase(i);
1309 states.push_back (state);
1313 /* now see if there was an active state and switch the setup to it */
1315 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1319 backend_combo.set_active_text ((*i).backend);
1320 driver_combo.set_active_text ((*i).driver);
1321 device_combo.set_active_text ((*i).device);
1322 sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
1323 buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
1324 input_latency.set_value ((*i).input_latency);
1325 output_latency.set_value ((*i).output_latency);
1326 midi_option_combo.set_active_text ((*i).midi_option);
1334 EngineControl::push_state_to_backend (bool start)
1336 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1342 /* figure out what is going to change */
1344 bool restart_required = false;
1345 bool was_running = ARDOUR::AudioEngine::instance()->running();
1346 bool change_driver = false;
1347 bool change_device = false;
1348 bool change_rate = false;
1349 bool change_bufsize = false;
1350 bool change_latency = false;
1351 bool change_channels = false;
1352 bool change_midi = false;
1354 uint32_t ochan = get_output_channels ();
1355 uint32_t ichan = get_input_channels ();
1357 if (_have_control) {
1359 if (started_at_least_once) {
1361 /* we can control the backend */
1363 if (backend->requires_driver_selection()) {
1364 if (get_driver() != backend->driver_name()) {
1365 change_driver = true;
1369 if (get_device_name() != backend->device_name()) {
1370 change_device = true;
1373 if (get_rate() != backend->sample_rate()) {
1377 if (get_buffer_size() != backend->buffer_size()) {
1378 change_bufsize = true;
1381 if (get_midi_option() != backend->midi_option()) {
1385 /* zero-requested channels means "all available" */
1388 ichan = backend->input_channels();
1392 ochan = backend->output_channels();
1395 if (ichan != backend->input_channels()) {
1396 change_channels = true;
1399 if (ochan != backend->output_channels()) {
1400 change_channels = true;
1403 if (get_input_latency() != backend->systemic_input_latency() ||
1404 get_output_latency() != backend->systemic_output_latency()) {
1405 change_latency = true;
1408 /* backend never started, so we have to force a group
1411 change_device = true;
1412 if (backend->requires_driver_selection()) {
1413 change_driver = true;
1416 change_bufsize = true;
1417 change_channels = true;
1418 change_latency = true;
1424 /* we have no control over the backend, meaning that we can
1425 * only possibly change sample rate and buffer size.
1429 if (get_rate() != backend->sample_rate()) {
1430 change_bufsize = true;
1433 if (get_buffer_size() != backend->buffer_size()) {
1434 change_bufsize = true;
1438 if (!_have_control) {
1440 /* We do not have control over the backend, so the best we can
1441 * do is try to change the sample rate and/or bufsize and get
1445 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1449 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1454 backend->set_sample_rate (get_rate());
1457 if (change_bufsize) {
1458 backend->set_buffer_size (get_buffer_size());
1462 if (ARDOUR::AudioEngine::instance()->start ()) {
1463 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1473 /* determine if we need to stop the backend before changing parameters */
1475 if (change_driver || change_device || change_channels || change_latency ||
1476 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1478 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1479 restart_required = true;
1481 restart_required = false;
1486 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1487 /* no changes in any parameters that absolutely require a
1488 * restart, so check those that might be changeable without a
1492 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1493 /* can't do this while running ... */
1494 restart_required = true;
1497 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1498 /* can't do this while running ... */
1499 restart_required = true;
1505 if (restart_required) {
1506 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1513 if (change_driver && backend->set_driver (get_driver())) {
1514 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1517 if (change_device && backend->set_device_name (get_device_name())) {
1518 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1521 if (change_rate && backend->set_sample_rate (get_rate())) {
1522 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1525 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1526 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1530 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1531 if (backend->set_input_channels (get_input_channels())) {
1532 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1535 if (backend->set_output_channels (get_output_channels())) {
1536 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1540 if (change_latency) {
1541 if (backend->set_systemic_input_latency (get_input_latency())) {
1542 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1545 if (backend->set_systemic_output_latency (get_output_latency())) {
1546 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1552 backend->set_midi_option (get_midi_option());
1556 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1557 if (_measure_midi) {
1558 if (*p == _measure_midi) {
1559 backend->set_midi_device_enabled ((*p)->name, true);
1561 backend->set_midi_device_enabled ((*p)->name, false);
1565 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1566 if (backend->can_set_systemic_midi_latencies()) {
1567 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1568 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1573 if (start || (was_running && restart_required)) {
1574 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1585 EngineControl::post_push ()
1587 /* get a pointer to the current state object, creating one if
1591 if (_have_control) {
1592 State* state = get_saved_state_for_currently_displayed_backend_and_device ();
1595 state = save_state ();
1601 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1602 (*i).active = false;
1605 /* mark this one active (to be used next time the dialog is
1609 state->active = true;
1611 manage_control_app_sensitivity ();
1614 /* schedule a redisplay of MIDI ports */
1615 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1620 EngineControl::get_rate () const
1622 float r = atof (sample_rate_combo.get_active_text ());
1623 /* the string may have been translated with an abbreviation for
1624 * thousands, so use a crude heuristic to fix this.
1634 EngineControl::get_buffer_size () const
1636 string txt = buffer_size_combo.get_active_text ();
1639 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1647 EngineControl::get_midi_option () const
1649 return midi_option_combo.get_active_text();
1653 EngineControl::get_input_channels() const
1655 return (uint32_t) input_channels_adjustment.get_value();
1659 EngineControl::get_output_channels() const
1661 return (uint32_t) output_channels_adjustment.get_value();
1665 EngineControl::get_input_latency() const
1667 return (uint32_t) input_latency_adjustment.get_value();
1671 EngineControl::get_output_latency() const
1673 return (uint32_t) output_latency_adjustment.get_value();
1677 EngineControl::get_backend () const
1679 return backend_combo.get_active_text ();
1683 EngineControl::get_driver () const
1685 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1686 return driver_combo.get_active_text ();
1693 EngineControl::get_device_name () const
1695 return device_combo.get_active_text ();
1699 EngineControl::control_app_button_clicked ()
1701 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1707 backend->launch_control_app ();
1711 EngineControl::manage_control_app_sensitivity ()
1713 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1719 string appname = backend->control_app_name();
1721 if (appname.empty()) {
1722 control_app_button.set_sensitive (false);
1724 control_app_button.set_sensitive (true);
1729 EngineControl::set_desired_sample_rate (uint32_t sr)
1731 _desired_sample_rate = sr;
1736 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1738 if (page_num == 0) {
1739 cancel_button->set_sensitive (true);
1740 ok_button->set_sensitive (true);
1741 apply_button->set_sensitive (true);
1742 _measure_midi.reset();
1744 cancel_button->set_sensitive (false);
1745 ok_button->set_sensitive (false);
1746 apply_button->set_sensitive (false);
1749 if (page_num == midi_tab) {
1751 refresh_midi_display ();
1754 if (page_num == latency_tab) {
1757 if (ARDOUR::AudioEngine::instance()->running()) {
1758 // TODO - mark as 'stopped for latency
1759 ARDOUR_UI::instance()->disconnect_from_engine ();
1763 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1765 /* save any existing latency values */
1767 uint32_t il = (uint32_t) input_latency.get_value ();
1768 uint32_t ol = (uint32_t) input_latency.get_value ();
1770 /* reset to zero so that our new test instance
1771 will be clean of any existing latency measures.
1773 NB. this should really be done by the backend
1774 when stated for latency measurement.
1777 input_latency.set_value (0);
1778 output_latency.set_value (0);
1780 push_state_to_backend (false);
1784 input_latency.set_value (il);
1785 output_latency.set_value (ol);
1788 // This should be done in push_state_to_backend()
1789 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1790 disable_latency_tab ();
1793 enable_latency_tab ();
1797 ARDOUR::AudioEngine::instance()->stop_latency_detection();
1802 /* latency measurement */
1805 EngineControl::check_audio_latency_measurement ()
1807 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1809 if (mtdm->resolve () < 0) {
1810 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1814 if (mtdm->err () > 0.3) {
1820 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1822 if (sample_rate == 0) {
1823 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1824 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1828 int frames_total = mtdm->del();
1829 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1831 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
1832 _("Detected roundtrip latency: "),
1833 frames_total, frames_total * 1000.0f/sample_rate,
1834 _("Systemic latency: "),
1835 extra, extra * 1000.0f/sample_rate);
1839 if (mtdm->err () > 0.2) {
1841 strcat (buf, _("(signal detection error)"));
1847 strcat (buf, _("(inverted - bad wiring)"));
1852 end_latency_detection ();
1853 lm_use_button.set_sensitive (true);
1854 have_lm_results = true;
1857 lm_results.set_markup (string_compose (results_markup, buf));
1863 EngineControl::check_midi_latency_measurement ()
1865 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1867 if (!mididm->have_signal () || mididm->latency () == 0) {
1868 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1873 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
1875 if (sample_rate == 0) {
1876 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1877 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1881 ARDOUR::framecnt_t frames_total = mididm->latency();
1882 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1883 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
1884 _("Detected roundtrip latency: "),
1885 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
1886 _("Systemic latency: "),
1887 extra, extra * 1000.0f / sample_rate);
1891 if (!mididm->ok ()) {
1893 strcat (buf, _("(averaging)"));
1897 if (mididm->deviation () > 50.0) {
1899 strcat (buf, _("(too large jitter)"));
1901 } else if (mididm->deviation () > 10.0) {
1903 strcat (buf, _("(large jitter)"));
1907 end_latency_detection ();
1908 lm_use_button.set_sensitive (true);
1909 have_lm_results = true;
1912 lm_results.set_markup (string_compose (results_markup, buf));
1918 EngineControl::start_latency_detection ()
1920 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
1921 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
1923 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
1924 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
1925 if (_measure_midi) {
1926 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
1928 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
1930 lm_measure_label.set_text (_("Cancel"));
1931 have_lm_results = false;
1932 lm_use_button.set_sensitive (false);
1933 lm_input_channel_combo.set_sensitive (false);
1934 lm_output_channel_combo.set_sensitive (false);
1938 lm_back_button_signal.disconnect();
1939 if (_measure_midi) {
1940 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
1942 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
1947 EngineControl::end_latency_detection ()
1949 latency_timeout.disconnect ();
1950 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
1951 lm_measure_label.set_text (_("Measure"));
1952 if (!have_lm_results) {
1953 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
1955 lm_use_button.set_sensitive (false);
1957 lm_input_channel_combo.set_sensitive (true);
1958 lm_output_channel_combo.set_sensitive (true);
1963 EngineControl::latency_button_clicked ()
1966 start_latency_detection ();
1968 end_latency_detection ();
1973 EngineControl::use_latency_button_clicked ()
1975 if (_measure_midi) {
1976 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
1980 ARDOUR::framecnt_t frames_total = mididm->latency();
1981 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1982 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
1983 _measure_midi->input_latency = one_way;
1984 _measure_midi->output_latency = one_way;
1985 notebook.set_current_page (midi_tab);
1987 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1993 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
1994 one_way = std::max (0., one_way);
1996 input_latency_adjustment.set_value (one_way);
1997 output_latency_adjustment.set_value (one_way);
1999 /* back to settings page */
2000 notebook.set_current_page (0);
2006 EngineControl::on_delete_event (GdkEventAny* ev)
2008 if (notebook.get_current_page() == 2) {
2009 /* currently on latency tab - be sure to clean up */
2010 end_latency_detection ();
2012 return ArdourDialog::on_delete_event (ev);
2016 EngineControl::engine_running ()
2018 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2021 buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
2022 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2024 buffer_size_combo.set_sensitive (true);
2025 sample_rate_combo.set_sensitive (true);
2027 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2029 started_at_least_once = true;
2033 EngineControl::engine_stopped ()
2035 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2038 buffer_size_combo.set_sensitive (false);
2039 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2041 sample_rate_combo.set_sensitive (true);
2042 buffer_size_combo.set_sensitive (true);
2046 EngineControl::connect_disconnect_click()
2048 if (ARDOUR::AudioEngine::instance()->running()) {
2049 ARDOUR_UI::instance()->disconnect_from_engine ();
2051 ARDOUR_UI::instance()->reconnect_to_engine ();
2056 EngineControl::calibrate_audio_latency ()
2058 _measure_midi.reset();
2059 notebook.set_current_page (latency_tab);
2063 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2066 notebook.set_current_page (latency_tab);
2070 EngineControl::configure_midi_devices ()
2072 notebook.set_current_page (midi_tab);