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::backend_changed ()
753 string backend_name = backend_combo.get_active_text();
754 boost::shared_ptr<ARDOUR::AudioBackend> backend;
756 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
757 /* eh? setting the backend failed... how ? */
758 /* A: stale config contains a backend that does not exist in current build */
762 _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
765 setup_midi_tab_for_backend ();
766 _midi_devices.clear();
768 if (backend->requires_driver_selection()) {
769 vector<string> drivers = backend->enumerate_drivers();
770 driver_combo.set_sensitive (true);
772 if (!drivers.empty()) {
774 string current_driver;
775 current_driver = backend->driver_name ();
777 // driver might not have been set yet
778 if (current_driver == "") {
779 current_driver = driver_combo.get_active_text ();
780 if (current_driver == "")
781 // driver has never been set, make sure it's not blank
782 current_driver = drivers.front ();
785 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
786 set_popdown_strings (driver_combo, drivers);
787 driver_combo.set_active_text (current_driver);
794 driver_combo.set_sensitive (false);
795 /* this will change the device text which will cause a call to
796 * device changed which will set up parameters
801 vector<string> midi_options = backend->enumerate_midi_options();
803 if (midi_options.size() == 1) {
804 /* only contains the "none" option */
805 midi_option_combo.set_sensitive (false);
808 set_popdown_strings (midi_option_combo, midi_options);
809 midi_option_combo.set_active_text (midi_options.front());
810 midi_option_combo.set_sensitive (true);
812 midi_option_combo.set_sensitive (false);
816 connect_disconnect_button.hide();
818 midi_option_changed();
820 started_at_least_once = false;
822 if (!ignore_changes) {
823 maybe_display_saved_state ();
828 EngineControl::print_channel_count (Gtk::SpinButton* sb)
830 if (ARDOUR::Profile->get_mixbus()) {
834 uint32_t cnt = (uint32_t) sb->get_value();
836 sb->set_text (_("all available channels"));
839 snprintf (buf, sizeof (buf), "%d", cnt);
846 EngineControl::set_driver_popdown_strings ()
848 string backend_name = backend_combo.get_active_text();
849 boost::shared_ptr<ARDOUR::AudioBackend> backend;
851 if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
852 /* eh? setting the backend failed... how ? */
853 /* A: stale config contains a backend that does not exist in current build */
857 vector<string> drivers = backend->enumerate_drivers();
858 set_popdown_strings (driver_combo, drivers);
862 // @return true if there are devices available
864 EngineControl::set_device_popdown_strings ()
866 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
867 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
869 /* NOTE: Ardour currently does not display the "available" field of the
872 * Doing so would require a different GUI widget than the combo
873 * box/popdown that we currently use, since it has no way to list
874 * items that are not selectable. Something more like a popup menu,
875 * which could have unselectable items, would be appropriate.
878 vector<string> available_devices;
880 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
881 available_devices.push_back (i->name);
885 if (!available_devices.empty()) {
888 string current_device, found_device;
889 current_device = device_combo.get_active_text ();
890 if (current_device == "") {
891 current_device = backend->device_name ();
894 // Make sure that the active text is still relevant for this
895 // device (it might only be relevant to the previous device!!)
896 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
897 if (*i == current_device)
898 found_device = current_device;
900 if (found_device == "")
901 // device has never been set (or was not relevant
902 // for this backend) Let's make sure it's not blank
903 current_device = available_devices.front ();
905 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
906 set_popdown_strings (device_combo, available_devices);
908 device_combo.set_active_text (current_device);
917 // @return true if there are input devices available
919 EngineControl::set_input_device_popdown_strings ()
921 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
922 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
924 vector<string> available_devices;
926 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
927 available_devices.push_back (i->name);
930 if (!available_devices.empty()) {
933 string current_device, found_device;
934 current_device = input_device_combo.get_active_text ();
935 if (current_device == "") {
936 current_device = backend->input_device_name ();
939 // Make sure that the active text is still relevant for this
940 // device (it might only be relevant to the previous device!!)
941 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
942 if (*i == current_device)
943 found_device = current_device;
945 if (found_device == "")
946 // device has never been set (or was not relevant
947 // for this backend) Let's make sure it's not blank
948 current_device = available_devices.front ();
950 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
951 set_popdown_strings (input_device_combo, available_devices);
953 input_device_combo.set_active_text (current_device);
963 // @return true if there are output devices available
965 EngineControl::set_output_device_popdown_strings ()
967 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
968 vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
970 vector<string> available_devices;
972 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
973 available_devices.push_back (i->name);
976 if (!available_devices.empty()) {
979 string current_device, found_device;
980 current_device = output_device_combo.get_active_text ();
981 if (current_device == "") {
982 current_device = backend->output_device_name ();
985 // Make sure that the active text is still relevant for this
986 // device (it might only be relevant to the previous device!!)
987 for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
988 if (*i == current_device)
989 found_device = current_device;
991 if (found_device == "")
992 // device has never been set (or was not relevant
993 // for this backend) Let's make sure it's not blank
994 current_device = available_devices.front ();
996 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
997 set_popdown_strings (output_device_combo, available_devices);
999 output_device_combo.set_active_text (current_device);
1010 EngineControl::list_devices ()
1012 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1015 /* now fill out devices, mark sample rates, buffer sizes insensitive */
1017 bool devices_available = false;
1019 if (backend->use_separate_input_and_output_devices ()) {
1020 bool input_devices_available = set_input_device_popdown_strings ();
1021 bool output_devices_available = set_output_device_popdown_strings ();
1022 devices_available = input_devices_available || output_devices_available;
1024 devices_available = set_device_popdown_strings ();
1027 if (devices_available) {
1028 input_latency.set_sensitive (true);
1029 output_latency.set_sensitive (true);
1030 input_channels.set_sensitive (true);
1031 output_channels.set_sensitive (true);
1033 ok_button->set_sensitive (true);
1034 apply_button->set_sensitive (true);
1037 device_combo.clear();
1038 input_device_combo.clear();
1039 output_device_combo.clear();
1040 sample_rate_combo.set_sensitive (false);
1041 buffer_size_combo.set_sensitive (false);
1042 input_latency.set_sensitive (false);
1043 output_latency.set_sensitive (false);
1044 input_channels.set_sensitive (false);
1045 output_channels.set_sensitive (false);
1046 if (_have_control) {
1047 ok_button->set_sensitive (false);
1048 apply_button->set_sensitive (false);
1050 ok_button->set_sensitive (true);
1051 apply_button->set_sensitive (true);
1052 if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
1053 sample_rate_combo.set_sensitive (true);
1055 if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
1056 buffer_size_combo.set_sensitive (true);
1064 EngineControl::driver_changed ()
1066 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1069 backend->set_driver (driver_combo.get_active_text());
1072 if (!ignore_changes) {
1073 maybe_display_saved_state ();
1078 EngineControl::set_samplerate_popdown_strings (const std::string& device_name)
1080 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1085 if (_have_control) {
1086 sr = backend->available_sample_rates (device_name);
1089 sr.push_back (8000.0f);
1090 sr.push_back (16000.0f);
1091 sr.push_back (32000.0f);
1092 sr.push_back (44100.0f);
1093 sr.push_back (48000.0f);
1094 sr.push_back (88200.0f);
1095 sr.push_back (96000.0f);
1096 sr.push_back (192000.0f);
1097 sr.push_back (384000.0f);
1100 for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1101 s.push_back (rate_as_string (*x));
1102 if (*x == _desired_sample_rate) {
1108 sample_rate_combo.set_sensitive (true);
1109 set_popdown_strings (sample_rate_combo, s);
1111 if (desired.empty()) {
1112 sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
1114 sample_rate_combo.set_active_text (desired);
1118 sample_rate_combo.set_sensitive (false);
1123 EngineControl::set_buffersize_popdown_strings (const std::string& device_name)
1125 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1126 vector<uint32_t> bs;
1129 if (_have_control) {
1130 bs = backend->available_buffer_sizes (device_name);
1131 } else if (backend->can_change_buffer_size_when_running()) {
1139 bs.push_back (1024);
1140 bs.push_back (2048);
1141 bs.push_back (4096);
1142 bs.push_back (8192);
1145 for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1146 s.push_back (bufsize_as_string (*x));
1150 buffer_size_combo.set_sensitive (true);
1151 set_popdown_strings (buffer_size_combo, s);
1152 buffer_size_combo.set_active_text (s.front());
1154 uint32_t period = backend->buffer_size();
1156 period = backend->default_buffer_size(device_name);
1158 set_active_text_if_present (buffer_size_combo, bufsize_as_string (period));
1159 show_buffer_duration ();
1161 buffer_size_combo.set_sensitive (false);
1166 EngineControl::device_changed ()
1168 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1171 string device_name_in;
1172 string device_name_out; // only used if backend support separate I/O devices
1174 if (backend->use_separate_input_and_output_devices()) {
1175 device_name_in = get_input_device_name ();
1176 device_name_out = get_output_device_name ();
1178 device_name_in = get_device_name ();
1181 /* we set the backend-device to query various device related intormation.
1182 * This has the side effect that backend->device_name() will match
1183 * the device_name and 'change_device' will never be true.
1184 * so work around this by setting...
1186 if (backend->use_separate_input_and_output_devices()) {
1187 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1188 queue_device_changed = true;
1191 if (device_name_in != backend->device_name()) {
1192 queue_device_changed = true;
1196 //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1197 if (backend->use_separate_input_and_output_devices()) {
1198 backend->set_input_device_name (device_name_in);
1199 backend->set_output_device_name (device_name_out);
1201 backend->set_device_name(device_name_in);
1205 /* don't allow programmatic change to combos to cause a
1206 recursive call to this method.
1208 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1210 /* backends that support separate devices, need to ignore
1211 * the device-name - and use the devies set above
1213 set_samplerate_popdown_strings (device_name_in);
1214 set_buffersize_popdown_strings (device_name_in);
1215 /* XXX theoretically need to set min + max channel counts here
1218 manage_control_app_sensitivity ();
1221 /* pick up any saved state for this device */
1223 if (!ignore_changes) {
1224 maybe_display_saved_state ();
1229 EngineControl::input_device_changed ()
1235 EngineControl::output_device_changed ()
1241 EngineControl::bufsize_as_string (uint32_t sz)
1243 /* Translators: "samples" is always plural here, so no
1244 need for plural+singular forms.
1247 snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1252 EngineControl::sample_rate_changed ()
1254 /* reset the strings for buffer size to show the correct msec value
1255 (reflecting the new sample rate).
1258 show_buffer_duration ();
1263 EngineControl::buffer_size_changed ()
1265 show_buffer_duration ();
1269 EngineControl::show_buffer_duration ()
1272 /* buffer sizes - convert from just samples to samples + msecs for
1273 * the displayed string
1276 string bs_text = buffer_size_combo.get_active_text ();
1277 uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1278 uint32_t rate = get_rate();
1280 /* Developers: note the hard-coding of a double buffered model
1281 in the (2 * samples) computation of latency. we always start
1282 the audiobackend in this configuration.
1284 /* note to jack1 developers: ardour also always starts the engine
1285 * in async mode (no jack2 --sync option) which adds an extra cycle
1286 * of latency with jack2 (and *3 would be correct)
1287 * The value can also be wrong if jackd is started externally..
1289 * At the time of writing the ALSA backend always uses double-buffering *2,
1290 * The Dummy backend *1, and who knows what ASIO really does :)
1292 * So just display the period size, that's also what
1293 * ARDOUR_UI::update_sample_rate() does for the status bar.
1294 * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1295 * but still, that's the buffer period, not [round-trip] latency)
1298 snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1299 buffer_size_duration_label.set_text (buf);
1303 EngineControl::midi_option_changed ()
1305 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1308 backend->set_midi_option (get_midi_option());
1310 vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1312 //_midi_devices.clear(); // TODO merge with state-saved settings..
1313 _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1314 std::vector<MidiDeviceSettings> new_devices;
1316 for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1317 MidiDeviceSettings mds = find_midi_device (i->name);
1318 if (i->available && !mds) {
1319 uint32_t input_latency = 0;
1320 uint32_t output_latency = 0;
1321 if (_can_set_midi_latencies) {
1322 input_latency = backend->systemic_midi_input_latency (i->name);
1323 output_latency = backend->systemic_midi_output_latency (i->name);
1325 bool enabled = backend->midi_device_enabled (i->name);
1326 MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1327 new_devices.push_back (ptr);
1328 } else if (i->available) {
1329 new_devices.push_back (mds);
1332 _midi_devices = new_devices;
1334 if (_midi_devices.empty()) {
1335 midi_devices_button.set_sensitive (false);
1337 midi_devices_button.set_sensitive (true);
1342 EngineControl::parameter_changed ()
1346 EngineControl::State
1347 EngineControl::get_matching_state (
1348 const string& backend,
1349 const string& driver,
1350 const string& device)
1352 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1353 if ((*i)->backend == backend &&
1354 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1362 EngineControl::State
1363 EngineControl::get_matching_state (
1364 const string& backend,
1365 const string& driver,
1366 const string& input_device,
1367 const string& output_device)
1369 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1370 if ((*i)->backend == backend &&
1371 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1379 EngineControl::State
1380 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1382 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1385 if (backend->use_separate_input_and_output_devices ()) {
1386 return get_matching_state (backend_combo.get_active_text(),
1387 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1388 input_device_combo.get_active_text(),
1389 output_device_combo.get_active_text());
1391 return get_matching_state (backend_combo.get_active_text(),
1392 (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1393 device_combo.get_active_text());
1397 return get_matching_state (backend_combo.get_active_text(),
1399 device_combo.get_active_text());
1402 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1403 const EngineControl::State& state2)
1405 if (state1->backend == state2->backend &&
1406 state1->driver == state2->driver &&
1407 state1->device == state2->device &&
1408 state1->input_device == state2->input_device &&
1409 state1->output_device == state2->output_device) {
1415 EngineControl::State
1416 EngineControl::save_state ()
1420 if (!_have_control) {
1421 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1425 state.reset(new StateStruct);
1426 state->backend = get_backend ();
1428 state.reset(new StateStruct);
1429 store_state (state);
1432 for (StateList::iterator i = states.begin(); i != states.end();) {
1433 if (equivalent_states (*i, state)) {
1434 i = states.erase(i);
1440 states.push_back (state);
1446 EngineControl::store_state (State state)
1448 state->backend = get_backend ();
1449 state->driver = get_driver ();
1450 state->device = get_device_name ();
1451 state->input_device = get_input_device_name ();
1452 state->output_device = get_output_device_name ();
1453 state->sample_rate = get_rate ();
1454 state->buffer_size = get_buffer_size ();
1455 state->input_latency = get_input_latency ();
1456 state->output_latency = get_output_latency ();
1457 state->input_channels = get_input_channels ();
1458 state->output_channels = get_output_channels ();
1459 state->midi_option = get_midi_option ();
1460 state->midi_devices = _midi_devices;
1464 EngineControl::maybe_display_saved_state ()
1466 if (!_have_control) {
1470 State state = get_saved_state_for_currently_displayed_backend_and_device ();
1473 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1475 if (!_desired_sample_rate) {
1476 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1478 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1479 /* call this explicitly because we're ignoring changes to
1480 the controls at this point.
1482 show_buffer_duration ();
1483 input_latency.set_value (state->input_latency);
1484 output_latency.set_value (state->output_latency);
1486 if (!state->midi_option.empty()) {
1487 midi_option_combo.set_active_text (state->midi_option);
1488 _midi_devices = state->midi_devices;
1494 EngineControl::get_state ()
1496 LocaleGuard lg (X_("C"));
1498 XMLNode* root = new XMLNode ("AudioMIDISetup");
1501 if (!states.empty()) {
1502 XMLNode* state_nodes = new XMLNode ("EngineStates");
1504 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1506 XMLNode* node = new XMLNode ("State");
1508 node->add_property ("backend", (*i)->backend);
1509 node->add_property ("driver", (*i)->driver);
1510 node->add_property ("device", (*i)->device);
1511 node->add_property ("input-device", (*i)->input_device);
1512 node->add_property ("output-device", (*i)->output_device);
1513 node->add_property ("sample-rate", (*i)->sample_rate);
1514 node->add_property ("buffer-size", (*i)->buffer_size);
1515 node->add_property ("input-latency", (*i)->input_latency);
1516 node->add_property ("output-latency", (*i)->output_latency);
1517 node->add_property ("input-channels", (*i)->input_channels);
1518 node->add_property ("output-channels", (*i)->output_channels);
1519 node->add_property ("active", (*i)->active ? "yes" : "no");
1520 node->add_property ("midi-option", (*i)->midi_option);
1522 XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1523 for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1524 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1525 midi_device_stuff->add_property (X_("name"), (*p)->name);
1526 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1527 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1528 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1529 midi_devices->add_child_nocopy (*midi_device_stuff);
1531 node->add_child_nocopy (*midi_devices);
1533 state_nodes->add_child_nocopy (*node);
1536 root->add_child_nocopy (*state_nodes);
1543 EngineControl::set_state (const XMLNode& root)
1545 XMLNodeList clist, cclist;
1546 XMLNodeConstIterator citer, cciter;
1548 XMLNode* grandchild;
1549 XMLProperty* prop = NULL;
1551 fprintf (stderr, "EngineControl::set_state\n");
1553 if (root.name() != "AudioMIDISetup") {
1557 clist = root.children();
1561 for (citer = clist.begin(); citer != clist.end(); ++citer) {
1565 if (child->name() != "EngineStates") {
1569 cclist = child->children();
1571 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1572 State state (new StateStruct);
1574 grandchild = *cciter;
1576 if (grandchild->name() != "State") {
1580 if ((prop = grandchild->property ("backend")) == 0) {
1583 state->backend = prop->value ();
1585 if ((prop = grandchild->property ("driver")) == 0) {
1588 state->driver = prop->value ();
1590 if ((prop = grandchild->property ("device")) == 0) {
1593 state->device = prop->value ();
1595 if ((prop = grandchild->property ("input-device")) == 0) {
1598 state->input_device = prop->value ();
1600 if ((prop = grandchild->property ("output-device")) == 0) {
1603 state->output_device = prop->value ();
1605 if ((prop = grandchild->property ("sample-rate")) == 0) {
1608 state->sample_rate = atof (prop->value ());
1610 if ((prop = grandchild->property ("buffer-size")) == 0) {
1613 state->buffer_size = atoi (prop->value ());
1615 if ((prop = grandchild->property ("input-latency")) == 0) {
1618 state->input_latency = atoi (prop->value ());
1620 if ((prop = grandchild->property ("output-latency")) == 0) {
1623 state->output_latency = atoi (prop->value ());
1625 if ((prop = grandchild->property ("input-channels")) == 0) {
1628 state->input_channels = atoi (prop->value ());
1630 if ((prop = grandchild->property ("output-channels")) == 0) {
1633 state->output_channels = atoi (prop->value ());
1635 if ((prop = grandchild->property ("active")) == 0) {
1638 state->active = string_is_affirmative (prop->value ());
1640 if ((prop = grandchild->property ("midi-option")) == 0) {
1643 state->midi_option = prop->value ();
1645 state->midi_devices.clear();
1647 if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1648 const XMLNodeList mnc = midinode->children();
1649 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1650 if ((*n)->property (X_("name")) == 0
1651 || (*n)->property (X_("enabled")) == 0
1652 || (*n)->property (X_("input-latency")) == 0
1653 || (*n)->property (X_("output-latency")) == 0
1658 MidiDeviceSettings ptr (new MidiDeviceSetting(
1659 (*n)->property (X_("name"))->value (),
1660 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1661 atoi ((*n)->property (X_("input-latency"))->value ()),
1662 atoi ((*n)->property (X_("output-latency"))->value ())
1664 state->midi_devices.push_back (ptr);
1669 /* remove accumulated duplicates (due to bug in ealier version)
1670 * this can be removed again before release
1672 for (StateList::iterator i = states.begin(); i != states.end();) {
1673 if ((*i)->backend == state->backend &&
1674 (*i)->driver == state->driver &&
1675 (*i)->device == state->device) {
1676 i = states.erase(i);
1683 states.push_back (state);
1687 /* now see if there was an active state and switch the setup to it */
1689 // purge states of backend that are not available in this built
1690 vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1691 vector<std::string> backend_names;
1693 for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1694 backend_names.push_back((*i)->name);
1696 for (StateList::iterator i = states.begin(); i != states.end();) {
1697 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1698 i = states.erase(i);
1704 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1707 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1708 backend_combo.set_active_text ((*i)->backend);
1710 /* The driver popdown strings need to be populated now so that
1711 * set_active_text will actually set a valid entry. Then
1712 * backend_changed() will populate all the other combo's so they
1713 * can also be set to valid entries and the state will be restored
1716 if (!(*i)->driver.empty()) {
1717 set_driver_popdown_strings ();
1719 driver_combo.set_active_text ((*i)->driver);
1722 device_combo.set_active_text ((*i)->device);
1723 input_device_combo.set_active_text ((*i)->input_device);
1724 output_device_combo.set_active_text ((*i)->output_device);
1725 sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1726 set_active_text_if_present (buffer_size_combo, bufsize_as_string ((*i)->buffer_size));
1727 input_latency.set_value ((*i)->input_latency);
1728 output_latency.set_value ((*i)->output_latency);
1729 midi_option_combo.set_active_text ((*i)->midi_option);
1736 EngineControl::push_state_to_backend (bool start)
1738 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1744 /* figure out what is going to change */
1746 bool restart_required = false;
1747 bool was_running = ARDOUR::AudioEngine::instance()->running();
1748 bool change_driver = false;
1749 bool change_device = false;
1750 bool change_rate = false;
1751 bool change_bufsize = false;
1752 bool change_latency = false;
1753 bool change_channels = false;
1754 bool change_midi = false;
1756 uint32_t ochan = get_output_channels ();
1757 uint32_t ichan = get_input_channels ();
1759 if (_have_control) {
1761 if (started_at_least_once) {
1763 /* we can control the backend */
1765 if (backend->requires_driver_selection()) {
1766 if (get_driver() != backend->driver_name()) {
1767 change_driver = true;
1771 if (backend->use_separate_input_and_output_devices()) {
1772 if (get_input_device_name() != backend->input_device_name()) {
1773 change_device = true;
1775 if (get_output_device_name() != backend->output_device_name()) {
1776 change_device = true;
1779 if (get_device_name() != backend->device_name()) {
1780 change_device = true;
1784 if (queue_device_changed) {
1785 change_device = true;
1788 if (get_rate() != backend->sample_rate()) {
1792 if (get_buffer_size() != backend->buffer_size()) {
1793 change_bufsize = true;
1796 if (get_midi_option() != backend->midi_option()) {
1800 /* zero-requested channels means "all available" */
1803 ichan = backend->input_channels();
1807 ochan = backend->output_channels();
1810 if (ichan != backend->input_channels()) {
1811 change_channels = true;
1814 if (ochan != backend->output_channels()) {
1815 change_channels = true;
1818 if (get_input_latency() != backend->systemic_input_latency() ||
1819 get_output_latency() != backend->systemic_output_latency()) {
1820 change_latency = true;
1823 /* backend never started, so we have to force a group
1826 change_device = true;
1827 if (backend->requires_driver_selection()) {
1828 change_driver = true;
1831 change_bufsize = true;
1832 change_channels = true;
1833 change_latency = true;
1839 /* we have no control over the backend, meaning that we can
1840 * only possibly change sample rate and buffer size.
1844 if (get_rate() != backend->sample_rate()) {
1845 change_bufsize = true;
1848 if (get_buffer_size() != backend->buffer_size()) {
1849 change_bufsize = true;
1853 queue_device_changed = false;
1855 if (!_have_control) {
1857 /* We do not have control over the backend, so the best we can
1858 * do is try to change the sample rate and/or bufsize and get
1862 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1866 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1871 backend->set_sample_rate (get_rate());
1874 if (change_bufsize) {
1875 backend->set_buffer_size (get_buffer_size());
1879 if (ARDOUR::AudioEngine::instance()->start ()) {
1880 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1890 /* determine if we need to stop the backend before changing parameters */
1892 if (change_driver || change_device || change_channels || change_latency ||
1893 (change_rate && !backend->can_change_sample_rate_when_running()) ||
1895 (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1896 restart_required = true;
1898 restart_required = false;
1903 if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1904 /* no changes in any parameters that absolutely require a
1905 * restart, so check those that might be changeable without a
1909 if (change_rate && !backend->can_change_sample_rate_when_running()) {
1910 /* can't do this while running ... */
1911 restart_required = true;
1914 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1915 /* can't do this while running ... */
1916 restart_required = true;
1922 if (restart_required) {
1923 if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
1930 if (change_driver && backend->set_driver (get_driver())) {
1931 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1934 if (backend->use_separate_input_and_output_devices()) {
1935 if (change_device && backend->set_input_device_name (get_input_device_name())) {
1936 error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
1939 if (change_device && backend->set_output_device_name (get_output_device_name())) {
1940 error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
1944 if (change_device && backend->set_device_name (get_device_name())) {
1945 error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1949 if (change_rate && backend->set_sample_rate (get_rate())) {
1950 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1953 if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1954 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1958 if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1959 if (backend->set_input_channels (get_input_channels())) {
1960 error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1963 if (backend->set_output_channels (get_output_channels())) {
1964 error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1968 if (change_latency) {
1969 if (backend->set_systemic_input_latency (get_input_latency())) {
1970 error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1973 if (backend->set_systemic_output_latency (get_output_latency())) {
1974 error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1980 backend->set_midi_option (get_midi_option());
1984 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1985 if (_measure_midi) {
1986 if (*p == _measure_midi) {
1987 backend->set_midi_device_enabled ((*p)->name, true);
1989 backend->set_midi_device_enabled ((*p)->name, false);
1993 backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1994 if (backend->can_set_systemic_midi_latencies()) {
1995 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1996 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2001 if (start || (was_running && restart_required)) {
2002 if (ARDOUR_UI::instance()->reconnect_to_engine()) {
2013 EngineControl::post_push ()
2015 /* get a pointer to the current state object, creating one if
2019 State state = get_saved_state_for_currently_displayed_backend_and_device ();
2022 state = save_state ();
2030 for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2031 (*i)->active = false;
2034 /* mark this one active (to be used next time the dialog is
2038 state->active = true;
2040 if (_have_control) { // XXX
2041 manage_control_app_sensitivity ();
2044 /* schedule a redisplay of MIDI ports */
2045 //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2050 EngineControl::get_rate () const
2052 float r = atof (sample_rate_combo.get_active_text ());
2053 /* the string may have been translated with an abbreviation for
2054 * thousands, so use a crude heuristic to fix this.
2064 EngineControl::get_buffer_size () const
2066 string txt = buffer_size_combo.get_active_text ();
2069 if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2070 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2071 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2079 EngineControl::get_midi_option () const
2081 return midi_option_combo.get_active_text();
2085 EngineControl::get_input_channels() const
2087 if (ARDOUR::Profile->get_mixbus()) {
2088 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2089 if (!backend) return 0;
2090 return backend->input_channels();
2092 return (uint32_t) input_channels_adjustment.get_value();
2096 EngineControl::get_output_channels() const
2098 if (ARDOUR::Profile->get_mixbus()) {
2099 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2100 if (!backend) return 0;
2101 return backend->input_channels();
2103 return (uint32_t) output_channels_adjustment.get_value();
2107 EngineControl::get_input_latency() const
2109 return (uint32_t) input_latency_adjustment.get_value();
2113 EngineControl::get_output_latency() const
2115 return (uint32_t) output_latency_adjustment.get_value();
2119 EngineControl::get_backend () const
2121 return backend_combo.get_active_text ();
2125 EngineControl::get_driver () const
2127 if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
2128 return driver_combo.get_active_text ();
2135 EngineControl::get_device_name () const
2137 return device_combo.get_active_text ();
2141 EngineControl::get_input_device_name () const
2143 return input_device_combo.get_active_text ();
2147 EngineControl::get_output_device_name () const
2149 return output_device_combo.get_active_text ();
2153 EngineControl::control_app_button_clicked ()
2155 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2161 backend->launch_control_app ();
2165 EngineControl::manage_control_app_sensitivity ()
2167 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2173 string appname = backend->control_app_name();
2175 if (appname.empty()) {
2176 control_app_button.set_sensitive (false);
2178 control_app_button.set_sensitive (true);
2183 EngineControl::set_desired_sample_rate (uint32_t sr)
2185 _desired_sample_rate = sr;
2190 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2192 if (page_num == 0) {
2193 cancel_button->set_sensitive (true);
2194 ok_button->set_sensitive (true);
2195 apply_button->set_sensitive (true);
2196 _measure_midi.reset();
2198 cancel_button->set_sensitive (false);
2199 ok_button->set_sensitive (false);
2200 apply_button->set_sensitive (false);
2203 if (page_num == midi_tab) {
2205 refresh_midi_display ();
2208 if (page_num == latency_tab) {
2211 if (ARDOUR::AudioEngine::instance()->running()) {
2212 // TODO - mark as 'stopped for latency
2213 ARDOUR_UI::instance()->disconnect_from_engine ();
2217 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2219 /* save any existing latency values */
2221 uint32_t il = (uint32_t) input_latency.get_value ();
2222 uint32_t ol = (uint32_t) input_latency.get_value ();
2224 /* reset to zero so that our new test instance
2225 will be clean of any existing latency measures.
2227 NB. this should really be done by the backend
2228 when stated for latency measurement.
2231 input_latency.set_value (0);
2232 output_latency.set_value (0);
2234 push_state_to_backend (false);
2238 input_latency.set_value (il);
2239 output_latency.set_value (ol);
2242 // This should be done in push_state_to_backend()
2243 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2244 disable_latency_tab ();
2247 enable_latency_tab ();
2251 end_latency_detection ();
2252 ARDOUR::AudioEngine::instance()->stop_latency_detection();
2257 /* latency measurement */
2260 EngineControl::check_audio_latency_measurement ()
2262 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2264 if (mtdm->resolve () < 0) {
2265 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2269 if (mtdm->err () > 0.3) {
2275 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2277 if (sample_rate == 0) {
2278 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2279 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2283 int frames_total = mtdm->del();
2284 int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2286 snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2287 _("Detected roundtrip latency: "),
2288 frames_total, frames_total * 1000.0f/sample_rate,
2289 _("Systemic latency: "),
2290 extra, extra * 1000.0f/sample_rate);
2294 if (mtdm->err () > 0.2) {
2296 strcat (buf, _("(signal detection error)"));
2302 strcat (buf, _("(inverted - bad wiring)"));
2306 lm_results.set_markup (string_compose (results_markup, buf));
2309 have_lm_results = true;
2310 end_latency_detection ();
2311 lm_use_button.set_sensitive (true);
2319 EngineControl::check_midi_latency_measurement ()
2321 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2323 if (!mididm->have_signal () || mididm->latency () == 0) {
2324 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2329 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2331 if (sample_rate == 0) {
2332 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2333 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2337 ARDOUR::framecnt_t frames_total = mididm->latency();
2338 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2339 snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2340 _("Detected roundtrip latency: "),
2341 frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2342 _("Systemic latency: "),
2343 extra, extra * 1000.0f / sample_rate);
2347 if (!mididm->ok ()) {
2349 strcat (buf, _("(averaging)"));
2353 if (mididm->deviation () > 50.0) {
2355 strcat (buf, _("(too large jitter)"));
2357 } else if (mididm->deviation () > 10.0) {
2359 strcat (buf, _("(large jitter)"));
2363 have_lm_results = true;
2364 end_latency_detection ();
2365 lm_use_button.set_sensitive (true);
2366 lm_results.set_markup (string_compose (results_markup, buf));
2368 } else if (mididm->processed () > 400) {
2369 have_lm_results = false;
2370 end_latency_detection ();
2371 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2375 lm_results.set_markup (string_compose (results_markup, buf));
2381 EngineControl::start_latency_detection ()
2383 ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
2384 ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
2386 if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
2387 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2388 if (_measure_midi) {
2389 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2391 latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2393 lm_measure_label.set_text (_("Cancel"));
2394 have_lm_results = false;
2395 lm_use_button.set_sensitive (false);
2396 lm_input_channel_combo.set_sensitive (false);
2397 lm_output_channel_combo.set_sensitive (false);
2403 EngineControl::end_latency_detection ()
2405 latency_timeout.disconnect ();
2406 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2407 lm_measure_label.set_text (_("Measure"));
2408 if (!have_lm_results) {
2409 lm_use_button.set_sensitive (false);
2411 lm_input_channel_combo.set_sensitive (true);
2412 lm_output_channel_combo.set_sensitive (true);
2417 EngineControl::latency_button_clicked ()
2420 start_latency_detection ();
2422 end_latency_detection ();
2427 EngineControl::use_latency_button_clicked ()
2429 if (_measure_midi) {
2430 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2434 ARDOUR::framecnt_t frames_total = mididm->latency();
2435 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2436 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2437 _measure_midi->input_latency = one_way;
2438 _measure_midi->output_latency = one_way;
2439 notebook.set_current_page (midi_tab);
2441 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2447 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2448 one_way = std::max (0., one_way);
2450 input_latency_adjustment.set_value (one_way);
2451 output_latency_adjustment.set_value (one_way);
2453 /* back to settings page */
2454 notebook.set_current_page (0);
2460 EngineControl::on_delete_event (GdkEventAny* ev)
2462 if (notebook.get_current_page() == 2) {
2463 /* currently on latency tab - be sure to clean up */
2464 end_latency_detection ();
2466 return ArdourDialog::on_delete_event (ev);
2470 EngineControl::engine_running ()
2472 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2475 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
2476 sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2478 buffer_size_combo.set_sensitive (true);
2479 sample_rate_combo.set_sensitive (true);
2481 connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2482 connect_disconnect_button.show();
2484 started_at_least_once = true;
2485 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2489 EngineControl::engine_stopped ()
2491 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2494 buffer_size_combo.set_sensitive (false);
2495 connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2496 connect_disconnect_button.show();
2498 sample_rate_combo.set_sensitive (true);
2499 buffer_size_combo.set_sensitive (true);
2500 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2504 EngineControl::device_list_changed ()
2506 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2508 midi_option_changed();
2512 EngineControl::connect_disconnect_click()
2514 if (ARDOUR::AudioEngine::instance()->running()) {
2515 ARDOUR_UI::instance()->disconnect_from_engine ();
2517 ARDOUR_UI::instance()->reconnect_to_engine ();
2522 EngineControl::calibrate_audio_latency ()
2524 _measure_midi.reset ();
2525 have_lm_results = false;
2526 lm_use_button.set_sensitive (false);
2527 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2528 notebook.set_current_page (latency_tab);
2532 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
2535 have_lm_results = false;
2536 lm_use_button.set_sensitive (false);
2537 lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2538 notebook.set_current_page (latency_tab);
2542 EngineControl::configure_midi_devices ()
2544 notebook.set_current_page (midi_tab);