2 Copyright (C) 2010 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <boost/scoped_ptr.hpp>
28 #include <gtkmm/messagedialog.h>
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
44 #include "ardour/rc_configuration.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
60 using namespace Gtkmm2ext;
63 using namespace ARDOUR_UI_UTILS;
65 static const unsigned int midi_tab = 2;
66 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
68 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
70 EngineControl::EngineControl ()
71 : ArdourDialog (_("Audio/MIDI Setup"))
74 , input_latency_adjustment (0, 0, 99999, 1)
75 , input_latency (input_latency_adjustment)
76 , output_latency_adjustment (0, 0, 99999, 1)
77 , output_latency (output_latency_adjustment)
78 , input_channels_adjustment (0, 0, 256, 1)
79 , input_channels (input_channels_adjustment)
80 , output_channels_adjustment (0, 0, 256, 1)
81 , output_channels (output_channels_adjustment)
82 , ports_adjustment (128, 8, 1024, 1, 16)
83 , ports_spinner (ports_adjustment)
84 , control_app_button (_("Device Control Panel"))
85 , midi_devices_button (_("Midi Device Setup"))
86 , lm_measure_label (_("Measure"))
87 , lm_use_button (_("Use results"))
88 , lm_back_button (_("Back to settings ... (ignore results)"))
89 , lm_button_audio (_("Calibrate Audio"))
91 , have_lm_results (false)
93 , midi_back_button (_("Back to settings"))
95 , _desired_sample_rate (0)
96 , started_at_least_once (false)
97 , queue_device_changed (false)
99 using namespace Notebook_Helpers;
100 vector<string> backend_names;
102 AttachOptions xopt = AttachOptions (FILL|EXPAND);
105 set_name (X_("AudioMIDISetup"));
107 /* the backend combo is the one thing that is ALWAYS visible */
109 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
111 if (backends.empty()) {
112 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));
114 throw failed_constructor ();
117 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
118 backend_names.push_back ((*b)->name);
121 set_popdown_strings (backend_combo, backend_names);
123 /* setup basic packing characteristics for the table used on the main
124 * tab of the notebook
127 basic_packer.set_spacings (6);
128 basic_packer.set_border_width (12);
129 basic_packer.set_homogeneous (false);
133 basic_hbox.pack_start (basic_packer, false, false);
135 /* latency measurement tab */
137 lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
140 lm_table.set_row_spacings (12);
141 lm_table.set_col_spacings (6);
142 lm_table.set_homogeneous (false);
144 lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
147 lm_preamble.set_width_chars (60);
148 lm_preamble.set_line_wrap (true);
149 lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
151 lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
154 Gtk::Label* preamble;
155 preamble = manage (new Label);
156 preamble->set_width_chars (60);
157 preamble->set_line_wrap (true);
158 preamble->set_markup (_("Select two channels below and connect them using a cable."));
160 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
163 label = manage (new Label (_("Output channel")));
164 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
166 Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
167 misc_align->add (lm_output_channel_combo);
168 lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
171 label = manage (new Label (_("Input channel")));
172 lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 misc_align = manage (new Alignment (0.0, 0.5));
175 misc_align->add (lm_input_channel_combo);
176 lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
179 lm_measure_label.set_padding (10, 10);
180 lm_measure_button.add (lm_measure_label);
181 lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
182 lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
183 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
185 lm_use_button.set_sensitive (false);
187 /* Increase the default spacing around the labels of these three
193 if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
194 l->set_padding (10, 10);
197 if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
198 l->set_padding (10, 10);
201 preamble = manage (new Label);
202 preamble->set_width_chars (60);
203 preamble->set_line_wrap (true);
204 preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
205 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
208 preamble = manage (new Label);
209 preamble->set_width_chars (60);
210 preamble->set_line_wrap (true);
211 preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
212 lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
214 ++row; // skip a row in the table
215 ++row; // skip a row in the table
217 lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
219 ++row; // skip a row in the table
220 ++row; // skip a row in the table
222 lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
223 lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
224 lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
228 lm_vbox.set_border_width (12);
229 lm_vbox.pack_start (lm_table, false, false);
231 midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
235 notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
236 notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
237 notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
238 notebook.set_border_width (12);
240 notebook.set_show_tabs (false);
241 notebook.show_all ();
243 notebook.set_name ("SettingsNotebook");
245 /* packup the notebook */
247 get_vbox()->set_border_width (12);
248 get_vbox()->pack_start (notebook);
250 get_action_area()->pack_start (engine_status);
251 engine_status.show();
253 /* need a special function to print "all available channels" when the
254 * channel counts hit zero.
257 input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
258 output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
260 midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
261 midi_devices_button.set_sensitive (false);
262 midi_devices_button.set_name ("generic button");
263 midi_devices_button.set_can_focus(true);
265 control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
266 manage_control_app_sensitivity ();
268 cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
269 apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
270 ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
272 /* Pick up any existing audio setup configuration, if appropriate */
274 XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
276 ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
277 ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
278 ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
279 ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
282 set_state (*audio_setup);
285 if (backend_combo.get_active_text().empty()) {
286 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
287 backend_combo.set_active_text (backend_names.front());
292 /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
293 if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
294 backend_combo.set_active_text (backend_names.back());
295 /* ignore: don't save state */
296 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
301 /* Connect to signals */
303 backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
304 driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
305 sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
306 buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
307 device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
308 midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
310 input_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::input_device_changed));
311 output_device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::output_device_changed));
313 input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
314 output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
315 input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
316 output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
318 notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
320 connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
321 connect_disconnect_button.set_no_show_all();
326 EngineControl::on_show ()
328 ArdourDialog::on_show ();
329 if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
330 // re-check _have_control (jackd running) see #6041
334 ok_button->grab_focus();
338 EngineControl::on_response (int response_id)
340 ArdourDialog::on_response (response_id);
342 switch (response_id) {
344 push_state_to_backend (true);
347 #ifdef PLATFORM_WINDOWS
348 // For some reason we don't understand, 'hide()'
349 // needs to get called first in Windows
352 // But if there's no session open, this can produce
353 // a long gap when nothing appears to be happening.
354 // Let's show the splash image while we're waiting.
355 if ( !ARDOUR_COMMAND_LINE::no_splash ) {
356 if ( ARDOUR_UI::instance() ) {
357 if ( !ARDOUR_UI::instance()->session_loaded ) {
358 ARDOUR_UI::instance()->show_splash();
362 push_state_to_backend (true);
365 push_state_to_backend (true);
369 case RESPONSE_DELETE_EVENT:
372 ev.type = GDK_BUTTON_PRESS;
374 on_delete_event ((GdkEventAny*) &ev);
383 EngineControl::build_notebook ()
386 AttachOptions xopt = AttachOptions (FILL|EXPAND);
388 /* clear the table */
390 Gtkmm2ext::container_clear (basic_vbox);
391 Gtkmm2ext::container_clear (basic_packer);
393 if (control_app_button.get_parent()) {
394 control_app_button.get_parent()->remove (control_app_button);
397 label = manage (left_aligned_label (_("Audio System:")));
398 basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
399 basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
401 lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
402 lm_button_audio.set_name ("generic button");
403 lm_button_audio.set_can_focus(true);
406 build_full_control_notebook ();
408 build_no_control_notebook ();
411 basic_vbox.pack_start (basic_hbox, false, false);
414 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
415 basic_vbox.show_all ();
420 EngineControl::build_full_control_notebook ()
422 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
425 using namespace Notebook_Helpers;
427 vector<string> strings;
428 AttachOptions xopt = AttachOptions (FILL|EXPAND);
429 int row = 1; // row zero == backend combo
431 /* start packing it up */
433 if (backend->requires_driver_selection()) {
434 label = manage (left_aligned_label (_("Driver:")));
435 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
436 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
440 if (backend->use_separate_input_and_output_devices()) {
441 label = manage (left_aligned_label (_("Input Device:")));
442 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
443 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
445 label = manage (left_aligned_label (_("Output Device:")));
446 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
447 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
449 // reset so it isn't used in state comparisons
450 device_combo.set_active_text ("");
452 label = manage (left_aligned_label (_("Device:")));
453 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
454 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
456 // reset these so they don't get used in state comparisons
457 input_device_combo.set_active_text ("");
458 output_device_combo.set_active_text ("");
461 label = manage (left_aligned_label (_("Sample rate:")));
462 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
463 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
467 label = manage (left_aligned_label (_("Buffer size:")));
468 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
469 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
470 buffer_size_duration_label.set_alignment (0.0); /* left-align */
471 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
473 /* button spans 2 rows */
475 basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
478 input_channels.set_name ("InputChannels");
479 input_channels.set_flags (Gtk::CAN_FOCUS);
480 input_channels.set_digits (0);
481 input_channels.set_wrap (false);
482 output_channels.set_editable (true);
484 if (!ARDOUR::Profile->get_mixbus()) {
485 label = manage (left_aligned_label (_("Input Channels:")));
486 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
487 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
491 output_channels.set_name ("OutputChannels");
492 output_channels.set_flags (Gtk::CAN_FOCUS);
493 output_channels.set_digits (0);
494 output_channels.set_wrap (false);
495 output_channels.set_editable (true);
497 if (!ARDOUR::Profile->get_mixbus()) {
498 label = manage (left_aligned_label (_("Output Channels:")));
499 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
500 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
504 input_latency.set_name ("InputLatency");
505 input_latency.set_flags (Gtk::CAN_FOCUS);
506 input_latency.set_digits (0);
507 input_latency.set_wrap (false);
508 input_latency.set_editable (true);
510 label = manage (left_aligned_label (_("Hardware input latency:")));
511 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
512 basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
513 label = manage (left_aligned_label (_("samples")));
514 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
517 output_latency.set_name ("OutputLatency");
518 output_latency.set_flags (Gtk::CAN_FOCUS);
519 output_latency.set_digits (0);
520 output_latency.set_wrap (false);
521 output_latency.set_editable (true);
523 label = manage (left_aligned_label (_("Hardware output latency:")));
524 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
525 basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
526 label = manage (left_aligned_label (_("samples")));
527 basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
529 /* button spans 2 rows */
531 basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
534 label = manage (left_aligned_label (_("MIDI System:")));
535 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
536 basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
537 basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
542 EngineControl::build_no_control_notebook ()
544 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
547 using namespace Notebook_Helpers;
549 vector<string> strings;
550 AttachOptions xopt = AttachOptions (FILL|EXPAND);
551 int row = 1; // row zero == backend combo
552 const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
554 label = manage (new Label);
555 label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
556 basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
559 if (backend->can_change_sample_rate_when_running()) {
560 label = manage (left_aligned_label (_("Sample rate:")));
561 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
562 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
566 if (backend->can_change_buffer_size_when_running()) {
567 label = manage (left_aligned_label (_("Buffer size:")));
568 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
569 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
570 buffer_size_duration_label.set_alignment (0.0); /* left-align */
571 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
575 basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
579 EngineControl::~EngineControl ()
581 ignore_changes = true;
585 EngineControl::disable_latency_tab ()
587 vector<string> empty;
588 set_popdown_strings (lm_output_channel_combo, empty);
589 set_popdown_strings (lm_input_channel_combo, empty);
590 lm_measure_button.set_sensitive (false);
591 lm_use_button.set_sensitive (false);
595 EngineControl::enable_latency_tab ()
597 vector<string> outputs;
598 vector<string> inputs;
600 ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
601 ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
602 ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
604 if (!ARDOUR::AudioEngine::instance()->running()) {
605 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
606 notebook.set_current_page (0);
610 else if (inputs.empty() || outputs.empty()) {
611 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
612 notebook.set_current_page (0);
617 lm_back_button_signal.disconnect();
619 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
622 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
626 set_popdown_strings (lm_output_channel_combo, outputs);
627 lm_output_channel_combo.set_active_text (outputs.front());
628 lm_output_channel_combo.set_sensitive (true);
630 set_popdown_strings (lm_input_channel_combo, inputs);
631 lm_input_channel_combo.set_active_text (inputs.front());
632 lm_input_channel_combo.set_sensitive (true);
634 lm_measure_button.set_sensitive (true);
638 EngineControl::setup_midi_tab_for_backend ()
640 string backend = backend_combo.get_active_text ();
642 Gtkmm2ext::container_clear (midi_vbox);
644 midi_vbox.set_border_width (12);
645 midi_device_table.set_border_width (12);
647 if (backend == "JACK") {
648 setup_midi_tab_for_jack ();
651 midi_vbox.pack_start (midi_device_table, true, true);
652 midi_vbox.pack_start (midi_back_button, false, false);
653 midi_vbox.show_all ();
657 EngineControl::setup_midi_tab_for_jack ()
662 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
664 device->input_latency = a->get_value();
666 device->output_latency = a->get_value();
671 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
672 b->set_active (!b->get_active());
673 device->enabled = b->get_active();
674 refresh_midi_display(device->name);
678 EngineControl::refresh_midi_display (std::string focus)
680 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
684 AttachOptions xopt = AttachOptions (FILL|EXPAND);
687 Gtkmm2ext::container_clear (midi_device_table);
689 midi_device_table.set_spacings (6);
691 l = manage (new Label);
692 l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
693 midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
694 l->set_alignment (0.5, 0.5);
698 l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
699 midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
700 l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
701 midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
703 l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
704 midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
705 l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
706 midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
709 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
714 bool enabled = (*p)->enabled;
716 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
717 m->set_name ("midi device");
718 m->set_can_focus (Gtk::CAN_FOCUS);
719 m->add_events (Gdk::BUTTON_RELEASE_MASK);
720 m->set_active (enabled);
721 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
722 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
723 if ((*p)->name == focus) {
727 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
728 s = manage (new Gtk::SpinButton (*a));
729 a->set_value ((*p)->input_latency);
730 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
731 s->set_sensitive (_can_set_midi_latencies && enabled);
732 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
734 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
735 s = manage (new Gtk::SpinButton (*a));
736 a->set_value ((*p)->output_latency);
737 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
738 s->set_sensitive (_can_set_midi_latencies && enabled);
739 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
741 b = manage (new Button (_("Calibrate")));
742 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
743 b->set_sensitive (_can_set_midi_latencies && enabled);
744 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
751 EngineControl::update_sensitivity ()
756 EngineControl::backend_changed ()
758 string backend_name = backend_combo.get_active_text();
759 boost::shared_ptr<ARDOUR::AudioBackend> backend;
761 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
762 /* eh? setting the backend failed... how ? */
763 /* A: stale config contains a backend that does not exist in current build */
767 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
770 setup_midi_tab_for_backend ();
771 _midi_devices.clear();
773 if (backend->requires_driver_selection()) {
774 vector<string> drivers = backend->enumerate_drivers();
775 driver_combo.set_sensitive (true);
777 if (!drivers.empty()) {
779 string current_driver;
780 current_driver = backend->driver_name ();
782 // driver might not have been set yet
783 if (current_driver == "") {
784 current_driver = driver_combo.get_active_text ();
785 if (current_driver == "")
786 // driver has never been set, make sure it's not blank
787 current_driver = drivers.front ();
790 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
791 set_popdown_strings (driver_combo, drivers);
792 driver_combo.set_active_text (current_driver);
799 driver_combo.set_sensitive (false);
800 /* this will change the device text which will cause a call to
801 * device changed which will set up parameters
806 vector<string> midi_options = backend->enumerate_midi_options();
808 if (midi_options.size() == 1) {
809 /* only contains the "none" option */
810 midi_option_combo.set_sensitive (false);
813 set_popdown_strings (midi_option_combo, midi_options);
814 midi_option_combo.set_active_text (midi_options.front());
815 midi_option_combo.set_sensitive (true);
817 midi_option_combo.set_sensitive (false);
821 connect_disconnect_button.hide();
823 midi_option_changed();
825 started_at_least_once = false;
827 if (!ignore_changes) {
828 maybe_display_saved_state ();
833 EngineControl::print_channel_count (Gtk::SpinButton* sb)
835 if (ARDOUR::Profile->get_mixbus()) {
839 uint32_t cnt = (uint32_t) sb->get_value();
841 sb->set_text (_("all available channels"));
844 snprintf (buf, sizeof (buf), "%d", cnt);
851 EngineControl::set_driver_popdown_strings ()
853 string backend_name = backend_combo.get_active_text();
854 boost::shared_ptr<ARDOUR::AudioBackend> backend;
856 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
857 /* eh? setting the backend failed... how ? */
858 /* A: stale config contains a backend that does not exist in current build */
862 vector<string> drivers = backend->enumerate_drivers();
863 set_popdown_strings (driver_combo, drivers);
867 // @return true if there are devices available
869 EngineControl::set_device_popdown_strings ()
871 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
872 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
874 /* NOTE: Ardour currently does not display the "available" field of the
877 * Doing so would require a different GUI widget than the combo
878 * box/popdown that we currently use, since it has no way to list
879 * items that are not selectable. Something more like a popup menu,
880 * which could have unselectable items, would be appropriate.
883 vector<string> available_devices;
885 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
886 available_devices.push_back (i->name);
890 if (!available_devices.empty()) {
891 update_sensitivity ();
894 string current_device, found_device;
895 current_device = device_combo.get_active_text ();
896 if (current_device == "") {
897 current_device = backend->device_name ();
900 // Make sure that the active text is still relevant for this
901 // device (it might only be relevant to the previous device!!)
902 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
903 if (*i == current_device)
904 found_device = current_device;
906 if (found_device == "")
907 // device has never been set (or was not relevant
908 // for this backend) Let's make sure it's not blank
909 current_device = available_devices.front ();
911 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
912 set_popdown_strings (device_combo, available_devices);
914 device_combo.set_active_text (current_device);
923 // @return true if there are input devices available
925 EngineControl::set_input_device_popdown_strings ()
927 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
928 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
930 vector<string> available_devices;
932 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
933 available_devices.push_back (i->name);
936 if (!available_devices.empty()) {
937 update_sensitivity ();
940 string current_device, found_device;
941 current_device = input_device_combo.get_active_text ();
942 if (current_device == "") {
943 current_device = backend->input_device_name ();
946 // Make sure that the active text is still relevant for this
947 // device (it might only be relevant to the previous device!!)
948 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
949 if (*i == current_device)
950 found_device = current_device;
952 if (found_device == "")
953 // device has never been set (or was not relevant
954 // for this backend) Let's make sure it's not blank
955 current_device = available_devices.front ();
957 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
958 set_popdown_strings (input_device_combo, available_devices);
960 input_device_combo.set_active_text (current_device);
970 // @return true if there are output devices available
972 EngineControl::set_output_device_popdown_strings ()
974 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
975 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
977 vector<string> available_devices;
979 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
980 available_devices.push_back (i->name);
983 if (!available_devices.empty()) {
984 update_sensitivity ();
987 string current_device, found_device;
988 current_device = output_device_combo.get_active_text ();
989 if (current_device == "") {
990 current_device = backend->output_device_name ();
993 // Make sure that the active text is still relevant for this
994 // device (it might only be relevant to the previous device!!)
995 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
996 if (*i == current_device)
997 found_device = current_device;
999 if (found_device == "")
1000 // device has never been set (or was not relevant
1001 // for this backend) Let's make sure it's not blank
1002 current_device = available_devices.front ();
1004 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1005 set_popdown_strings (output_device_combo, available_devices);
1007 output_device_combo.set_active_text (current_device);
1018 EngineControl::list_devices ()
1020 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1023 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1025 bool devices_available = false;
1027 if (backend->use_separate_input_and_output_devices ()) {
1028 bool input_devices_available = set_input_device_popdown_strings ();
1029 bool output_devices_available = set_output_device_popdown_strings ();
1030 devices_available = input_devices_available || output_devices_available;
1032 devices_available = set_device_popdown_strings ();
1035 if (devices_available) {
1036 input_latency.set_sensitive (true);
1037 output_latency.set_sensitive (true);
1038 input_channels.set_sensitive (true);
1039 output_channels.set_sensitive (true);
1041 ok_button->set_sensitive (true);
1042 apply_button->set_sensitive (true);
1045 device_combo.clear();
1046 input_device_combo.clear();
1047 output_device_combo.clear();
1048 sample_rate_combo.set_sensitive (false);
1049 buffer_size_combo.set_sensitive (false);
1050 input_latency.set_sensitive (false);
1051 output_latency.set_sensitive (false);
1052 input_channels.set_sensitive (false);
1053 output_channels.set_sensitive (false);
1054 if (_have_control) {
1055 ok_button->set_sensitive (false);
1056 apply_button->set_sensitive (false);
1058 ok_button->set_sensitive (true);
1059 apply_button->set_sensitive (true);
1060 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1061 sample_rate_combo.set_sensitive (true);
1063 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1064 buffer_size_combo.set_sensitive (true);
1072 EngineControl::driver_changed ()
1074 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1077 backend->set_driver (driver_combo.get_active_text());
1080 if (!ignore_changes) {
1081 maybe_display_saved_state ();
1086 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1088 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1093 if (_have_control) {
1094 sr = backend->available_sample_rates (device_name);
1097 sr.push_back (8000.0f);
1098 sr.push_back (16000.0f);
1099 sr.push_back (32000.0f);
1100 sr.push_back (44100.0f);
1101 sr.push_back (48000.0f);
1102 sr.push_back (88200.0f);
1103 sr.push_back (96000.0f);
1104 sr.push_back (192000.0f);
1105 sr.push_back (384000.0f);
1108 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1109 s.push_back (rate_as_string (*x));
1110 if (*x == _desired_sample_rate) {
1116 sample_rate_combo.set_sensitive (true);
1117 set_popdown_strings (sample_rate_combo, s);
1119 if (desired.empty()) {
1120 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1122 sample_rate_combo.set_active_text (desired);
1126 sample_rate_combo.set_sensitive (false);
1131 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1133 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1134 vector<uint32_t> bs;
1137 if (_have_control) {
1138 bs = backend->available_buffer_sizes (device_name);
1139 } else if (backend->can_change_buffer_size_when_running()) {
1147 bs.push_back (1024);
1148 bs.push_back (2048);
1149 bs.push_back (4096);
1150 bs.push_back (8192);
1153 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1154 s.push_back (bufsize_as_string (*x));
1158 buffer_size_combo.set_sensitive (true);
1159 set_popdown_strings (buffer_size_combo, s);
1160 buffer_size_combo.set_active_text (s.front());
1162 uint32_t period = backend->buffer_size();
1164 period = backend->default_buffer_size(device_name);
1166 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1167 show_buffer_duration ();
1169 buffer_size_combo.set_sensitive (false);
1174 EngineControl::device_changed ()
1176 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1179 string device_name_in;
1180 string device_name_out; // only used if backend support separate I/O devices
1182 if (backend->use_separate_input_and_output_devices()) {
1183 device_name_in = get_input_device_name ();
1184 device_name_out = get_output_device_name ();
1186 device_name_in = get_device_name ();
1189 /* we set the backend-device to query various device related intormation.
1190 * This has the side effect that backend->device_name() will match
1191 * the device_name and 'change_device' will never be true.
1192 * so work around this by setting...
1194 if (backend->use_separate_input_and_output_devices()) {
1195 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1196 queue_device_changed = true;
1199 if (device_name_in != backend->device_name()) {
1200 queue_device_changed = true;
1204 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1205 if (backend->use_separate_input_and_output_devices()) {
1206 backend->set_input_device_name (device_name_in);
1207 backend->set_output_device_name (device_name_out);
1209 backend->set_device_name(device_name_in);
1213 /* don't allow programmatic change to combos to cause a
1214 recursive call to this method.
1216 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1218 /* backends that support separate devices, need to ignore
1219 * the device-name - and use the devies set above
1221 set_samplerate_popdown_strings (device_name_in);
1222 set_buffersize_popdown_strings (device_name_in);
1223 /* XXX theoretically need to set min + max channel counts here
1226 manage_control_app_sensitivity ();
1229 /* pick up any saved state for this device */
1231 if (!ignore_changes) {
1232 maybe_display_saved_state ();
1237 EngineControl::input_device_changed ()
1243 EngineControl::output_device_changed ()
1249 EngineControl::bufsize_as_string (uint32_t sz)
1251 /* Translators: "samples" is always plural here, so no
1252 need for plural+singular forms.
1255 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1260 EngineControl::sample_rate_changed ()
1262 /* reset the strings for buffer size to show the correct msec value
1263 (reflecting the new sample rate).
1266 show_buffer_duration ();
1271 EngineControl::buffer_size_changed ()
1273 show_buffer_duration ();
1277 EngineControl::show_buffer_duration ()
1280 /* buffer sizes - convert from just samples to samples + msecs for
1281 * the displayed string
1284 string bs_text = buffer_size_combo.get_active_text ();
1285 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1286 uint32_t rate = get_rate();
1288 /* Developers: note the hard-coding of a double buffered model
1289 in the (2 * samples) computation of latency. we always start
1290 the audiobackend in this configuration.
1292 /* note to jack1 developers: ardour also always starts the engine
1293 * in async mode (no jack2 --sync option) which adds an extra cycle
1294 * of latency with jack2 (and *3 would be correct)
1295 * The value can also be wrong if jackd is started externally..
1297 * At the time of writing the ALSA backend always uses double-buffering *2,
1298 * The Dummy backend *1, and who knows what ASIO really does :)
1300 * So just display the period size, that's also what
1301 * ARDOUR_UI::update_sample_rate() does for the status bar.
1302 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1303 * but still, that's the buffer period, not [round-trip] latency)
1306 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1307 buffer_size_duration_label.set_text (buf);
1311 EngineControl::midi_option_changed ()
1313 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1316 backend->set_midi_option (get_midi_option());
1318 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1320 //_midi_devices.clear(); // TODO merge with state-saved settings..
1321 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1322 std::vector<MidiDeviceSettings> new_devices;
1324 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1325 MidiDeviceSettings mds = find_midi_device (i->name);
1326 if (i->available && !mds) {
1327 uint32_t input_latency = 0;
1328 uint32_t output_latency = 0;
1329 if (_can_set_midi_latencies) {
1330 input_latency = backend->systemic_midi_input_latency (i->name);
1331 output_latency = backend->systemic_midi_output_latency (i->name);
1333 bool enabled = backend->midi_device_enabled (i->name);
1334 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1335 new_devices.push_back (ptr);
1336 } else if (i->available) {
1337 new_devices.push_back (mds);
1340 _midi_devices = new_devices;
1342 if (_midi_devices.empty()) {
1343 midi_devices_button.set_sensitive (false);
1345 midi_devices_button.set_sensitive (true);
1350 EngineControl::parameter_changed ()
1354 EngineControl::State
1355 EngineControl::get_matching_state (
1356 const string& backend,
1357 const string& driver,
1358 const string& device)
1360 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1361 if ((*i)->backend == backend &&
1362 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1370 EngineControl::State
1371 EngineControl::get_matching_state (
1372 const string& backend,
1373 const string& driver,
1374 const string& input_device,
1375 const string& output_device)
1377 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1378 if ((*i)->backend == backend &&
1379 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1387 EngineControl::State
1388 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1390 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1393 if (backend->use_separate_input_and_output_devices ()) {
1394 return get_matching_state (backend_combo.get_active_text(),
1395 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1396 input_device_combo.get_active_text(),
1397 output_device_combo.get_active_text());
1399 return get_matching_state (backend_combo.get_active_text(),
1400 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1401 device_combo.get_active_text());
1405 return get_matching_state (backend_combo.get_active_text(),
1407 device_combo.get_active_text());
1410 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1411 const EngineControl::State& state2)
1413 if (state1->backend == state2->backend &&
1414 state1->driver == state2->driver &&
1415 state1->device == state2->device &&
1416 state1->input_device == state2->input_device &&
1417 state1->output_device == state2->output_device) {
1423 EngineControl::State
1424 EngineControl::save_state ()
1428 if (!_have_control) {
1429 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1433 state.reset(new StateStruct);
1434 state->backend = get_backend ();
1436 state.reset(new StateStruct);
1437 store_state (state);
1440 for (StateList::iterator i = states.begin(); i != states.end();) {
1441 if (equivalent_states (*i, state)) {
1442 i = states.erase(i);
1448 states.push_back (state);
1454 EngineControl::store_state (State state)
1456 state->backend = get_backend ();
1457 state->driver = get_driver ();
1458 state->device = get_device_name ();
1459 state->input_device = get_input_device_name ();
1460 state->output_device = get_output_device_name ();
1461 state->sample_rate = get_rate ();
1462 state->buffer_size = get_buffer_size ();
1463 state->input_latency = get_input_latency ();
1464 state->output_latency = get_output_latency ();
1465 state->input_channels = get_input_channels ();
1466 state->output_channels = get_output_channels ();
1467 state->midi_option = get_midi_option ();
1468 state->midi_devices = _midi_devices;
1472 EngineControl::maybe_display_saved_state ()
1474 if (!_have_control) {
1478 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1481 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1483 if (!_desired_sample_rate) {
1484 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1486 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1487 /* call this explicitly because we're ignoring changes to
1488 the controls at this point.
1490 show_buffer_duration ();
1491 input_latency.set_value (state->input_latency);
1492 output_latency.set_value (state->output_latency);
1494 if (!state->midi_option.empty()) {
1495 midi_option_combo.set_active_text (state->midi_option);
1496 _midi_devices = state->midi_devices;
1502 EngineControl::get_state ()
1504 LocaleGuard lg (X_("C"));
1506 XMLNode* root = new XMLNode ("AudioMIDISetup");
1509 if (!states.empty()) {
1510 XMLNode* state_nodes = new XMLNode ("EngineStates");
1512 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1514 XMLNode* node = new XMLNode ("State");
1516 node->add_property ("backend", (*i)->backend);
1517 node->add_property ("driver", (*i)->driver);
1518 node->add_property ("device", (*i)->device);
1519 node->add_property ("input-device", (*i)->input_device);
1520 node->add_property ("output-device", (*i)->output_device);
1521 node->add_property ("sample-rate", (*i)->sample_rate);
1522 node->add_property ("buffer-size", (*i)->buffer_size);
1523 node->add_property ("input-latency", (*i)->input_latency);
1524 node->add_property ("output-latency", (*i)->output_latency);
1525 node->add_property ("input-channels", (*i)->input_channels);
1526 node->add_property ("output-channels", (*i)->output_channels);
1527 node->add_property ("active", (*i)->active ? "yes" : "no");
1528 node->add_property ("midi-option", (*i)->midi_option);
1530 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1531 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1532 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1533 midi_device_stuff->add_property (X_("name"), (*p)->name);
1534 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1535 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1536 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1537 midi_devices->add_child_nocopy (*midi_device_stuff);
1539 node->add_child_nocopy (*midi_devices);
1541 state_nodes->add_child_nocopy (*node);
1544 root->add_child_nocopy (*state_nodes);
1551 EngineControl::set_state (const XMLNode& root)
1553 XMLNodeList clist, cclist;
1554 XMLNodeConstIterator citer, cciter;
1556 XMLNode* grandchild;
1557 XMLProperty* prop = NULL;
1559 fprintf (stderr, "EngineControl::set_state\n");
1561 if (root.name() != "AudioMIDISetup") {
1565 clist = root.children();
1569 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1573 if (child->name() != "EngineStates") {
1577 cclist = child->children();
1579 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1580 State state (new StateStruct);
1582 grandchild = *cciter;
1584 if (grandchild->name() != "State") {
1588 if ((prop = grandchild->property ("backend")) == 0) {
1591 state->backend = prop->value ();
1593 if ((prop = grandchild->property ("driver")) == 0) {
1596 state->driver = prop->value ();
1598 if ((prop = grandchild->property ("device")) == 0) {
1601 state->device = prop->value ();
1603 if ((prop = grandchild->property ("input-device")) == 0) {
1606 state->input_device = prop->value ();
1608 if ((prop = grandchild->property ("output-device")) == 0) {
1611 state->output_device = prop->value ();
1613 if ((prop = grandchild->property ("sample-rate")) == 0) {
1616 state->sample_rate = atof (prop->value ());
1618 if ((prop = grandchild->property ("buffer-size")) == 0) {
1621 state->buffer_size = atoi (prop->value ());
1623 if ((prop = grandchild->property ("input-latency")) == 0) {
1626 state->input_latency = atoi (prop->value ());
1628 if ((prop = grandchild->property ("output-latency")) == 0) {
1631 state->output_latency = atoi (prop->value ());
1633 if ((prop = grandchild->property ("input-channels")) == 0) {
1636 state->input_channels = atoi (prop->value ());
1638 if ((prop = grandchild->property ("output-channels")) == 0) {
1641 state->output_channels = atoi (prop->value ());
1643 if ((prop = grandchild->property ("active")) == 0) {
1646 state->active = string_is_affirmative (prop->value ());
1648 if ((prop = grandchild->property ("midi-option")) == 0) {
1651 state->midi_option = prop->value ();
1653 state->midi_devices.clear();
1655 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1656 const XMLNodeList mnc = midinode->children();
1657 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1658 if ((*n)->property (X_("name")) == 0
1659 || (*n)->property (X_("enabled")) == 0
1660 || (*n)->property (X_("input-latency")) == 0
1661 || (*n)->property (X_("output-latency")) == 0
1666 MidiDeviceSettings ptr (new MidiDeviceSetting(
1667 (*n)->property (X_("name"))->value (),
1668 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1669 atoi ((*n)->property (X_("input-latency"))->value ()),
1670 atoi ((*n)->property (X_("output-latency"))->value ())
1672 state->midi_devices.push_back (ptr);
1677 /* remove accumulated duplicates (due to bug in ealier version)
1678 * this can be removed again before release
1680 for (StateList::iterator i = states.begin(); i != states.end();) {
1681 if ((*i)->backend == state->backend &&
1682 (*i)->driver == state->driver &&
1683 (*i)->device == state->device) {
1684 i = states.erase(i);
1691 states.push_back (state);
1695 /* now see if there was an active state and switch the setup to it */
1697 // purge states of backend that are not available in this built
1698 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1699 vector<std::string> backend_names;
1701 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1702 backend_names.push_back((*i)->name);
1704 for (StateList::iterator i = states.begin(); i != states.end();) {
1705 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1706 i = states.erase(i);
1712 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1715 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1716 backend_combo.set_active_text ((*i)->backend);
1718 /* The driver popdown strings need to be populated now so that
1719 * set_active_text will actually set a valid entry. Then
1720 * backend_changed() will populate all the other combo's so they
1721 * can also be set to valid entries and the state will be restored
1724 if (!(*i)->driver.empty()) {
1725 set_driver_popdown_strings ();
1727 driver_combo.set_active_text ((*i)->driver);
1730 device_combo.set_active_text ((*i)->device);
1731 input_device_combo.set_active_text ((*i)->input_device);
1732 output_device_combo.set_active_text ((*i)->output_device);
1733 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1734 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1735 input_latency.set_value ((*i)->input_latency);
1736 output_latency.set_value ((*i)->output_latency);
1737 midi_option_combo.set_active_text ((*i)->midi_option);
1744 EngineControl::push_state_to_backend (bool start)
1746 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1752 /* figure out what is going to change */
1754 bool restart_required = false;
1755 bool was_running = ARDOUR::AudioEngine::instance()->running();
1756 bool change_driver = false;
1757 bool change_device = false;
1758 bool change_rate = false;
1759 bool change_bufsize = false;
1760 bool change_latency = false;
1761 bool change_channels = false;
1762 bool change_midi = false;
1764 uint32_t ochan = get_output_channels ();
1765 uint32_t ichan = get_input_channels ();
1767 if (_have_control) {
1769 if (started_at_least_once) {
1771 /* we can control the backend */
1773 if (backend->requires_driver_selection()) {
1774 if (get_driver() != backend->driver_name()) {
1775 change_driver = true;
1779 if (backend->use_separate_input_and_output_devices()) {
1780 if (get_input_device_name() != backend->input_device_name()) {
1781 change_device = true;
1783 if (get_output_device_name() != backend->output_device_name()) {
1784 change_device = true;
1787 if (get_device_name() != backend->device_name()) {
1788 change_device = true;
1792 if (queue_device_changed) {
1793 change_device = true;
1796 if (get_rate() != backend->sample_rate()) {
1800 if (get_buffer_size() != backend->buffer_size()) {
1801 change_bufsize = true;
1804 if (get_midi_option() != backend->midi_option()) {
1808 /* zero-requested channels means "all available" */
1811 ichan = backend->input_channels();
1815 ochan = backend->output_channels();
1818 if (ichan != backend->input_channels()) {
1819 change_channels = true;
1822 if (ochan != backend->output_channels()) {
1823 change_channels = true;
1826 if (get_input_latency() != backend->systemic_input_latency() ||
1827 get_output_latency() != backend->systemic_output_latency()) {
1828 change_latency = true;
1831 /* backend never started, so we have to force a group
1834 change_device = true;
1835 if (backend->requires_driver_selection()) {
1836 change_driver = true;
1839 change_bufsize = true;
1840 change_channels = true;
1841 change_latency = true;
1847 /* we have no control over the backend, meaning that we can
1848 * only possibly change sample rate and buffer size.
1852 if (get_rate() != backend->sample_rate()) {
1853 change_bufsize = true;
1856 if (get_buffer_size() != backend->buffer_size()) {
1857 change_bufsize = true;
1861 queue_device_changed = false;
1863 if (!_have_control) {
1865 /* We do not have control over the backend, so the best we can
1866 * do is try to change the sample rate and/or bufsize and get
1870 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1874 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1879 backend->set_sample_rate (get_rate());
1882 if (change_bufsize) {
1883 backend->set_buffer_size (get_buffer_size());
1887 if (ARDOUR::AudioEngine::instance()->start ()) {
1888 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1898 /* determine if we need to stop the backend before changing parameters */
1900 if (change_driver || change_device || change_channels || change_latency ||
1901 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1903 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1904 restart_required = true;
1906 restart_required = false;
1911 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1912 /* no changes in any parameters that absolutely require a
1913 * restart, so check those that might be changeable without a
1917 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1918 /* can't do this while running ... */
1919 restart_required = true;
1922 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1923 /* can't do this while running ... */
1924 restart_required = true;
1930 if (restart_required) {
1931 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1938 if (change_driver && backend->set_driver (get_driver())) {
1939 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1942 if (backend->use_separate_input_and_output_devices()) {
1943 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1944 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1947 if (change_device && backend->set_output_device_name (get_output_device_name())) {
1948 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
1952 if (change_device && backend->set_device_name (get_device_name())) {
1953 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1957 if (change_rate && backend->set_sample_rate (get_rate())) {
1958 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1961 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1962 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1966 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1967 if (backend->set_input_channels (get_input_channels())) {
1968 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1971 if (backend->set_output_channels (get_output_channels())) {
1972 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1976 if (change_latency) {
1977 if (backend->set_systemic_input_latency (get_input_latency())) {
1978 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1981 if (backend->set_systemic_output_latency (get_output_latency())) {
1982 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1988 backend->set_midi_option (get_midi_option());
1992 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1993 if (_measure_midi) {
1994 if (*p == _measure_midi) {
1995 backend->set_midi_device_enabled ((*p)->name, true);
1997 backend->set_midi_device_enabled ((*p)->name, false);
2001 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2002 if (backend->can_set_systemic_midi_latencies()) {
2003 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2004 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2009 if (start || (was_running && restart_required)) {
2010 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2021 EngineControl::post_push ()
2023 /* get a pointer to the current state object, creating one if
2027 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2030 state = save_state ();
2038 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2039 (*i)->active = false;
2042 /* mark this one active (to be used next time the dialog is
2046 state->active = true;
2048 if (_have_control) { // XXX
2049 manage_control_app_sensitivity ();
2052 /* schedule a redisplay of MIDI ports */
2053 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2058 EngineControl::get_rate () const
2060 float r = atof (sample_rate_combo.get_active_text ());
2061 /* the string may have been translated with an abbreviation for
2062 * thousands, so use a crude heuristic to fix this.
2072 EngineControl::get_buffer_size () const
2074 string txt = buffer_size_combo.get_active_text ();
2077 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2078 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2079 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2087 EngineControl::get_midi_option () const
2089 return midi_option_combo.get_active_text();
2093 EngineControl::get_input_channels() const
2095 if (ARDOUR::Profile->get_mixbus()) {
2096 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2097 if (!backend) return 0;
2098 return backend->input_channels();
2100 return (uint32_t) input_channels_adjustment.get_value();
2104 EngineControl::get_output_channels() const
2106 if (ARDOUR::Profile->get_mixbus()) {
2107 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2108 if (!backend) return 0;
2109 return backend->input_channels();
2111 return (uint32_t) output_channels_adjustment.get_value();
2115 EngineControl::get_input_latency() const
2117 return (uint32_t) input_latency_adjustment.get_value();
2121 EngineControl::get_output_latency() const
2123 return (uint32_t) output_latency_adjustment.get_value();
2127 EngineControl::get_backend () const
2129 return backend_combo.get_active_text ();
2133 EngineControl::get_driver () const
2135 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2136 return driver_combo.get_active_text ();
2143 EngineControl::get_device_name () const
2145 return device_combo.get_active_text ();
2149 EngineControl::get_input_device_name () const
2151 return input_device_combo.get_active_text ();
2155 EngineControl::get_output_device_name () const
2157 return output_device_combo.get_active_text ();
2161 EngineControl::control_app_button_clicked ()
2163 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2169 backend->launch_control_app ();
2173 EngineControl::manage_control_app_sensitivity ()
2175 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2181 string appname = backend->control_app_name();
2183 if (appname.empty()) {
2184 control_app_button.set_sensitive (false);
2186 control_app_button.set_sensitive (true);
2191 EngineControl::set_desired_sample_rate (uint32_t sr)
2193 _desired_sample_rate = sr;
2198 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2200 if (page_num == 0) {
2201 cancel_button->set_sensitive (true);
2202 ok_button->set_sensitive (true);
2203 apply_button->set_sensitive (true);
2204 _measure_midi.reset();
2206 cancel_button->set_sensitive (false);
2207 ok_button->set_sensitive (false);
2208 apply_button->set_sensitive (false);
2211 if (page_num == midi_tab) {
2213 refresh_midi_display ();
2216 if (page_num == latency_tab) {
2219 if (ARDOUR::AudioEngine::instance()->running()) {
2220 // TODO - mark as 'stopped for latency
2221 ARDOUR_UI::instance()->disconnect_from_engine ();
2225 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2227 /* save any existing latency values */
2229 uint32_t il = (uint32_t) input_latency.get_value ();
2230 uint32_t ol = (uint32_t) input_latency.get_value ();
2232 /* reset to zero so that our new test instance
2233 will be clean of any existing latency measures.
2235 NB. this should really be done by the backend
2236 when stated for latency measurement.
2239 input_latency.set_value (0);
2240 output_latency.set_value (0);
2242 push_state_to_backend (false);
2246 input_latency.set_value (il);
2247 output_latency.set_value (ol);
2250 // This should be done in push_state_to_backend()
2251 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2252 disable_latency_tab ();
2255 enable_latency_tab ();
2259 end_latency_detection ();
2260 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2265 /* latency measurement */
2268 EngineControl::check_audio_latency_measurement ()
2270 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2272 if (mtdm->resolve () < 0) {
2273 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2277 if (mtdm->err () > 0.3) {
2283 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2285 if (sample_rate == 0) {
2286 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2287 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2291 int frames_total = mtdm->del();
2292 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2294 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2295 _("Detected roundtrip latency: "),
2296 frames_total, frames_total * 1000.0f/sample_rate,
2297 _("Systemic latency: "),
2298 extra, extra * 1000.0f/sample_rate);
2302 if (mtdm->err () > 0.2) {
2304 strcat (buf, _("(signal detection error)"));
2310 strcat (buf, _("(inverted - bad wiring)"));
2314 lm_results.set_markup (string_compose (results_markup, buf));
2317 have_lm_results = true;
2318 end_latency_detection ();
2319 lm_use_button.set_sensitive (true);
2327 EngineControl::check_midi_latency_measurement ()
2329 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2331 if (!mididm->have_signal () || mididm->latency () == 0) {
2332 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2337 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2339 if (sample_rate == 0) {
2340 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2341 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2345 ARDOUR::framecnt_t frames_total = mididm->latency();
2346 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2347 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2348 _("Detected roundtrip latency: "),
2349 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2350 _("Systemic latency: "),
2351 extra, extra * 1000.0f / sample_rate);
2355 if (!mididm->ok ()) {
2357 strcat (buf, _("(averaging)"));
2361 if (mididm->deviation () > 50.0) {
2363 strcat (buf, _("(too large jitter)"));
2365 } else if (mididm->deviation () > 10.0) {
2367 strcat (buf, _("(large jitter)"));
2371 have_lm_results = true;
2372 end_latency_detection ();
2373 lm_use_button.set_sensitive (true);
2374 lm_results.set_markup (string_compose (results_markup, buf));
2376 } else if (mididm->processed () > 400) {
2377 have_lm_results = false;
2378 end_latency_detection ();
2379 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2383 lm_results.set_markup (string_compose (results_markup, buf));
2389 EngineControl::start_latency_detection ()
2391 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2392 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2394 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2395 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2396 if (_measure_midi) {
2397 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2399 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2401 lm_measure_label.set_text (_("Cancel"));
2402 have_lm_results = false;
2403 lm_use_button.set_sensitive (false);
2404 lm_input_channel_combo.set_sensitive (false);
2405 lm_output_channel_combo.set_sensitive (false);
2411 EngineControl::end_latency_detection ()
2413 latency_timeout.disconnect ();
2414 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2415 lm_measure_label.set_text (_("Measure"));
2416 if (!have_lm_results) {
2417 lm_use_button.set_sensitive (false);
2419 lm_input_channel_combo.set_sensitive (true);
2420 lm_output_channel_combo.set_sensitive (true);
2425 EngineControl::latency_button_clicked ()
2428 start_latency_detection ();
2430 end_latency_detection ();
2435 EngineControl::use_latency_button_clicked ()
2437 if (_measure_midi) {
2438 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2442 ARDOUR::framecnt_t frames_total = mididm->latency();
2443 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2444 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2445 _measure_midi->input_latency = one_way;
2446 _measure_midi->output_latency = one_way;
2447 notebook.set_current_page (midi_tab);
2449 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2455 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2456 one_way = std::max (0., one_way);
2458 input_latency_adjustment.set_value (one_way);
2459 output_latency_adjustment.set_value (one_way);
2461 /* back to settings page */
2462 notebook.set_current_page (0);
2468 EngineControl::on_delete_event (GdkEventAny* ev)
2470 if (notebook.get_current_page() == 2) {
2471 /* currently on latency tab - be sure to clean up */
2472 end_latency_detection ();
2474 return ArdourDialog::on_delete_event (ev);
2478 EngineControl::engine_running ()
2480 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2483 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2484 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2486 buffer_size_combo.set_sensitive (true);
2487 sample_rate_combo.set_sensitive (true);
2489 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2490 connect_disconnect_button.show();
2492 started_at_least_once = true;
2493 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2497 EngineControl::engine_stopped ()
2499 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2502 buffer_size_combo.set_sensitive (false);
2503 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2504 connect_disconnect_button.show();
2506 sample_rate_combo.set_sensitive (true);
2507 buffer_size_combo.set_sensitive (true);
2508 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2512 EngineControl::device_list_changed ()
2514 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2516 midi_option_changed();
2520 EngineControl::connect_disconnect_click()
2522 if (ARDOUR::AudioEngine::instance()->running()) {
2523 ARDOUR_UI::instance()->disconnect_from_engine ();
2525 ARDOUR_UI::instance()->reconnect_to_engine ();
2530 EngineControl::calibrate_audio_latency ()
2532 _measure_midi.reset ();
2533 have_lm_results = false;
2534 lm_use_button.set_sensitive (false);
2535 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2536 notebook.set_current_page (latency_tab);
2540 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2543 have_lm_results = false;
2544 lm_use_button.set_sensitive (false);
2545 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2546 notebook.set_current_page (latency_tab);
2550 EngineControl::configure_midi_devices ()
2552 notebook.set_current_page (midi_tab);